aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml
diff options
context:
space:
mode:
Diffstat (limited to 'src/qml')
-rw-r--r--src/qml/animations/animations.pri16
-rw-r--r--src/qml/animations/qabstractanimationjob.cpp544
-rw-r--r--src/qml/animations/qabstractanimationjob_p.h233
-rw-r--r--src/qml/animations/qanimationgroupjob.cpp164
-rw-r--r--src/qml/animations/qanimationgroupjob_p.h93
-rw-r--r--src/qml/animations/qanimationjobutil_p.h59
-rw-r--r--src/qml/animations/qparallelanimationgroupjob.cpp227
-rw-r--r--src/qml/animations/qparallelanimationgroupjob_p.h81
-rw-r--r--src/qml/animations/qpauseanimationjob.cpp71
-rw-r--r--src/qml/animations/qpauseanimationjob_p.h75
-rw-r--r--src/qml/animations/qsequentialanimationgroupjob.cpp388
-rw-r--r--src/qml/animations/qsequentialanimationgroupjob_p.h108
-rw-r--r--src/qml/debugger/debugger.pri32
-rw-r--r--src/qml/debugger/qdebugmessageservice.cpp124
-rw-r--r--src/qml/debugger/qdebugmessageservice_p.h91
-rw-r--r--src/qml/debugger/qpacketprotocol.cpp550
-rw-r--r--src/qml/debugger/qpacketprotocol_p.h137
-rw-r--r--src/qml/debugger/qqmldebug.h66
-rw-r--r--src/qml/debugger/qqmldebugclient.cpp421
-rw-r--r--src/qml/debugger/qqmldebugclient_p.h131
-rw-r--r--src/qml/debugger/qqmldebughelper.cpp70
-rw-r--r--src/qml/debugger/qqmldebughelper_p.h84
-rw-r--r--src/qml/debugger/qqmldebugserver.cpp540
-rw-r--r--src/qml/debugger/qqmldebugserver_p.h105
-rw-r--r--src/qml/debugger/qqmldebugserverconnection_p.h85
-rw-r--r--src/qml/debugger/qqmldebugservice.cpp268
-rw-r--r--src/qml/debugger/qqmldebugservice_p.h113
-rw-r--r--src/qml/debugger/qqmldebugservice_p_p.h82
-rw-r--r--src/qml/debugger/qqmldebugstatesdelegate_p.h98
-rw-r--r--src/qml/debugger/qqmlenginedebug.cpp1072
-rw-r--r--src/qml/debugger/qqmlenginedebug_p.h397
-rw-r--r--src/qml/debugger/qqmlenginedebugservice.cpp733
-rw-r--r--src/qml/debugger/qqmlenginedebugservice_p.h136
-rw-r--r--src/qml/debugger/qqmlinspectorinterface_p.h83
-rw-r--r--src/qml/debugger/qqmlinspectorservice.cpp186
-rw-r--r--src/qml/debugger/qqmlinspectorservice_p.h101
-rw-r--r--src/qml/debugger/qqmlprofilerservice.cpp357
-rw-r--r--src/qml/debugger/qqmlprofilerservice_p.h183
-rw-r--r--src/qml/debugger/qv8debugservice.cpp294
-rw-r--r--src/qml/debugger/qv8debugservice_p.h105
-rw-r--r--src/qml/debugger/qv8profilerservice.cpp287
-rw-r--r--src/qml/debugger/qv8profilerservice_p.h119
-rw-r--r--src/qml/qml.pro37
-rw-r--r--src/qml/qml/ftw/ftw.pri29
-rw-r--r--src/qml/qml/ftw/qbitfield_p.h165
-rw-r--r--src/qml/qml/ftw/qdeletewatcher_p.h113
-rw-r--r--src/qml/qml/ftw/qfastmetabuilder.cpp369
-rw-r--r--src/qml/qml/ftw/qfastmetabuilder_p.h206
-rw-r--r--src/qml/qml/ftw/qfieldlist_p.h426
-rw-r--r--src/qml/qml/ftw/qfinitestack_p.h186
-rw-r--r--src/qml/qml/ftw/qflagpointer_p.h338
-rw-r--r--src/qml/qml/ftw/qhashedstring.cpp490
-rw-r--r--src/qml/qml/ftw/qhashedstring_p.h1418
-rw-r--r--src/qml/qml/ftw/qhashfield_p.h120
-rw-r--r--src/qml/qml/ftw/qintrusivelist.cpp179
-rw-r--r--src/qml/qml/ftw/qintrusivelist_p.h274
-rw-r--r--src/qml/qml/ftw/qlazilyallocated_p.h146
-rw-r--r--src/qml/qml/ftw/qpodvector_p.h173
-rw-r--r--src/qml/qml/ftw/qpointervaluepair_p.h196
-rw-r--r--src/qml/qml/ftw/qqmlpool.cpp92
-rw-r--r--src/qml/qml/ftw/qqmlpool_p.h278
-rw-r--r--src/qml/qml/ftw/qqmlrefcount_p.h192
-rw-r--r--src/qml/qml/ftw/qqmlthread.cpp359
-rw-r--r--src/qml/qml/ftw/qqmlthread_p.h318
-rw-r--r--src/qml/qml/ftw/qqmltrace.cpp154
-rw-r--r--src/qml/qml/ftw/qqmltrace_p.h294
-rw-r--r--src/qml/qml/ftw/qrecursionwatcher_p.h105
-rw-r--r--src/qml/qml/ftw/qrecyclepool_p.h220
-rw-r--r--src/qml/qml/parser/parser.pri19
-rw-r--r--src/qml/qml/parser/qqmljs.g3016
-rw-r--r--src/qml/qml/parser/qqmljsast.cpp931
-rw-r--r--src/qml/qml/parser/qqmljsast_p.h2640
-rw-r--r--src/qml/qml/parser/qqmljsastfwd_p.h186
-rw-r--r--src/qml/qml/parser/qqmljsastvisitor.cpp58
-rw-r--r--src/qml/qml/parser/qqmljsastvisitor_p.h329
-rw-r--r--src/qml/qml/parser/qqmljsengine_p.cpp161
-rw-r--r--src/qml/qml/parser/qqmljsengine_p.h126
-rw-r--r--src/qml/qml/parser/qqmljsglobal_p.h69
-rw-r--r--src/qml/qml/parser/qqmljsgrammar.cpp1013
-rw-r--r--src/qml/qml/parser/qqmljsgrammar_p.h211
-rw-r--r--src/qml/qml/parser/qqmljskeywords_p.h860
-rw-r--r--src/qml/qml/parser/qqmljslexer.cpp1166
-rw-r--r--src/qml/qml/parser/qqmljslexer_p.h248
-rw-r--r--src/qml/qml/parser/qqmljsmemorypool_p.h173
-rw-r--r--src/qml/qml/parser/qqmljsparser.cpp1812
-rw-r--r--src/qml/qml/parser/qqmljsparser_p.h248
-rw-r--r--src/qml/qml/qlistmodelinterface.cpp104
-rw-r--r--src/qml/qml/qlistmodelinterface_p.h83
-rw-r--r--src/qml/qml/qml.pri125
-rw-r--r--src/qml/qml/qqml.h451
-rw-r--r--src/qml/qml/qqmlaccessors.cpp127
-rw-r--r--src/qml/qml/qqmlaccessors_p.h166
-rw-r--r--src/qml/qml/qqmlbinding.cpp551
-rw-r--r--src/qml/qml/qqmlbinding_p.h219
-rw-r--r--src/qml/qml/qqmlbinding_p_p.h89
-rw-r--r--src/qml/qml/qqmlboundsignal.cpp300
-rw-r--r--src/qml/qml/qqmlboundsignal_p.h103
-rw-r--r--src/qml/qml/qqmlcleanup.cpp118
-rw-r--r--src/qml/qml/qqmlcleanup_p.h87
-rw-r--r--src/qml/qml/qqmlcompileddata.cpp261
-rw-r--r--src/qml/qml/qqmlcompiler.cpp3882
-rw-r--r--src/qml/qml/qqmlcompiler_p.h466
-rw-r--r--src/qml/qml/qqmlcomponent.cpp1350
-rw-r--r--src/qml/qml/qqmlcomponent.h138
-rw-r--r--src/qml/qml/qqmlcomponent_p.h129
-rw-r--r--src/qml/qml/qqmlcomponentattached_p.h85
-rw-r--r--src/qml/qml/qqmlcontext.cpp811
-rw-r--r--src/qml/qml/qqmlcontext.h113
-rw-r--r--src/qml/qml/qqmlcontext_p.h334
-rw-r--r--src/qml/qml/qqmlcustomparser.cpp319
-rw-r--r--src/qml/qml/qqmlcustomparser_p.h168
-rw-r--r--src/qml/qml/qqmlcustomparser_p_p.h89
-rw-r--r--src/qml/qml/qqmldata_p.h207
-rw-r--r--src/qml/qml/qqmldirparser.cpp298
-rw-r--r--src/qml/qml/qqmldirparser_p.h166
-rw-r--r--src/qml/qml/qqmlengine.cpp1854
-rw-r--r--src/qml/qml/qqmlengine.h138
-rw-r--r--src/qml/qml/qqmlengine_p.h522
-rw-r--r--src/qml/qml/qqmlerror.cpp285
-rw-r--r--src/qml/qml/qqmlerror.h87
-rw-r--r--src/qml/qml/qqmlexpression.cpp982
-rw-r--r--src/qml/qml/qqmlexpression.h121
-rw-r--r--src/qml/qml/qqmlexpression_p.h406
-rw-r--r--src/qml/qml/qqmlextensioninterface.h76
-rw-r--r--src/qml/qml/qqmlextensionplugin.cpp171
-rw-r--r--src/qml/qml/qqmlextensionplugin.h77
-rw-r--r--src/qml/qml/qqmlglobal_p.h129
-rw-r--r--src/qml/qml/qqmlguard_p.h218
-rw-r--r--src/qml/qml/qqmlimageprovider.cpp334
-rw-r--r--src/qml/qml/qqmlimageprovider.h96
-rw-r--r--src/qml/qml/qqmlimport.cpp1183
-rw-r--r--src/qml/qml/qqmlimport_p.h157
-rw-r--r--src/qml/qml/qqmlincubator.cpp696
-rw-r--r--src/qml/qml/qqmlincubator.h129
-rw-r--r--src/qml/qml/qqmlincubator_p.h106
-rw-r--r--src/qml/qml/qqmlinfo.cpp192
-rw-r--r--src/qml/qml/qqmlinfo.h103
-rw-r--r--src/qml/qml/qqmlinstruction.cpp278
-rw-r--r--src/qml/qml/qqmlinstruction_p.h558
-rw-r--r--src/qml/qml/qqmlintegercache.cpp82
-rw-r--r--src/qml/qml/qqmlintegercache_p.h97
-rw-r--r--src/qml/qml/qqmllist.cpp417
-rw-r--r--src/qml/qml/qqmllist.h151
-rw-r--r--src/qml/qml/qqmllist_p.h85
-rw-r--r--src/qml/qml/qqmllocale.cpp1123
-rw-r--r--src/qml/qml/qqmllocale_p.h135
-rw-r--r--src/qml/qml/qqmlmetatype.cpp1359
-rw-r--r--src/qml/qml/qqmlmetatype_p.h268
-rw-r--r--src/qml/qml/qqmlnetworkaccessmanagerfactory.cpp103
-rw-r--r--src/qml/qml/qqmlnetworkaccessmanagerfactory.h66
-rw-r--r--src/qml/qml/qqmlnotifier.cpp115
-rw-r--r--src/qml/qml/qqmlnotifier_p.h206
-rw-r--r--src/qml/qml/qqmlnullablevalue_p_p.h81
-rw-r--r--src/qml/qml/qqmlopenmetaobject.cpp387
-rw-r--r--src/qml/qml/qqmlopenmetaobject_p.h130
-rw-r--r--src/qml/qml/qqmlparserstatus.cpp107
-rw-r--r--src/qml/qml/qqmlparserstatus.h75
-rw-r--r--src/qml/qml/qqmlprivate.h265
-rw-r--r--src/qml/qml/qqmlproperty.cpp1917
-rw-r--r--src/qml/qml/qqmlproperty.h143
-rw-r--r--src/qml/qml/qqmlproperty_p.h171
-rw-r--r--src/qml/qml/qqmlpropertycache.cpp889
-rw-r--r--src/qml/qml/qqmlpropertycache_p.h383
-rw-r--r--src/qml/qml/qqmlpropertyvalueinterceptor.cpp79
-rw-r--r--src/qml/qml/qqmlpropertyvalueinterceptor_p.h74
-rw-r--r--src/qml/qml/qqmlpropertyvaluesource.cpp76
-rw-r--r--src/qml/qml/qqmlpropertyvaluesource.h67
-rw-r--r--src/qml/qml/qqmlproxymetaobject.cpp124
-rw-r--r--src/qml/qml/qqmlproxymetaobject_p.h99
-rw-r--r--src/qml/qml/qqmlrewrite.cpp441
-rw-r--r--src/qml/qml/qqmlrewrite_p.h149
-rw-r--r--src/qml/qml/qqmlscript.cpp1700
-rw-r--r--src/qml/qml/qqmlscript_p.h533
-rw-r--r--src/qml/qml/qqmlscriptstring.cpp157
-rw-r--r--src/qml/qml/qqmlscriptstring.h90
-rw-r--r--src/qml/qml/qqmlscriptstring_p.h64
-rw-r--r--src/qml/qml/qqmlstringconverters.cpp311
-rw-r--r--src/qml/qml/qqmlstringconverters_p.h93
-rw-r--r--src/qml/qml/qqmltypeloader.cpp1928
-rw-r--r--src/qml/qml/qqmltypeloader_p.h435
-rw-r--r--src/qml/qml/qqmltypenamecache.cpp127
-rw-r--r--src/qml/qml/qqmltypenamecache_p.h187
-rw-r--r--src/qml/qml/qqmltypenotavailable.cpp53
-rw-r--r--src/qml/qml/qqmltypenotavailable_p.h64
-rw-r--r--src/qml/qml/qqmlvaluetype.cpp868
-rw-r--r--src/qml/qml/qqmlvaluetype_p.h635
-rw-r--r--src/qml/qml/qqmlvme.cpp1370
-rw-r--r--src/qml/qml/qqmlvme_p.h240
-rw-r--r--src/qml/qml/qqmlvmemetaobject.cpp1110
-rw-r--r--src/qml/qml/qqmlvmemetaobject_p.h221
-rw-r--r--src/qml/qml/qqmlwatcher.cpp188
-rw-r--r--src/qml/qml/qqmlwatcher_p.h94
-rw-r--r--src/qml/qml/qqmlxmlhttprequest.cpp1797
-rw-r--r--src/qml/qml/qqmlxmlhttprequest_p.h73
-rw-r--r--src/qml/qml/qquickapplication.cpp124
-rw-r--r--src/qml/qml/qquickapplication_p.h87
-rw-r--r--src/qml/qml/qquicklistmodel.cpp2467
-rw-r--r--src/qml/qml/qquicklistmodel_p.h199
-rw-r--r--src/qml/qml/qquicklistmodel_p_p.h378
-rw-r--r--src/qml/qml/qquicklistmodelworkeragent.cpp246
-rw-r--r--src/qml/qml/qquicklistmodelworkeragent_p.h161
-rw-r--r--src/qml/qml/qquickworkerscript.cpp730
-rw-r--r--src/qml/qml/qquickworkerscript_p.h130
-rw-r--r--src/qml/qml/rewriter/rewriter.pri2
-rw-r--r--src/qml/qml/rewriter/textwriter.cpp217
-rw-r--r--src/qml/qml/rewriter/textwriter_p.h101
-rw-r--r--src/qml/qml/v4/qv4bindings.cpp1538
-rw-r--r--src/qml/qml/v4/qv4bindings_p.h153
-rw-r--r--src/qml/qml/v4/qv4compiler.cpp1399
-rw-r--r--src/qml/qml/v4/qv4compiler_p.h105
-rw-r--r--src/qml/qml/v4/qv4compiler_p_p.h245
-rw-r--r--src/qml/qml/v4/qv4instruction.cpp412
-rw-r--r--src/qml/qml/v4/qv4instruction_p.h432
-rw-r--r--src/qml/qml/v4/qv4ir.cpp882
-rw-r--r--src/qml/qml/v4/qv4ir_p.h604
-rw-r--r--src/qml/qml/v4/qv4irbuilder.cpp1303
-rw-r--r--src/qml/qml/v4/qv4irbuilder_p.h240
-rw-r--r--src/qml/qml/v4/qv4program_p.h122
-rw-r--r--src/qml/qml/v4/v4.pri15
-rw-r--r--src/qml/qml/v8/notes.txt4
-rw-r--r--src/qml/qml/v8/qjsconverter_impl_p.h268
-rw-r--r--src/qml/qml/v8/qjsconverter_p.h93
-rw-r--r--src/qml/qml/v8/qjsengine.cpp476
-rw-r--r--src/qml/qml/v8/qjsengine.h141
-rw-r--r--src/qml/qml/v8/qjsengine_p.h57
-rw-r--r--src/qml/qml/v8/qjsvalue.cpp856
-rw-r--r--src/qml/qml/v8/qjsvalue.h143
-rw-r--r--src/qml/qml/v8/qjsvalue_impl_p.h977
-rw-r--r--src/qml/qml/v8/qjsvalue_p.h195
-rw-r--r--src/qml/qml/v8/qjsvalueiterator.cpp157
-rw-r--r--src/qml/qml/v8/qjsvalueiterator.h63
-rw-r--r--src/qml/qml/v8/qjsvalueiterator_impl_p.h121
-rw-r--r--src/qml/qml/v8/qjsvalueiterator_p.h68
-rw-r--r--src/qml/qml/v8/qqmlbuiltinfunctions.cpp1320
-rw-r--r--src/qml/qml/v8/qqmlbuiltinfunctions_p.h110
-rw-r--r--src/qml/qml/v8/qscript_impl_p.h43
-rw-r--r--src/qml/qml/v8/qscriptisolate_p.h71
-rw-r--r--src/qml/qml/v8/qscriptoriginalglobalobject_p.h159
-rw-r--r--src/qml/qml/v8/qscriptshareddata_p.h151
-rw-r--r--src/qml/qml/v8/qscripttools_p.h68
-rw-r--r--src/qml/qml/v8/qv8_p.h42
-rw-r--r--src/qml/qml/v8/qv8bindings.cpp285
-rw-r--r--src/qml/qml/v8/qv8bindings_p.h148
-rw-r--r--src/qml/qml/v8/qv8contextwrapper.cpp455
-rw-r--r--src/qml/qml/v8/qv8contextwrapper_p.h120
-rw-r--r--src/qml/qml/v8/qv8debug_p.h42
-rw-r--r--src/qml/qml/v8/qv8domerrors.cpp73
-rw-r--r--src/qml/qml/v8/qv8domerrors_p.h94
-rw-r--r--src/qml/qml/v8/qv8engine.cpp1598
-rw-r--r--src/qml/qml/v8/qv8engine_impl_p.h155
-rw-r--r--src/qml/qml/v8/qv8engine_p.h631
-rw-r--r--src/qml/qml/v8/qv8include.cpp244
-rw-r--r--src/qml/qml/v8/qv8include_p.h113
-rw-r--r--src/qml/qml/v8/qv8listwrapper.cpp194
-rw-r--r--src/qml/qml/v8/qv8listwrapper_p.h97
-rw-r--r--src/qml/qml/v8/qv8profiler_p.h42
-rw-r--r--src/qml/qml/v8/qv8qobjectwrapper.cpp2113
-rw-r--r--src/qml/qml/v8/qv8qobjectwrapper_p.h159
-rw-r--r--src/qml/qml/v8/qv8sequencewrapper.cpp264
-rw-r--r--src/qml/qml/v8/qv8sequencewrapper_p.h106
-rw-r--r--src/qml/qml/v8/qv8sequencewrapper_p_p.h503
-rw-r--r--src/qml/qml/v8/qv8sqlerrors.cpp64
-rw-r--r--src/qml/qml/v8/qv8sqlerrors_p.h77
-rw-r--r--src/qml/qml/v8/qv8stringwrapper.cpp78
-rw-r--r--src/qml/qml/v8/qv8stringwrapper_p.h78
-rw-r--r--src/qml/qml/v8/qv8typewrapper.cpp314
-rw-r--r--src/qml/qml/v8/qv8typewrapper_p.h94
-rw-r--r--src/qml/qml/v8/qv8valuetypewrapper.cpp387
-rw-r--r--src/qml/qml/v8/qv8valuetypewrapper_p.h104
-rw-r--r--src/qml/qml/v8/qv8variantresource_p.h81
-rw-r--r--src/qml/qml/v8/qv8variantwrapper.cpp279
-rw-r--r--src/qml/qml/v8/qv8variantwrapper_p.h110
-rw-r--r--src/qml/qml/v8/qv8worker.cpp392
-rw-r--r--src/qml/qml/v8/qv8worker_p.h75
-rw-r--r--src/qml/qml/v8/script.pri21
-rw-r--r--src/qml/qml/v8/v8.pri45
-rw-r--r--src/qml/qtqmlglobal.h67
-rw-r--r--src/qml/qtqmlglobal_p.h60
-rw-r--r--src/qml/util/qqmlpropertymap.cpp309
-rw-r--r--src/qml/util/qqmlpropertymap.h91
-rw-r--r--src/qml/util/util.pri5
281 files changed, 99733 insertions, 0 deletions
diff --git a/src/qml/animations/animations.pri b/src/qml/animations/animations.pri
new file mode 100644
index 0000000000..01ac25af46
--- /dev/null
+++ b/src/qml/animations/animations.pri
@@ -0,0 +1,16 @@
+INCLUDEPATH += $$PWD
+
+HEADERS += \
+ $$PWD/qabstractanimationjob_p.h \
+ $$PWD/qanimationgroupjob_p.h \
+ $$PWD/qsequentialanimationgroupjob_p.h \
+ $$PWD/qparallelanimationgroupjob_p.h \
+ $$PWD/qpauseanimationjob_p.h \
+ $$PWD/qanimationjobutil_p.h
+
+SOURCES += \
+ $$PWD/qabstractanimationjob.cpp \
+ $$PWD/qanimationgroupjob.cpp \
+ $$PWD/qsequentialanimationgroupjob.cpp \
+ $$PWD/qparallelanimationgroupjob.cpp \
+ $$PWD/qpauseanimationjob.cpp
diff --git a/src/qml/animations/qabstractanimationjob.cpp b/src/qml/animations/qabstractanimationjob.cpp
new file mode 100644
index 0000000000..2bfc66fea0
--- /dev/null
+++ b/src/qml/animations/qabstractanimationjob.cpp
@@ -0,0 +1,544 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtCore/qthreadstorage.h>
+
+#include "private/qabstractanimationjob_p.h"
+#include "private/qanimationgroupjob_p.h"
+#include "private/qanimationjobutil_p.h"
+
+#define DEFAULT_TIMER_INTERVAL 16
+
+QT_BEGIN_NAMESPACE
+
+#ifndef QT_NO_THREAD
+Q_GLOBAL_STATIC(QThreadStorage<QQmlAnimationTimer *>, animationTimer)
+#endif
+
+QQmlAnimationTimer::QQmlAnimationTimer() :
+ QAbstractAnimationTimer(), lastTick(0), lastDelta(0),
+ currentAnimationIdx(0), insideTick(false),
+ startAnimationPending(false), stopTimerPending(false),
+ runningLeafAnimations(0)
+{
+}
+
+QQmlAnimationTimer *QQmlAnimationTimer::instance(bool create)
+{
+ QQmlAnimationTimer *inst;
+#ifndef QT_NO_THREAD
+ if (create && !animationTimer()->hasLocalData()) {
+ inst = new QQmlAnimationTimer;
+ animationTimer()->setLocalData(inst);
+ } else {
+ inst = animationTimer() ? animationTimer()->localData() : 0;
+ }
+#else
+ static QAnimationTimer unifiedTimer;
+ inst = &unifiedTimer;
+#endif
+ return inst;
+}
+
+QQmlAnimationTimer *QQmlAnimationTimer::instance()
+{
+ return instance(true);
+}
+
+void QQmlAnimationTimer::ensureTimerUpdate()
+{
+ QQmlAnimationTimer *inst = QQmlAnimationTimer::instance(false);
+ QUnifiedTimer *instU = QUnifiedTimer::instance(false);
+ if (instU && inst && inst->isPaused)
+ instU->updateAnimationTimers(-1);
+}
+
+void QQmlAnimationTimer::updateAnimationsTime(qint64 delta)
+{
+ //setCurrentTime can get this called again while we're the for loop. At least with pauseAnimations
+ if (insideTick)
+ return;
+
+ lastTick += delta;
+ lastDelta = delta;
+
+ //we make sure we only call update time if the time has actually changed
+ //it might happen in some cases that the time doesn't change because events are delayed
+ //when the CPU load is high
+ if (delta) {
+ insideTick = true;
+ for (currentAnimationIdx = 0; currentAnimationIdx < animations.count(); ++currentAnimationIdx) {
+ QAbstractAnimationJob *animation = animations.at(currentAnimationIdx);
+ int elapsed = animation->m_totalCurrentTime
+ + (animation->direction() == QAbstractAnimationJob::Forward ? delta : -delta);
+ animation->setCurrentTime(elapsed);
+ }
+ insideTick = false;
+ currentAnimationIdx = 0;
+ }
+}
+
+void QQmlAnimationTimer::updateAnimationTimer()
+{
+ QQmlAnimationTimer *inst = QQmlAnimationTimer::instance(false);
+ if (inst)
+ inst->restartAnimationTimer();
+}
+
+void QQmlAnimationTimer::restartAnimationTimer()
+{
+ if (runningLeafAnimations == 0 && !runningPauseAnimations.isEmpty())
+ QUnifiedTimer::pauseAnimationTimer(this, closestPauseAnimationTimeToFinish());
+ else if (isPaused)
+ QUnifiedTimer::resumeAnimationTimer(this);
+ else if (!isRegistered)
+ QUnifiedTimer::startAnimationTimer(this);
+}
+
+void QQmlAnimationTimer::startAnimations()
+{
+ startAnimationPending = false;
+ //force timer to update, which prevents large deltas for our newly added animations
+ if (!animations.isEmpty())
+ QUnifiedTimer::instance()->maybeUpdateAnimationsToCurrentTime();
+
+ //we transfer the waiting animations into the "really running" state
+ animations += animationsToStart;
+ animationsToStart.clear();
+ if (!animations.isEmpty())
+ restartAnimationTimer();
+}
+
+void QQmlAnimationTimer::stopTimer()
+{
+ stopTimerPending = false;
+ if (animations.isEmpty()) {
+ QUnifiedTimer::resumeAnimationTimer(this);
+ QUnifiedTimer::stopAnimationTimer(this);
+ // invalidate the start reference time
+ lastTick = 0;
+ lastDelta = 0;
+ }
+}
+
+void QQmlAnimationTimer::registerAnimation(QAbstractAnimationJob *animation, bool isTopLevel)
+{
+ QQmlAnimationTimer *inst = instance(true); //we create the instance if needed
+ inst->registerRunningAnimation(animation);
+ if (isTopLevel) {
+ Q_ASSERT(!animation->m_hasRegisteredTimer);
+ animation->m_hasRegisteredTimer = true;
+ inst->animationsToStart << animation;
+ if (!inst->startAnimationPending) {
+ inst->startAnimationPending = true;
+ QMetaObject::invokeMethod(inst, "startAnimations", Qt::QueuedConnection);
+ }
+ }
+}
+
+void QQmlAnimationTimer::unregisterAnimation(QAbstractAnimationJob *animation)
+{
+ QQmlAnimationTimer *inst = QQmlAnimationTimer::instance(false);
+ if (inst) {
+ //at this point the unified timer should have been created
+ //but it might also have been already destroyed in case the application is shutting down
+
+ inst->unregisterRunningAnimation(animation);
+
+ if (!animation->m_hasRegisteredTimer)
+ return;
+
+ int idx = inst->animations.indexOf(animation);
+ if (idx != -1) {
+ inst->animations.removeAt(idx);
+ // this is needed if we unregister an animation while its running
+ if (idx <= inst->currentAnimationIdx)
+ --inst->currentAnimationIdx;
+
+ if (inst->animations.isEmpty() && !inst->stopTimerPending) {
+ inst->stopTimerPending = true;
+ QMetaObject::invokeMethod(inst, "stopTimer", Qt::QueuedConnection);
+ }
+ } else {
+ inst->animationsToStart.removeOne(animation);
+ }
+ }
+ animation->m_hasRegisteredTimer = false;
+}
+
+void QQmlAnimationTimer::registerRunningAnimation(QAbstractAnimationJob *animation)
+{
+ if (animation->m_isGroup)
+ return;
+
+ if (animation->m_isPause) {
+ runningPauseAnimations << animation;
+ } else
+ runningLeafAnimations++;
+}
+
+void QQmlAnimationTimer::unregisterRunningAnimation(QAbstractAnimationJob *animation)
+{
+ if (animation->m_isGroup)
+ return;
+
+ if (animation->m_isPause)
+ runningPauseAnimations.removeOne(animation);
+ else
+ runningLeafAnimations--;
+ Q_ASSERT(runningLeafAnimations >= 0);
+}
+
+int QQmlAnimationTimer::closestPauseAnimationTimeToFinish()
+{
+ int closestTimeToFinish = INT_MAX;
+ for (int i = 0; i < runningPauseAnimations.size(); ++i) {
+ QAbstractAnimationJob *animation = runningPauseAnimations.at(i);
+ int timeToFinish;
+
+ if (animation->direction() == QAbstractAnimationJob::Forward)
+ timeToFinish = animation->duration() - animation->currentLoopTime();
+ else
+ timeToFinish = animation->currentLoopTime();
+
+ if (timeToFinish < closestTimeToFinish)
+ closestTimeToFinish = timeToFinish;
+ }
+ return closestTimeToFinish;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+QAbstractAnimationJob::QAbstractAnimationJob()
+ : m_isPause(false)
+ , m_isGroup(false)
+ , m_loopCount(1)
+ , m_group(0)
+ , m_direction(QAbstractAnimationJob::Forward)
+ , m_state(QAbstractAnimationJob::Stopped)
+ , m_totalCurrentTime(0)
+ , m_currentTime(0)
+ , m_currentLoop(0)
+ , m_hasRegisteredTimer(false)
+ , m_uncontrolledFinishTime(-1)
+ , m_wasDeleted(0)
+ , m_nextSibling(0)
+ , m_previousSibling(0)
+{
+}
+
+QAbstractAnimationJob::~QAbstractAnimationJob()
+{
+ if (m_wasDeleted)
+ *m_wasDeleted = true;
+
+ //we can't call stop here. Otherwise we get pure virtual calls
+ if (m_state != Stopped) {
+ State oldState = m_state;
+ m_state = Stopped;
+ stateChanged(oldState, m_state);
+ if (oldState == Running)
+ QQmlAnimationTimer::unregisterAnimation(this);
+ }
+
+ if (m_group)
+ m_group->removeAnimation(this);
+}
+
+void QAbstractAnimationJob::setState(QAbstractAnimationJob::State newState)
+{
+ if (m_state == newState)
+ return;
+
+ if (m_loopCount == 0)
+ return;
+
+ State oldState = m_state;
+ int oldCurrentTime = m_currentTime;
+ int oldCurrentLoop = m_currentLoop;
+ Direction oldDirection = m_direction;
+
+ // check if we should Rewind
+ if ((newState == Paused || newState == Running) && oldState == Stopped) {
+ //here we reset the time if needed
+ //we don't call setCurrentTime because this might change the way the animation
+ //behaves: changing the state or changing the current value
+ m_totalCurrentTime = m_currentTime = (m_direction == Forward) ?
+ 0 : (m_loopCount == -1 ? duration() : totalDuration());
+ }
+
+ m_state = newState;
+ //(un)registration of the animation must always happen before calls to
+ //virtual function (updateState) to ensure a correct state of the timer
+ bool isTopLevel = !m_group || m_group->isStopped();
+ if (oldState == Running) {
+ if (newState == Paused && m_hasRegisteredTimer)
+ QQmlAnimationTimer::ensureTimerUpdate();
+ //the animation, is not running any more
+ QQmlAnimationTimer::unregisterAnimation(this);
+ } else if (newState == Running) {
+ QQmlAnimationTimer::registerAnimation(this, isTopLevel);
+ }
+
+ //starting an animation qualifies as a top level loop change
+ if (newState == Running && oldState == Stopped && !m_group)
+ topLevelAnimationLoopChanged();
+
+ RETURN_IF_DELETED(updateState(newState, oldState));
+
+ if (newState != m_state) //this is to be safe if updateState changes the state
+ return;
+
+ // Notify state change
+ stateChanged(newState, oldState);
+ if (newState != m_state) //this is to be safe if updateState changes the state
+ return;
+
+ switch (m_state) {
+ case Paused:
+ break;
+ case Running:
+ {
+ // this ensures that the value is updated now that the animation is running
+ if (oldState == Stopped) {
+ if (isTopLevel) {
+ // currentTime needs to be updated if pauseTimer is active
+ QQmlAnimationTimer::ensureTimerUpdate();
+ setCurrentTime(m_totalCurrentTime);
+ }
+ }
+ }
+ break;
+ case Stopped:
+ // Leave running state.
+ int dura = duration();
+
+ if (dura == -1 || m_loopCount < 0
+ || (oldDirection == Forward && (oldCurrentTime * (oldCurrentLoop + 1)) == (dura * m_loopCount))
+ || (oldDirection == Backward && oldCurrentTime == 0)) {
+ finished();
+ }
+ break;
+ }
+}
+
+void QAbstractAnimationJob::setDirection(Direction direction)
+{
+ if (m_direction == direction)
+ return;
+
+ if (m_state == Stopped) {
+ if (m_direction == Backward) {
+ m_currentTime = duration();
+ m_currentLoop = m_loopCount - 1;
+ } else {
+ m_currentTime = 0;
+ m_currentLoop = 0;
+ }
+ }
+
+ // the commands order below is important: first we need to setCurrentTime with the old direction,
+ // then update the direction on this and all children and finally restart the pauseTimer if needed
+ if (m_hasRegisteredTimer)
+ QQmlAnimationTimer::ensureTimerUpdate();
+
+ m_direction = direction;
+ updateDirection(direction);
+
+ if (m_hasRegisteredTimer)
+ // needed to update the timer interval in case of a pause animation
+ QQmlAnimationTimer::updateAnimationTimer();
+}
+
+void QAbstractAnimationJob::setLoopCount(int loopCount)
+{
+ m_loopCount = loopCount;
+}
+
+int QAbstractAnimationJob::totalDuration() const
+{
+ int dura = duration();
+ if (dura <= 0)
+ return dura;
+ int loopcount = loopCount();
+ if (loopcount < 0)
+ return -1;
+ return dura * loopcount;
+}
+
+void QAbstractAnimationJob::setCurrentTime(int msecs)
+{
+ msecs = qMax(msecs, 0);
+ // Calculate new time and loop.
+ int dura = duration();
+ int totalDura = dura <= 0 ? dura : ((m_loopCount < 0) ? -1 : dura * m_loopCount);
+ if (totalDura != -1)
+ msecs = qMin(totalDura, msecs);
+ m_totalCurrentTime = msecs;
+
+ // Update new values.
+ int oldLoop = m_currentLoop;
+ m_currentLoop = ((dura <= 0) ? 0 : (msecs / dura));
+ if (m_currentLoop == m_loopCount) {
+ //we're at the end
+ m_currentTime = qMax(0, dura);
+ m_currentLoop = qMax(0, m_loopCount - 1);
+ } else {
+ if (m_direction == Forward) {
+ m_currentTime = (dura <= 0) ? msecs : (msecs % dura);
+ } else {
+ m_currentTime = (dura <= 0) ? msecs : ((msecs - 1) % dura) + 1;
+ if (m_currentTime == dura)
+ --m_currentLoop;
+ }
+ }
+
+ if (m_currentLoop != oldLoop && !m_group) //### verify Running as well?
+ topLevelAnimationLoopChanged();
+
+ RETURN_IF_DELETED(updateCurrentTime(m_currentTime));
+
+ if (m_currentLoop != oldLoop)
+ currentLoopChanged(m_currentLoop);
+
+ // All animations are responsible for stopping the animation when their
+ // own end state is reached; in this case the animation is time driven,
+ // and has reached the end.
+ if ((m_direction == Forward && m_totalCurrentTime == totalDura)
+ || (m_direction == Backward && m_totalCurrentTime == 0)) {
+ stop();
+ }
+}
+
+void QAbstractAnimationJob::start()
+{
+ if (m_state == Running)
+ return;
+ setState(Running);
+}
+
+void QAbstractAnimationJob::stop()
+{
+ if (m_state == Stopped)
+ return;
+ setState(Stopped);
+}
+
+void QAbstractAnimationJob::pause()
+{
+ if (m_state == Stopped) {
+ qWarning("QAbstractAnimationJob::pause: Cannot pause a stopped animation");
+ return;
+ }
+
+ setState(Paused);
+}
+
+void QAbstractAnimationJob::resume()
+{
+ if (m_state != Paused) {
+ qWarning("QAbstractAnimationJob::resume: "
+ "Cannot resume an animation that is not paused");
+ return;
+ }
+ setState(Running);
+}
+
+void QAbstractAnimationJob::updateState(QAbstractAnimationJob::State newState,
+ QAbstractAnimationJob::State oldState)
+{
+ Q_UNUSED(oldState);
+ Q_UNUSED(newState);
+}
+
+void QAbstractAnimationJob::updateDirection(QAbstractAnimationJob::Direction direction)
+{
+ Q_UNUSED(direction);
+}
+
+void QAbstractAnimationJob::finished()
+{
+ //TODO: update this code so it is valid to delete the animation in animationFinished
+ for (int i = 0; i < changeListeners.count(); ++i) {
+ const QAbstractAnimationJob::ChangeListener &change = changeListeners.at(i);
+ if (change.types & QAbstractAnimationJob::Completion)
+ change.listener->animationFinished(this);
+ }
+
+ if (m_group && (duration() == -1 || loopCount() < 0)) {
+ //this is an uncontrolled animation, need to notify the group animation we are finished
+ m_group->uncontrolledAnimationFinished(this);
+ }
+}
+
+void QAbstractAnimationJob::stateChanged(QAbstractAnimationJob::State newState, QAbstractAnimationJob::State oldState)
+{
+ for (int i = 0; i < changeListeners.count(); ++i) {
+ const QAbstractAnimationJob::ChangeListener &change = changeListeners.at(i);
+ if (change.types & QAbstractAnimationJob::StateChange)
+ change.listener->animationStateChanged(this, newState, oldState);
+ }
+}
+
+void QAbstractAnimationJob::currentLoopChanged(int currentLoop)
+{
+ Q_UNUSED(currentLoop);
+ for (int i = 0; i < changeListeners.count(); ++i) {
+ const QAbstractAnimationJob::ChangeListener &change = changeListeners.at(i);
+ if (change.types & QAbstractAnimationJob::CurrentLoop)
+ change.listener->animationCurrentLoopChanged(this);
+ }
+}
+
+void QAbstractAnimationJob::addAnimationChangeListener(QAnimationJobChangeListener *listener, QAbstractAnimationJob::ChangeTypes changes)
+{
+ changeListeners.append(ChangeListener(listener, changes));
+}
+
+void QAbstractAnimationJob::removeAnimationChangeListener(QAnimationJobChangeListener *listener, QAbstractAnimationJob::ChangeTypes changes)
+{
+ changeListeners.removeOne(ChangeListener(listener, changes));
+}
+
+
+QT_END_NAMESPACE
+
+//#include "moc_qabstractanimation2_p.cpp"
diff --git a/src/qml/animations/qabstractanimationjob_p.h b/src/qml/animations/qabstractanimationjob_p.h
new file mode 100644
index 0000000000..f00090cb30
--- /dev/null
+++ b/src/qml/animations/qabstractanimationjob_p.h
@@ -0,0 +1,233 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QABSTRACTANIMATIONJOB_P_H
+#define QABSTRACTANIMATIONJOB_P_H
+
+#include <QtQml/qtqmlglobal.h>
+#include <QtCore/QObject>
+#include <QtCore/private/qabstractanimation_p.h>
+#include "private/qpodvector_p.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Qml)
+
+class QAnimationGroupJob;
+class QAnimationJobChangeListener;
+class Q_QML_EXPORT QAbstractAnimationJob
+{
+ Q_DISABLE_COPY(QAbstractAnimationJob)
+public:
+ enum Direction {
+ Forward,
+ Backward
+ };
+
+ enum State {
+ Stopped,
+ Paused,
+ Running
+ };
+
+ QAbstractAnimationJob();
+ virtual ~QAbstractAnimationJob();
+
+ //definition
+ inline QAnimationGroupJob *group() const {return m_group;}
+
+ inline int loopCount() const {return m_loopCount;}
+ void setLoopCount(int loopCount);
+
+ int totalDuration() const;
+ virtual int duration() const {return 0;}
+
+ inline QAbstractAnimationJob::Direction direction() const {return m_direction;}
+ void setDirection(QAbstractAnimationJob::Direction direction);
+
+ //state
+ inline int currentTime() const {return m_totalCurrentTime;}
+ inline int currentLoopTime() const {return m_currentTime;}
+ inline int currentLoop() const {return m_currentLoop;}
+ inline QAbstractAnimationJob::State state() const {return m_state;}
+ inline bool isRunning() { return m_state == Running; }
+ inline bool isStopped() { return m_state == Stopped; }
+ inline bool isPaused() { return m_state == Paused; }
+
+ void setCurrentTime(int msecs);
+
+ void start();
+ void pause();
+ void resume();
+ void stop();
+
+ enum ChangeType {
+ Completion = 0x01,
+ StateChange = 0x02,
+ CurrentLoop = 0x04
+ };
+ Q_DECLARE_FLAGS(ChangeTypes, ChangeType)
+
+ void addAnimationChangeListener(QAnimationJobChangeListener *listener, QAbstractAnimationJob::ChangeTypes);
+ void removeAnimationChangeListener(QAnimationJobChangeListener *listener, QAbstractAnimationJob::ChangeTypes);
+
+ QAbstractAnimationJob *nextSibling() const { return m_nextSibling; }
+ QAbstractAnimationJob *previousSibling() const { return m_previousSibling; }
+
+protected:
+ virtual void updateCurrentTime(int) {}
+ virtual void updateState(QAbstractAnimationJob::State newState, QAbstractAnimationJob::State oldState);
+ virtual void updateDirection(QAbstractAnimationJob::Direction direction);
+ virtual void topLevelAnimationLoopChanged() {}
+
+ void setState(QAbstractAnimationJob::State state);
+
+ void finished();
+ void stateChanged(QAbstractAnimationJob::State newState, QAbstractAnimationJob::State oldState);
+ void currentLoopChanged(int currentLoop);
+ void directionChanged(QAbstractAnimationJob::Direction);
+
+ //definition
+ bool m_isPause;
+ bool m_isGroup;
+ int m_loopCount;
+ QAnimationGroupJob *m_group;
+ QAbstractAnimationJob::Direction m_direction;
+
+ //state
+ QAbstractAnimationJob::State m_state;
+ int m_totalCurrentTime;
+ int m_currentTime;
+ int m_currentLoop;
+ bool m_hasRegisteredTimer;
+ //records the finish time for an uncontrolled animation (used by animation groups)
+ int m_uncontrolledFinishTime;
+ bool *m_wasDeleted;
+
+ struct ChangeListener {
+ ChangeListener(QAnimationJobChangeListener *l, QAbstractAnimationJob::ChangeTypes t) : listener(l), types(t) {}
+ QAnimationJobChangeListener *listener;
+ QAbstractAnimationJob::ChangeTypes types;
+ bool operator==(const ChangeListener &other) const { return listener == other.listener && types == other.types; }
+ };
+ QPODVector<ChangeListener,4> changeListeners;
+
+ QAbstractAnimationJob *m_nextSibling;
+ QAbstractAnimationJob *m_previousSibling;
+
+ friend class QQmlAnimationTimer;
+ friend class QAnimationGroupJob;
+};
+
+class Q_AUTOTEST_EXPORT QAnimationJobChangeListener
+{
+public:
+ virtual void animationFinished(QAbstractAnimationJob *) {}
+ virtual void animationStateChanged(QAbstractAnimationJob *, QAbstractAnimationJob::State, QAbstractAnimationJob::State) {}
+ virtual void animationCurrentLoopChanged(QAbstractAnimationJob *) {}
+};
+
+class Q_QML_EXPORT QQmlAnimationTimer : public QAbstractAnimationTimer
+{
+ Q_OBJECT
+private:
+ QQmlAnimationTimer();
+
+public:
+ static QQmlAnimationTimer *instance();
+ static QQmlAnimationTimer *instance(bool create);
+
+ static void registerAnimation(QAbstractAnimationJob *animation, bool isTopLevel);
+ static void unregisterAnimation(QAbstractAnimationJob *animation);
+
+ /*
+ this is used for updating the currentTime of all animations in case the pause
+ timer is active or, otherwise, only of the animation passed as parameter.
+ */
+ static void ensureTimerUpdate();
+
+ /*
+ this will evaluate the need of restarting the pause timer in case there is still
+ some pause animations running.
+ */
+ static void updateAnimationTimer();
+
+ void restartAnimationTimer();
+ void updateAnimationsTime(qint64 timeStep);
+
+ int currentDelta() { return lastDelta; }
+
+ //useful for profiling/debugging
+ int runningAnimationCount() { return animations.count(); }
+
+private Q_SLOTS:
+ void startAnimations();
+ void stopTimer();
+
+private:
+ qint64 lastTick;
+ int lastDelta;
+ int currentAnimationIdx;
+ bool insideTick;
+ bool startAnimationPending;
+ bool stopTimerPending;
+
+ QList<QAbstractAnimationJob*> animations, animationsToStart;
+
+ // this is the count of running animations that are not a group neither a pause animation
+ int runningLeafAnimations;
+ QList<QAbstractAnimationJob*> runningPauseAnimations;
+
+ void registerRunningAnimation(QAbstractAnimationJob *animation);
+ void unregisterRunningAnimation(QAbstractAnimationJob *animation);
+
+ int closestPauseAnimationTimeToFinish();
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QAbstractAnimationJob::ChangeTypes)
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QABSTRACTANIMATIONJOB_P_H
diff --git a/src/qml/animations/qanimationgroupjob.cpp b/src/qml/animations/qanimationgroupjob.cpp
new file mode 100644
index 0000000000..83b2192313
--- /dev/null
+++ b/src/qml/animations/qanimationgroupjob.cpp
@@ -0,0 +1,164 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "private/qanimationgroupjob_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QAnimationGroupJob::QAnimationGroupJob()
+ : QAbstractAnimationJob(), m_firstChild(0), m_lastChild(0)
+{
+ m_isGroup = true;
+}
+
+QAnimationGroupJob::~QAnimationGroupJob()
+{
+ while (firstChild() != 0)
+ delete firstChild();
+}
+
+void QAnimationGroupJob::topLevelAnimationLoopChanged()
+{
+ for (QAbstractAnimationJob *animation = firstChild(); animation; animation = animation->nextSibling())
+ animation->topLevelAnimationLoopChanged();
+}
+
+void QAnimationGroupJob::appendAnimation(QAbstractAnimationJob *animation)
+{
+ if (QAnimationGroupJob *oldGroup = animation->m_group)
+ oldGroup->removeAnimation(animation);
+
+ Q_ASSERT(!animation->previousSibling() && !animation->nextSibling());
+
+ if (m_lastChild)
+ m_lastChild->m_nextSibling = animation;
+ else
+ m_firstChild = animation;
+ animation->m_previousSibling = m_lastChild;
+ m_lastChild = animation;
+
+ animation->m_group = this;
+ animationInserted(animation);
+}
+
+void QAnimationGroupJob::prependAnimation(QAbstractAnimationJob *animation)
+{
+ if (QAnimationGroupJob *oldGroup = animation->m_group)
+ oldGroup->removeAnimation(animation);
+
+ Q_ASSERT(!previousSibling() && !nextSibling());
+
+ if (m_firstChild)
+ m_firstChild->m_previousSibling = animation;
+ else
+ m_lastChild = animation;
+ animation->m_nextSibling = m_firstChild;
+ m_firstChild = animation;
+
+ animation->m_group = this;
+ animationInserted(animation);
+}
+
+void QAnimationGroupJob::removeAnimation(QAbstractAnimationJob *animation)
+{
+ Q_ASSERT(animation);
+ Q_ASSERT(animation->m_group == this);
+ QAbstractAnimationJob *prev = animation->previousSibling();
+ QAbstractAnimationJob *next = animation->nextSibling();
+
+ if (prev)
+ prev->m_nextSibling = next;
+ else
+ m_firstChild = next;
+
+ if (next)
+ next->m_previousSibling = prev;
+ else
+ m_lastChild = prev;
+
+ animation->m_previousSibling = 0;
+ animation->m_nextSibling = 0;
+
+ animation->m_group = 0;
+ animationRemoved(animation, prev, next);
+}
+
+void QAnimationGroupJob::clear()
+{
+ //### should this remove and delete, or just remove?
+ while (firstChild() != 0)
+ delete firstChild(); //removeAnimation(firstChild());
+}
+
+void QAnimationGroupJob::resetUncontrolledAnimationsFinishTime()
+{
+ for (QAbstractAnimationJob *animation = firstChild(); animation; animation = animation->nextSibling()) {
+ if (animation->duration() == -1 || animation->loopCount() < 0) {
+ resetUncontrolledAnimationFinishTime(animation);
+ }
+ }
+}
+
+void QAnimationGroupJob::resetUncontrolledAnimationFinishTime(QAbstractAnimationJob *anim)
+{
+ setUncontrolledAnimationFinishTime(anim, -1);
+}
+
+void QAnimationGroupJob::setUncontrolledAnimationFinishTime(QAbstractAnimationJob *anim, int time)
+{
+ anim->m_uncontrolledFinishTime = time;
+}
+
+void QAnimationGroupJob::uncontrolledAnimationFinished(QAbstractAnimationJob *animation)
+{
+ Q_UNUSED(animation);
+}
+
+void QAnimationGroupJob::animationRemoved(QAbstractAnimationJob* anim, QAbstractAnimationJob* , QAbstractAnimationJob* )
+{
+ resetUncontrolledAnimationFinishTime(anim);
+ if (!firstChild()) {
+ m_currentTime = 0;
+ stop();
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/animations/qanimationgroupjob_p.h b/src/qml/animations/qanimationgroupjob_p.h
new file mode 100644
index 0000000000..303dc898d9
--- /dev/null
+++ b/src/qml/animations/qanimationgroupjob_p.h
@@ -0,0 +1,93 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QANIMATIONGROUPJOB_P_H
+#define QANIMATIONGROUPJOB_P_H
+
+#include "private/qabstractanimationjob_p.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Qml)
+
+class Q_QML_EXPORT QAnimationGroupJob : public QAbstractAnimationJob
+{
+ Q_DISABLE_COPY(QAnimationGroupJob)
+public:
+ QAnimationGroupJob();
+ ~QAnimationGroupJob();
+
+ void appendAnimation(QAbstractAnimationJob *animation);
+ void prependAnimation(QAbstractAnimationJob *animation);
+ void removeAnimation(QAbstractAnimationJob *animation);
+
+ QAbstractAnimationJob *firstChild() const { return m_firstChild; }
+ QAbstractAnimationJob *lastChild() const { return m_lastChild; }
+
+ void clear();
+
+ //called by QAbstractAnimationJob
+ virtual void uncontrolledAnimationFinished(QAbstractAnimationJob *animation);
+protected:
+ void topLevelAnimationLoopChanged();
+
+ virtual void animationInserted(QAbstractAnimationJob*) { }
+ virtual void animationRemoved(QAbstractAnimationJob*, QAbstractAnimationJob*, QAbstractAnimationJob*);
+
+ //TODO: confirm location of these (should any be moved into QAbstractAnimationJob?)
+ void resetUncontrolledAnimationsFinishTime();
+ void resetUncontrolledAnimationFinishTime(QAbstractAnimationJob *anim);
+ int uncontrolledAnimationFinishTime(QAbstractAnimationJob *anim) const { return anim->m_uncontrolledFinishTime; }
+ void setUncontrolledAnimationFinishTime(QAbstractAnimationJob *anim, int time);
+
+private:
+ //definition
+ QAbstractAnimationJob *m_firstChild;
+ QAbstractAnimationJob *m_lastChild;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif //QANIMATIONGROUPJOB_P_H
diff --git a/src/qml/animations/qanimationjobutil_p.h b/src/qml/animations/qanimationjobutil_p.h
new file mode 100644
index 0000000000..c891b8725d
--- /dev/null
+++ b/src/qml/animations/qanimationjobutil_p.h
@@ -0,0 +1,59 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QANIMATIONJOBUTIL_P_H
+#define QANIMATIONJOBUTIL_P_H
+
+#define RETURN_IF_DELETED(func) \
+{ \
+ bool *prevWasDeleted = m_wasDeleted; \
+ bool wasDeleted = false; \
+ m_wasDeleted = &wasDeleted; \
+ func; \
+ if (wasDeleted) { \
+ if (prevWasDeleted) \
+ *prevWasDeleted = true; \
+ return; \
+ } \
+ m_wasDeleted = prevWasDeleted; \
+}
+
+#endif // QANIMATIONJOBUTIL_P_H
diff --git a/src/qml/animations/qparallelanimationgroupjob.cpp b/src/qml/animations/qparallelanimationgroupjob.cpp
new file mode 100644
index 0000000000..0472c959f4
--- /dev/null
+++ b/src/qml/animations/qparallelanimationgroupjob.cpp
@@ -0,0 +1,227 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "private/qparallelanimationgroupjob_p.h"
+#include "private/qanimationjobutil_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QParallelAnimationGroupJob::QParallelAnimationGroupJob()
+ : QAnimationGroupJob()
+ , m_previousLoop(0)
+ , m_previousCurrentTime(0)
+{
+}
+
+QParallelAnimationGroupJob::~QParallelAnimationGroupJob()
+{
+}
+
+int QParallelAnimationGroupJob::duration() const
+{
+ int ret = 0;
+
+ for (QAbstractAnimationJob *animation = firstChild(); animation; animation = animation->nextSibling()) {
+ int currentDuration = animation->totalDuration();
+ //this takes care of the case where a parallel animation group has controlled and uncontrolled
+ //animations, and the uncontrolled stop before the controlled
+ if (currentDuration == -1)
+ currentDuration = uncontrolledAnimationFinishTime(animation);
+ if (currentDuration == -1)
+ return -1; // Undetermined length
+
+ ret = qMax(ret, currentDuration);
+ }
+
+ return ret;
+}
+
+void QParallelAnimationGroupJob::updateCurrentTime(int /*currentTime*/)
+{
+ if (!firstChild())
+ return;
+
+ if (m_currentLoop > m_previousLoop) {
+ // simulate completion of the loop
+ int dura = duration();
+ if (dura > 0) {
+ for (QAbstractAnimationJob *animation = firstChild(); animation; animation = animation->nextSibling()) {
+ if (!animation->isStopped())
+ RETURN_IF_DELETED(animation->setCurrentTime(dura)); // will stop
+ }
+ }
+ } else if (m_currentLoop < m_previousLoop) {
+ // simulate completion of the loop seeking backwards
+ for (QAbstractAnimationJob *animation = firstChild(); animation; animation = animation->nextSibling()) {
+ //we need to make sure the animation is in the right state
+ //and then rewind it
+ applyGroupState(animation);
+ RETURN_IF_DELETED(animation->setCurrentTime(0));
+ animation->stop();
+ }
+ }
+
+ // finally move into the actual time of the current loop
+ for (QAbstractAnimationJob *animation = firstChild(); animation; animation = animation->nextSibling()) {
+ const int dura = animation->totalDuration();
+ //if the loopcount is bigger we should always start all animations
+ if (m_currentLoop > m_previousLoop
+ //if we're at the end of the animation, we need to start it if it wasn't already started in this loop
+ //this happens in Backward direction where not all animations are started at the same time
+ || shouldAnimationStart(animation, m_previousCurrentTime > dura /*startIfAtEnd*/)) {
+ applyGroupState(animation);
+ }
+
+ if (animation->state() == state()) {
+ RETURN_IF_DELETED(animation->setCurrentTime(m_currentTime));
+ if (dura > 0 && m_currentTime > dura)
+ animation->stop();
+ }
+ }
+ m_previousLoop = m_currentLoop;
+ m_previousCurrentTime = m_currentTime;
+}
+
+void QParallelAnimationGroupJob::updateState(QAbstractAnimationJob::State newState,
+ QAbstractAnimationJob::State oldState)
+{
+ QAnimationGroupJob::updateState(newState, oldState);
+
+ switch (newState) {
+ case Stopped:
+ for (QAbstractAnimationJob *animation = firstChild(); animation; animation = animation->nextSibling())
+ animation->stop();
+ break;
+ case Paused:
+ for (QAbstractAnimationJob *animation = firstChild(); animation; animation = animation->nextSibling())
+ if (animation->isRunning())
+ animation->pause();
+ break;
+ case Running:
+ for (QAbstractAnimationJob *animation = firstChild(); animation; animation = animation->nextSibling()) {
+ if (oldState == Stopped)
+ animation->stop();
+ resetUncontrolledAnimationFinishTime(animation);
+ animation->setDirection(m_direction);
+ if (shouldAnimationStart(animation, oldState == Stopped))
+ animation->start();
+ }
+ break;
+ }
+}
+
+bool QParallelAnimationGroupJob::shouldAnimationStart(QAbstractAnimationJob *animation, bool startIfAtEnd) const
+{
+ const int dura = animation->totalDuration();
+
+ if (dura == -1)
+ return uncontrolledAnimationFinishTime(animation) == -1;
+
+ if (startIfAtEnd)
+ return m_currentTime <= dura;
+ if (m_direction == Forward)
+ return m_currentTime < dura;
+ else //direction == Backward
+ return m_currentTime && m_currentTime <= dura;
+}
+
+void QParallelAnimationGroupJob::applyGroupState(QAbstractAnimationJob *animation)
+{
+ switch (m_state)
+ {
+ case Running:
+ animation->start();
+ break;
+ case Paused:
+ animation->pause();
+ break;
+ case Stopped:
+ default:
+ break;
+ }
+}
+
+void QParallelAnimationGroupJob::updateDirection(QAbstractAnimationJob::Direction direction)
+{
+ //we need to update the direction of the current animation
+ if (!isStopped()) {
+ for (QAbstractAnimationJob *animation = firstChild(); animation; animation = animation->nextSibling()) {
+ animation->setDirection(direction);
+ }
+ } else {
+ if (direction == Forward) {
+ m_previousLoop = 0;
+ m_previousCurrentTime = 0;
+ } else {
+ // Looping backwards with loopCount == -1 does not really work well...
+ m_previousLoop = (m_loopCount == -1 ? 0 : m_loopCount - 1);
+ m_previousCurrentTime = duration();
+ }
+ }
+}
+
+void QParallelAnimationGroupJob::uncontrolledAnimationFinished(QAbstractAnimationJob *animation)
+{
+ Q_ASSERT(animation && (animation->duration() == -1 || animation->loopCount() < 0));
+ int uncontrolledRunningCount = 0;
+
+ for (QAbstractAnimationJob *child = firstChild(); child; child = child->nextSibling()) {
+ if (child == animation) {
+ setUncontrolledAnimationFinishTime(animation, animation->currentTime());
+ } else if (child->duration() == -1 || child->loopCount() < 0) {
+ if (uncontrolledAnimationFinishTime(child) == -1)
+ ++uncontrolledRunningCount;
+ }
+ }
+
+ if (uncontrolledRunningCount > 0)
+ return;
+
+ int maxDuration = 0;
+ for (QAbstractAnimationJob *animation = firstChild(); animation; animation = animation->nextSibling())
+ maxDuration = qMax(maxDuration, animation->totalDuration());
+
+ if (m_currentTime >= maxDuration)
+ stop();
+}
+
+QT_END_NAMESPACE
+
diff --git a/src/qml/animations/qparallelanimationgroupjob_p.h b/src/qml/animations/qparallelanimationgroupjob_p.h
new file mode 100644
index 0000000000..d77a8c84f9
--- /dev/null
+++ b/src/qml/animations/qparallelanimationgroupjob_p.h
@@ -0,0 +1,81 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QPARALLELANIMATIONGROUPJOB_P_H
+#define QPARALLELANIMATIONGROUPJOB_P_H
+
+#include "private/qanimationgroupjob_p.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Qml)
+
+class Q_QML_EXPORT QParallelAnimationGroupJob : public QAnimationGroupJob
+{
+ Q_DISABLE_COPY(QParallelAnimationGroupJob)
+public:
+ QParallelAnimationGroupJob();
+ ~QParallelAnimationGroupJob();
+
+ int duration() const;
+
+protected:
+ void updateCurrentTime(int currentTime);
+ void updateState(QAbstractAnimationJob::State newState, QAbstractAnimationJob::State oldState);
+ void updateDirection(QAbstractAnimationJob::Direction direction);
+ void uncontrolledAnimationFinished(QAbstractAnimationJob *animation);
+
+private:
+ bool shouldAnimationStart(QAbstractAnimationJob *animation, bool startIfAtEnd) const;
+ void applyGroupState(QAbstractAnimationJob *animation);
+
+ //state
+ int m_previousLoop;
+ int m_previousCurrentTime;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QPARALLELANIMATIONGROUPJOB_P_H
diff --git a/src/qml/animations/qpauseanimationjob.cpp b/src/qml/animations/qpauseanimationjob.cpp
new file mode 100644
index 0000000000..40bcef7e89
--- /dev/null
+++ b/src/qml/animations/qpauseanimationjob.cpp
@@ -0,0 +1,71 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "private/qpauseanimationjob_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QPauseAnimationJob::QPauseAnimationJob(int duration)
+ : QAbstractAnimationJob()
+ , m_duration(duration)
+{
+ m_isPause = true;
+}
+
+QPauseAnimationJob::~QPauseAnimationJob()
+{
+}
+
+int QPauseAnimationJob::duration() const
+{
+ return m_duration;
+}
+
+void QPauseAnimationJob::setDuration(int msecs)
+{
+ m_duration = msecs;
+}
+
+void QPauseAnimationJob::updateCurrentTime(int)
+{
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/animations/qpauseanimationjob_p.h b/src/qml/animations/qpauseanimationjob_p.h
new file mode 100644
index 0000000000..82462be101
--- /dev/null
+++ b/src/qml/animations/qpauseanimationjob_p.h
@@ -0,0 +1,75 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QPAUSEANIMATIONJOB_P_H
+#define QPAUSEANIMATIONJOB_P_H
+
+#include <private/qanimationgroupjob_p.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Qml)
+
+class Q_QML_EXPORT QPauseAnimationJob : public QAbstractAnimationJob
+{
+ Q_DISABLE_COPY(QPauseAnimationJob)
+public:
+ explicit QPauseAnimationJob(int duration = 250);
+ ~QPauseAnimationJob();
+
+ int duration() const;
+ void setDuration(int msecs);
+
+protected:
+ void updateCurrentTime(int);
+
+private:
+ //definition
+ int m_duration;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QPAUSEANIMATIONJOB_P_H
diff --git a/src/qml/animations/qsequentialanimationgroupjob.cpp b/src/qml/animations/qsequentialanimationgroupjob.cpp
new file mode 100644
index 0000000000..12cce39fbc
--- /dev/null
+++ b/src/qml/animations/qsequentialanimationgroupjob.cpp
@@ -0,0 +1,388 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "private/qsequentialanimationgroupjob_p.h"
+#include "private/qpauseanimationjob_p.h"
+#include "private/qanimationjobutil_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QSequentialAnimationGroupJob::QSequentialAnimationGroupJob()
+ : QAnimationGroupJob()
+ , m_currentAnimation(0)
+ , m_previousLoop(0)
+{
+}
+
+QSequentialAnimationGroupJob::~QSequentialAnimationGroupJob()
+{
+}
+
+bool QSequentialAnimationGroupJob::atEnd() const
+{
+ // we try to detect if we're at the end of the group
+ //this is true if the following conditions are true:
+ // 1. we're in the last loop
+ // 2. the direction is forward
+ // 3. the current animation is the last one
+ // 4. the current animation has reached its end
+ const int animTotalCurrentTime = m_currentAnimation->currentTime();
+ return (m_currentLoop == m_loopCount - 1
+ && m_direction == Forward
+ && !m_currentAnimation->nextSibling()
+ && animTotalCurrentTime == animationActualTotalDuration(m_currentAnimation));
+}
+
+int QSequentialAnimationGroupJob::animationActualTotalDuration(QAbstractAnimationJob *anim) const
+{
+ int ret = anim->totalDuration();
+ if (ret == -1)
+ ret = uncontrolledAnimationFinishTime(anim); //we can try the actual duration there
+ return ret;
+}
+
+QSequentialAnimationGroupJob::AnimationIndex QSequentialAnimationGroupJob::indexForCurrentTime() const
+{
+ Q_ASSERT(firstChild());
+
+ AnimationIndex ret;
+ QAbstractAnimationJob *anim = 0;
+ int duration = 0;
+
+ for (anim = firstChild(); anim; anim = anim->nextSibling()) {
+ duration = animationActualTotalDuration(anim);
+
+ // 'animation' is the current animation if one of these reasons is true:
+ // 1. it's duration is undefined
+ // 2. it ends after msecs
+ // 3. it is the last animation (this can happen in case there is at least 1 uncontrolled animation)
+ // 4. it ends exactly in msecs and the direction is backwards
+ if (duration == -1 || m_currentTime < (ret.timeOffset + duration)
+ || (m_currentTime == (ret.timeOffset + duration) && m_direction == QAbstractAnimationJob::Backward)) {
+ ret.animation = anim;
+ return ret;
+ }
+
+ if (anim == m_currentAnimation)
+ ret.afterCurrent = true;
+
+ // 'animation' has a non-null defined duration and is not the one at time 'msecs'.
+ ret.timeOffset += duration;
+ }
+
+ // this can only happen when one of those conditions is true:
+ // 1. the duration of the group is undefined and we passed its actual duration
+ // 2. there are only 0-duration animations in the group
+ ret.timeOffset -= duration;
+ ret.animation = lastChild();
+ return ret;
+}
+
+void QSequentialAnimationGroupJob::restart()
+{
+ // restarting the group by making the first/last animation the current one
+ if (m_direction == Forward) {
+ m_previousLoop = 0;
+ if (m_currentAnimation == firstChild())
+ activateCurrentAnimation();
+ else
+ setCurrentAnimation(firstChild());
+ }
+ else { // direction == Backward
+ m_previousLoop = m_loopCount - 1;
+ if (m_currentAnimation == lastChild())
+ activateCurrentAnimation();
+ else
+ setCurrentAnimation(lastChild());
+ }
+}
+
+void QSequentialAnimationGroupJob::advanceForwards(const AnimationIndex &newAnimationIndex)
+{
+ if (m_previousLoop < m_currentLoop) {
+ // we need to fast forward to the end
+ for (QAbstractAnimationJob *anim = m_currentAnimation; anim; anim = anim->nextSibling()) {
+ setCurrentAnimation(anim, true);
+ RETURN_IF_DELETED(anim->setCurrentTime(animationActualTotalDuration(anim)));
+ }
+ // this will make sure the current animation is reset to the beginning
+ if (firstChild() && !firstChild()->nextSibling()) //count == 1
+ // we need to force activation because setCurrentAnimation will have no effect
+ activateCurrentAnimation();
+ else
+ setCurrentAnimation(firstChild(), true);
+ }
+
+ // and now we need to fast forward from the current position to
+ for (QAbstractAnimationJob *anim = m_currentAnimation; anim && anim != newAnimationIndex.animation; anim = anim->nextSibling()) { //### WRONG,
+ setCurrentAnimation(anim, true);
+ RETURN_IF_DELETED(anim->setCurrentTime(animationActualTotalDuration(anim)));
+ }
+ // setting the new current animation will happen later
+}
+
+void QSequentialAnimationGroupJob::rewindForwards(const AnimationIndex &newAnimationIndex)
+{
+ if (m_previousLoop > m_currentLoop) {
+ // we need to fast rewind to the beginning
+ for (QAbstractAnimationJob *anim = m_currentAnimation; anim; anim = anim->previousSibling()) {
+ setCurrentAnimation(anim, true);
+ RETURN_IF_DELETED(anim->setCurrentTime(0));
+ }
+ // this will make sure the current animation is reset to the end
+ if (lastChild() && !lastChild()->previousSibling()) //count == 1
+ // we need to force activation because setCurrentAnimation will have no effect
+ activateCurrentAnimation();
+ else {
+ setCurrentAnimation(lastChild(), true);
+ }
+ }
+
+ // and now we need to fast rewind from the current position to
+ for (QAbstractAnimationJob *anim = m_currentAnimation; anim && anim != newAnimationIndex.animation; anim = anim->previousSibling()) {
+ setCurrentAnimation(anim, true);
+ RETURN_IF_DELETED(anim->setCurrentTime(0));
+ }
+ // setting the new current animation will happen later
+}
+
+int QSequentialAnimationGroupJob::duration() const
+{
+ int ret = 0;
+
+ for (QAbstractAnimationJob *anim = firstChild(); anim; anim = anim->nextSibling()) {
+ const int currentDuration = anim->totalDuration();
+ if (currentDuration == -1)
+ return -1; // Undetermined length
+
+ ret += currentDuration;
+ }
+
+ return ret;
+}
+
+void QSequentialAnimationGroupJob::updateCurrentTime(int currentTime)
+{
+ if (!m_currentAnimation)
+ return;
+
+ const QSequentialAnimationGroupJob::AnimationIndex newAnimationIndex = indexForCurrentTime();
+
+ // newAnimationIndex.index is the new current animation
+ if (m_previousLoop < m_currentLoop
+ || (m_previousLoop == m_currentLoop && m_currentAnimation != newAnimationIndex.animation && newAnimationIndex.afterCurrent)) {
+ // advancing with forward direction is the same as rewinding with backwards direction
+ RETURN_IF_DELETED(advanceForwards(newAnimationIndex));
+ } else if (m_previousLoop > m_currentLoop
+ || (m_previousLoop == m_currentLoop && m_currentAnimation != newAnimationIndex.animation && !newAnimationIndex.afterCurrent)) {
+ // rewinding with forward direction is the same as advancing with backwards direction
+ RETURN_IF_DELETED(rewindForwards(newAnimationIndex));
+ }
+
+ setCurrentAnimation(newAnimationIndex.animation);
+
+ const int newCurrentTime = currentTime - newAnimationIndex.timeOffset;
+
+ if (m_currentAnimation) {
+ RETURN_IF_DELETED(m_currentAnimation->setCurrentTime(newCurrentTime));
+ if (atEnd()) {
+ //we make sure that we don't exceed the duration here
+ m_currentTime += m_currentAnimation->currentTime() - newCurrentTime;
+ stop();
+ }
+ } else {
+ //the only case where currentAnimation could be null
+ //is when all animations have been removed
+ Q_ASSERT(!firstChild());
+ m_currentTime = 0;
+ stop();
+ }
+
+ m_previousLoop = m_currentLoop;
+}
+
+void QSequentialAnimationGroupJob::updateState(QAbstractAnimationJob::State newState,
+ QAbstractAnimationJob::State oldState)
+{
+ QAnimationGroupJob::updateState(newState, oldState);
+
+ if (!m_currentAnimation)
+ return;
+
+ switch (newState) {
+ case Stopped:
+ m_currentAnimation->stop();
+ break;
+ case Paused:
+ if (oldState == m_currentAnimation->state() && oldState == Running)
+ m_currentAnimation->pause();
+ else
+ restart();
+ break;
+ case Running:
+ if (oldState == m_currentAnimation->state() && oldState == Paused)
+ m_currentAnimation->start();
+ else
+ restart();
+ break;
+ }
+}
+
+void QSequentialAnimationGroupJob::updateDirection(QAbstractAnimationJob::Direction direction)
+{
+ // we need to update the direction of the current animation
+ if (!isStopped() && m_currentAnimation)
+ m_currentAnimation->setDirection(direction);
+}
+
+void QSequentialAnimationGroupJob::setCurrentAnimation(QAbstractAnimationJob *anim, bool intermediate)
+{
+ if (!anim) {
+ Q_ASSERT(!firstChild());
+ m_currentAnimation = 0;
+ return;
+ }
+
+ if (anim == m_currentAnimation)
+ return;
+
+ // stop the old current animation
+ if (m_currentAnimation)
+ m_currentAnimation->stop();
+
+ m_currentAnimation = anim;
+
+ activateCurrentAnimation(intermediate);
+}
+
+void QSequentialAnimationGroupJob::activateCurrentAnimation(bool intermediate)
+{
+ if (!m_currentAnimation || isStopped())
+ return;
+
+ m_currentAnimation->stop();
+
+ // we ensure the direction is consistent with the group's direction
+ m_currentAnimation->setDirection(m_direction);
+
+ // reset the finish time of the animation if it is uncontrolled
+ if (m_currentAnimation->totalDuration() == -1)
+ resetUncontrolledAnimationFinishTime(m_currentAnimation);
+
+ m_currentAnimation->start();
+ if (!intermediate && isPaused())
+ m_currentAnimation->pause();
+}
+
+void QSequentialAnimationGroupJob::uncontrolledAnimationFinished(QAbstractAnimationJob *animation)
+{
+ Q_UNUSED(animation);
+ Q_ASSERT(animation == m_currentAnimation);
+
+ setUncontrolledAnimationFinishTime(m_currentAnimation, m_currentAnimation->currentTime());
+
+ if ((m_direction == Forward && m_currentAnimation == lastChild())
+ || (m_direction == Backward && m_currentAnimation == firstChild())) {
+ // we don't handle looping of a group with undefined duration
+ stop();
+ } else if (m_direction == Forward) {
+ // set the current animation to be the next one
+ setCurrentAnimation(m_currentAnimation->nextSibling());
+ } else {
+ // set the current animation to be the previous one
+ setCurrentAnimation(m_currentAnimation->previousSibling());
+ }
+}
+
+void QSequentialAnimationGroupJob::animationInserted(QAbstractAnimationJob *anim)
+{
+ if (m_currentAnimation == 0)
+ setCurrentAnimation(firstChild()); // initialize the current animation
+
+ if (m_currentAnimation == anim->nextSibling()
+ && m_currentAnimation->currentTime() == 0 && m_currentAnimation->currentLoop() == 0) {
+ //in this case we simply insert the animation before the current one has actually started
+ setCurrentAnimation(anim);
+ }
+
+// TODO
+// if (index < m_currentAnimationIndex || m_currentLoop != 0) {
+// qWarning("QSequentialGroup::insertAnimation only supports to add animations after the current one.");
+// return; //we're not affected because it is added after the current one
+// }
+}
+
+void QSequentialAnimationGroupJob::animationRemoved(QAbstractAnimationJob *anim, QAbstractAnimationJob *prev, QAbstractAnimationJob *next)
+{
+ QAnimationGroupJob::animationRemoved(anim, prev, next);
+
+ Q_ASSERT(m_currentAnimation); // currentAnimation should always be set
+
+ bool removingCurrent = anim == m_currentAnimation;
+ if (removingCurrent) {
+ if (next)
+ setCurrentAnimation(next); //let's try to take the next one
+ else if (prev)
+ setCurrentAnimation(prev);
+ else// case all animations were removed
+ setCurrentAnimation(0);
+ }
+
+ // duration of the previous animations up to the current animation
+ m_currentTime = 0;
+ for (QAbstractAnimationJob *anim = firstChild(); anim; anim = anim->nextSibling()) {
+ if (anim == m_currentAnimation)
+ break;
+ m_currentTime += animationActualTotalDuration(anim);
+
+ }
+
+ if (!removingCurrent) {
+ //the current animation is not the one being removed
+ //so we add its current time to the current time of this group
+ m_currentTime += m_currentAnimation->currentTime();
+ }
+
+ //let's also update the total current time
+ m_totalCurrentTime = m_currentTime + m_loopCount * duration();
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/animations/qsequentialanimationgroupjob_p.h b/src/qml/animations/qsequentialanimationgroupjob_p.h
new file mode 100644
index 0000000000..b406d04f6f
--- /dev/null
+++ b/src/qml/animations/qsequentialanimationgroupjob_p.h
@@ -0,0 +1,108 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSEQUENTIALANIMATIONGROUPJOB_P_H
+#define QSEQUENTIALANIMATIONGROUPJOB_P_H
+
+#include <private/qanimationgroupjob_p.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Qml)
+
+class QPauseAnimationJob;
+class Q_QML_EXPORT QSequentialAnimationGroupJob : public QAnimationGroupJob
+{
+ Q_DISABLE_COPY(QSequentialAnimationGroupJob)
+public:
+ QSequentialAnimationGroupJob();
+ ~QSequentialAnimationGroupJob();
+
+ int duration() const;
+
+ QAbstractAnimationJob *currentAnimation() const { return m_currentAnimation; }
+
+protected:
+ void updateCurrentTime(int);
+ void updateState(QAbstractAnimationJob::State newState, QAbstractAnimationJob::State oldState);
+ void updateDirection(QAbstractAnimationJob::Direction direction);
+ void uncontrolledAnimationFinished(QAbstractAnimationJob *animation);
+
+private:
+ struct AnimationIndex
+ {
+ AnimationIndex() : afterCurrent(false), timeOffset(0), animation(0) {}
+ // AnimationIndex points to the animation at timeOffset, skipping 0 duration animations.
+ // Note that the index semantic is slightly different depending on the direction.
+ bool afterCurrent; //whether animation is before or after m_currentAnimation //TODO: make enum Before/After/Same
+ int timeOffset; // time offset when the animation at index starts.
+ QAbstractAnimationJob *animation; //points to the animation at timeOffset
+ };
+
+ int animationActualTotalDuration(QAbstractAnimationJob *anim) const;
+ AnimationIndex indexForCurrentTime() const;
+
+ void setCurrentAnimation(QAbstractAnimationJob *anim, bool intermediate = false);
+ void activateCurrentAnimation(bool intermediate = false);
+
+ void animationInserted(QAbstractAnimationJob *anim);
+ void animationRemoved(QAbstractAnimationJob *anim,QAbstractAnimationJob*,QAbstractAnimationJob*);
+
+ bool atEnd() const;
+
+ void restart();
+
+ // handle time changes
+ void rewindForwards(const AnimationIndex &newAnimationIndex);
+ void advanceForwards(const AnimationIndex &newAnimationIndex);
+
+ //state
+ QAbstractAnimationJob *m_currentAnimation;
+ int m_previousLoop;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif //QSEQUENTIALANIMATIONGROUPJOB_P_H
diff --git a/src/qml/debugger/debugger.pri b/src/qml/debugger/debugger.pri
new file mode 100644
index 0000000000..10ca9706c4
--- /dev/null
+++ b/src/qml/debugger/debugger.pri
@@ -0,0 +1,32 @@
+SOURCES += \
+ $$PWD/qpacketprotocol.cpp \
+ $$PWD/qqmldebugservice.cpp \
+ $$PWD/qqmldebugclient.cpp \
+ $$PWD/qqmlenginedebug.cpp \
+ $$PWD/qqmlprofilerservice.cpp \
+ $$PWD/qqmldebughelper.cpp \
+ $$PWD/qqmldebugserver.cpp \
+ $$PWD/qqmlinspectorservice.cpp \
+ $$PWD/qv8debugservice.cpp \
+ $$PWD/qv8profilerservice.cpp \
+ $$PWD/qqmlenginedebugservice.cpp \
+ $$PWD/qdebugmessageservice.cpp
+
+HEADERS += \
+ $$PWD/qpacketprotocol_p.h \
+ $$PWD/qqmldebugservice_p.h \
+ $$PWD/qqmldebugservice_p_p.h \
+ $$PWD/qqmldebugclient_p.h \
+ $$PWD/qqmlenginedebug_p.h \
+ $$PWD/qqmlprofilerservice_p.h \
+ $$PWD/qqmldebughelper_p.h \
+ $$PWD/qqmldebugserver_p.h \
+ $$PWD/qqmldebugserverconnection_p.h \
+ $$PWD/qqmldebugstatesdelegate_p.h \
+ $$PWD/qqmlinspectorservice_p.h \
+ $$PWD/qqmlinspectorinterface_p.h \
+ $$PWD/qv8debugservice_p.h \
+ $$PWD/qv8profilerservice_p.h \
+ $$PWD/qqmlenginedebugservice_p.h \
+ $$PWD/qqmldebug.h \
+ $$PWD/qdebugmessageservice_p.h
diff --git a/src/qml/debugger/qdebugmessageservice.cpp b/src/qml/debugger/qdebugmessageservice.cpp
new file mode 100644
index 0000000000..2c52809e56
--- /dev/null
+++ b/src/qml/debugger/qdebugmessageservice.cpp
@@ -0,0 +1,124 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qdebugmessageservice_p.h"
+#include "qqmldebugservice_p_p.h"
+
+QT_BEGIN_NAMESPACE
+
+Q_GLOBAL_STATIC(QDebugMessageService, qmlDebugMessageService)
+
+void DebugMessageHandler(QtMsgType type, const QMessageLogContext &ctxt,
+ const char *buf)
+{
+ QDebugMessageService::instance()->sendDebugMessage(type, ctxt, buf);
+}
+
+class QDebugMessageServicePrivate : public QQmlDebugServicePrivate
+{
+public:
+ QDebugMessageServicePrivate()
+ : oldMsgHandler(0)
+ , prevState(QQmlDebugService::NotConnected)
+ {
+ }
+
+ QMessageHandler oldMsgHandler;
+ QQmlDebugService::State prevState;
+};
+
+QDebugMessageService::QDebugMessageService(QObject *parent) :
+ QQmlDebugService(*(new QDebugMessageServicePrivate()),
+ QLatin1String("DebugMessages"), 2, parent)
+{
+ Q_D(QDebugMessageService);
+
+ registerService();
+ if (state() == Enabled) {
+ d->oldMsgHandler = qInstallMessageHandler(DebugMessageHandler);
+ d->prevState = Enabled;
+ }
+}
+
+QDebugMessageService *QDebugMessageService::instance()
+{
+ return qmlDebugMessageService();
+}
+
+void QDebugMessageService::sendDebugMessage(QtMsgType type,
+ const QMessageLogContext &ctxt,
+ const char *buf)
+{
+ Q_D(QDebugMessageService);
+
+ //We do not want to alter the message handling mechanism
+ //We just eavesdrop and forward the messages to a port
+ //only if a client is connected to it.
+ QByteArray message;
+ QDataStream ws(&message, QIODevice::WriteOnly);
+ ws << QByteArray("MESSAGE") << type << QString::fromLocal8Bit(buf).toUtf8();
+ ws << QString::fromLatin1(ctxt.file).toUtf8();
+ ws << ctxt.line << QString::fromLatin1(ctxt.function).toUtf8();
+
+ sendMessage(message);
+ if (d->oldMsgHandler)
+ (*d->oldMsgHandler)(type, ctxt, buf);
+}
+
+void QDebugMessageService::stateChanged(State state)
+{
+ Q_D(QDebugMessageService);
+
+ if (state != Enabled && d->prevState == Enabled) {
+ QMessageHandler handler = qInstallMessageHandler(d->oldMsgHandler);
+ // has our handler been overwritten in between?
+ if (handler != DebugMessageHandler)
+ qInstallMessageHandler(handler);
+
+ } else if (state == Enabled && d->prevState != Enabled) {
+ d->oldMsgHandler = qInstallMessageHandler(DebugMessageHandler);
+
+ }
+
+ d->prevState = state;
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/debugger/qdebugmessageservice_p.h b/src/qml/debugger/qdebugmessageservice_p.h
new file mode 100644
index 0000000000..88b918e217
--- /dev/null
+++ b/src/qml/debugger/qdebugmessageservice_p.h
@@ -0,0 +1,91 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDEBUGMESSAGESERVICE_P_H
+#define QDEBUGMESSAGESERVICE_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 "qqmldebugservice_p.h"
+
+#include <QtCore/qlogging.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Qml)
+
+class QDebugMessageServicePrivate;
+
+class QDebugMessageService : public QQmlDebugService
+{
+ Q_OBJECT
+public:
+ QDebugMessageService(QObject *parent = 0);
+
+ static QDebugMessageService *instance();
+
+ void sendDebugMessage(QtMsgType type, const QMessageLogContext &ctxt,
+ const char *buf);
+
+protected:
+ void stateChanged(State);
+
+private:
+ Q_DISABLE_COPY(QDebugMessageService)
+ Q_DECLARE_PRIVATE(QDebugMessageService)
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QDEBUGMESSAGESERVICE_P_H
diff --git a/src/qml/debugger/qpacketprotocol.cpp b/src/qml/debugger/qpacketprotocol.cpp
new file mode 100644
index 0000000000..978054a238
--- /dev/null
+++ b/src/qml/debugger/qpacketprotocol.cpp
@@ -0,0 +1,550 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qpacketprotocol_p.h"
+
+#include <QtCore/QBuffer>
+#include <QtCore/QElapsedTimer>
+
+QT_BEGIN_NAMESPACE
+
+static const unsigned int MAX_PACKET_SIZE = 0x7FFFFFFF;
+
+/*!
+ \class QPacketProtocol
+ \internal
+
+ \brief The QPacketProtocol class encapsulates communicating discrete packets
+ across fragmented IO channels, such as TCP sockets.
+
+ QPacketProtocol makes it simple to send arbitrary sized data "packets" across
+ fragmented transports such as TCP and UDP.
+
+ As transmission boundaries are not respected, sending packets over protocols
+ like TCP frequently involves "stitching" them back together at the receiver.
+ QPacketProtocol makes this easier by performing this task for you. Packet
+ data sent using QPacketProtocol is prepended with a 4-byte size header
+ allowing the receiving QPacketProtocol to buffer the packet internally until
+ it has all been received. QPacketProtocol does not perform any sanity
+ checking on the size or on the data, so this class should only be used in
+ prototyping or trusted situations where DOS attacks are unlikely.
+
+ QPacketProtocol does not perform any communications itself. Instead it can
+ operate on any QIODevice that supports the QIODevice::readyRead() signal. A
+ logical "packet" is encapsulated by the companion QPacket class. The
+ following example shows two ways to send data using QPacketProtocol. The
+ transmitted data is equivalent in both.
+
+ \code
+ QTcpSocket socket;
+ // ... connect socket ...
+
+ QPacketProtocol protocol(&socket);
+
+ // Send packet the quick way
+ protocol.send() << "Hello world" << 123;
+
+ // Send packet the longer way
+ QPacket packet;
+ packet << "Hello world" << 123;
+ protocol.send(packet);
+ \endcode
+
+ Likewise, the following shows how to read data from QPacketProtocol, assuming
+ that the QPacketProtocol::readyRead() signal has been emitted.
+
+ \code
+ // ... QPacketProtocol::readyRead() is emitted ...
+
+ int a;
+ QByteArray b;
+
+ // Receive packet the quick way
+ protocol.read() >> a >> b;
+
+ // Receive packet the longer way
+ QPacket packet = protocol.read();
+ p >> a >> b;
+ \endcode
+
+ \ingroup io
+ \sa QPacket
+*/
+
+class QPacketProtocolPrivate : public QObject
+{
+ Q_OBJECT
+public:
+ QPacketProtocolPrivate(QPacketProtocol *parent, QIODevice *_dev)
+ : QObject(parent), inProgressSize(-1), maxPacketSize(MAX_PACKET_SIZE),
+ waitingForPacket(false), dev(_dev)
+ {
+ Q_ASSERT(4 == sizeof(qint32));
+
+ QObject::connect(this, SIGNAL(readyRead()),
+ parent, SIGNAL(readyRead()));
+ QObject::connect(this, SIGNAL(packetWritten()),
+ parent, SIGNAL(packetWritten()));
+ QObject::connect(this, SIGNAL(invalidPacket()),
+ parent, SIGNAL(invalidPacket()));
+ QObject::connect(dev, SIGNAL(readyRead()),
+ this, SLOT(readyToRead()));
+ QObject::connect(dev, SIGNAL(aboutToClose()),
+ this, SLOT(aboutToClose()));
+ QObject::connect(dev, SIGNAL(bytesWritten(qint64)),
+ this, SLOT(bytesWritten(qint64)));
+ }
+
+Q_SIGNALS:
+ void readyRead();
+ void packetWritten();
+ void invalidPacket();
+
+public Q_SLOTS:
+ void aboutToClose()
+ {
+ inProgress.clear();
+ sendingPackets.clear();
+ inProgressSize = -1;
+ }
+
+ void bytesWritten(qint64 bytes)
+ {
+ Q_ASSERT(!sendingPackets.isEmpty());
+
+ while (bytes) {
+ if (sendingPackets.at(0) > bytes) {
+ sendingPackets[0] -= bytes;
+ bytes = 0;
+ } else {
+ bytes -= sendingPackets.at(0);
+ sendingPackets.removeFirst();
+ emit packetWritten();
+ }
+ }
+ }
+
+ void readyToRead()
+ {
+ while (true) {
+ // Need to get trailing data
+ if (-1 == inProgressSize) {
+ // We need a size header of sizeof(qint32)
+ if (sizeof(qint32) > (uint)dev->bytesAvailable())
+ return;
+
+ // Read size header
+ int read = dev->read((char *)&inProgressSize, sizeof(qint32));
+ Q_ASSERT(read == sizeof(qint32));
+ Q_UNUSED(read);
+
+ // Check sizing constraints
+ if (inProgressSize > maxPacketSize) {
+ QObject::disconnect(dev, SIGNAL(readyRead()),
+ this, SLOT(readyToRead()));
+ QObject::disconnect(dev, SIGNAL(aboutToClose()),
+ this, SLOT(aboutToClose()));
+ QObject::disconnect(dev, SIGNAL(bytesWritten(qint64)),
+ this, SLOT(bytesWritten(qint64)));
+ dev = 0;
+ emit invalidPacket();
+ return;
+ }
+
+ inProgressSize -= sizeof(qint32);
+ } else {
+ inProgress.append(dev->read(inProgressSize - inProgress.size()));
+
+ if (inProgressSize == inProgress.size()) {
+ // Packet has arrived!
+ packets.append(inProgress);
+ inProgressSize = -1;
+ inProgress.clear();
+
+ waitingForPacket = false;
+ emit readyRead();
+ } else
+ return;
+ }
+ }
+ }
+
+public:
+ QList<qint64> sendingPackets;
+ QList<QByteArray> packets;
+ QByteArray inProgress;
+ qint32 inProgressSize;
+ qint32 maxPacketSize;
+ bool waitingForPacket;
+ QIODevice *dev;
+};
+
+/*!
+ Construct a QPacketProtocol instance that works on \a dev with the
+ specified \a parent.
+ */
+QPacketProtocol::QPacketProtocol(QIODevice *dev, QObject *parent)
+ : QObject(parent), d(new QPacketProtocolPrivate(this, dev))
+{
+ Q_ASSERT(dev);
+}
+
+/*!
+ Destroys the QPacketProtocol instance.
+ */
+QPacketProtocol::~QPacketProtocol()
+{
+}
+
+/*!
+ Returns the maximum packet size allowed. By default this is
+ 2,147,483,647 bytes.
+
+ If a packet claiming to be larger than the maximum packet size is received,
+ the QPacketProtocol::invalidPacket() signal is emitted.
+
+ \sa QPacketProtocol::setMaximumPacketSize()
+ */
+qint32 QPacketProtocol::maximumPacketSize() const
+{
+ return d->maxPacketSize;
+}
+
+/*!
+ Sets the maximum allowable packet size to \a max.
+
+ \sa QPacketProtocol::maximumPacketSize()
+ */
+qint32 QPacketProtocol::setMaximumPacketSize(qint32 max)
+{
+ if (max > (signed)sizeof(qint32))
+ d->maxPacketSize = max;
+ return d->maxPacketSize;
+}
+
+/*!
+ Returns a streamable object that is transmitted on destruction. For example
+
+ \code
+ protocol.send() << "Hello world" << 123;
+ \endcode
+
+ will send a packet containing "Hello world" and 123. To construct more
+ complex packets, explicitly construct a QPacket instance.
+ */
+QPacketAutoSend QPacketProtocol::send()
+{
+ return QPacketAutoSend(this);
+}
+
+/*!
+ \fn void QPacketProtocol::send(const QPacket & packet)
+
+ Transmit the \a packet.
+ */
+void QPacketProtocol::send(const QPacket & p)
+{
+ if (p.b.isEmpty())
+ return; // We don't send empty packets
+
+ qint64 sendSize = p.b.size() + sizeof(qint32);
+
+ d->sendingPackets.append(sendSize);
+ qint32 sendSize32 = sendSize;
+ qint64 writeBytes = d->dev->write((char *)&sendSize32, sizeof(qint32));
+ Q_ASSERT(writeBytes == sizeof(qint32));
+ writeBytes = d->dev->write(p.b);
+ Q_ASSERT(writeBytes == p.b.size());
+}
+
+/*!
+ Returns the number of received packets yet to be read.
+ */
+qint64 QPacketProtocol::packetsAvailable() const
+{
+ return d->packets.count();
+}
+
+/*!
+ Discard any unread packets.
+ */
+void QPacketProtocol::clear()
+{
+ d->packets.clear();
+}
+
+/*!
+ Return the next unread packet, or an invalid QPacket instance if no packets
+ are available. This method does NOT block.
+ */
+QPacket QPacketProtocol::read()
+{
+ if (0 == d->packets.count())
+ return QPacket();
+
+ QPacket rv(d->packets.at(0));
+ d->packets.removeFirst();
+ return rv;
+}
+
+/*
+ Returns the difference between msecs and elapsed. If msecs is -1,
+ however, -1 is returned.
+*/
+static int qt_timeout_value(int msecs, int elapsed)
+{
+ if (msecs == -1)
+ return -1;
+
+ int timeout = msecs - elapsed;
+ return timeout < 0 ? 0 : timeout;
+}
+
+/*!
+ This function locks until a new packet is available for reading and the
+ \l{QIODevice::}{readyRead()} signal has been emitted. The function
+ will timeout after \a msecs milliseconds; the default timeout is
+ 30000 milliseconds.
+
+ The function returns true if the readyRead() signal is emitted and
+ there is new data available for reading; otherwise it returns false
+ (if an error occurred or the operation timed out).
+ */
+
+bool QPacketProtocol::waitForReadyRead(int msecs)
+{
+ if (!d->packets.isEmpty())
+ return true;
+
+ QElapsedTimer stopWatch;
+ stopWatch.start();
+
+ d->waitingForPacket = true;
+ do {
+ if (!d->dev->waitForReadyRead(msecs))
+ return false;
+ if (!d->waitingForPacket)
+ return true;
+ msecs = qt_timeout_value(msecs, stopWatch.elapsed());
+ } while (true);
+}
+
+/*!
+ Return the QIODevice passed to the QPacketProtocol constructor.
+*/
+QIODevice *QPacketProtocol::device()
+{
+ return d->dev;
+}
+
+/*!
+ \fn void QPacketProtocol::readyRead()
+
+ Emitted whenever a new packet is received. Applications may use
+ QPacketProtocol::read() to retrieve this packet.
+ */
+
+/*!
+ \fn void QPacketProtocol::invalidPacket()
+
+ A packet larger than the maximum allowable packet size was received. The
+ packet will be discarded and, as it indicates corruption in the protocol, no
+ further packets will be received.
+ */
+
+/*!
+ \fn void QPacketProtocol::packetWritten()
+
+ Emitted each time a packet is completing written to the device. This signal
+ may be used for communications flow control.
+ */
+
+/*!
+ \class QPacket
+ \internal
+
+ \brief The QPacket class encapsulates an unfragmentable packet of data to be
+ transmitted by QPacketProtocol.
+
+ The QPacket class works together with QPacketProtocol to make it simple to
+ send arbitrary sized data "packets" across fragmented transports such as TCP
+ and UDP.
+
+ QPacket provides a QDataStream interface to an unfragmentable packet.
+ Applications should construct a QPacket, propagate it with data and then
+ transmit it over a QPacketProtocol instance. For example:
+ \code
+ QPacketProtocol protocol(...);
+
+ QPacket myPacket;
+ myPacket << "Hello world!" << 123;
+ protocol.send(myPacket);
+ \endcode
+
+ As long as both ends of the connection are using the QPacketProtocol class,
+ the data within this packet will be delivered unfragmented at the other end,
+ ready for extraction.
+
+ \code
+ QByteArray greeting;
+ int count;
+
+ QPacket myPacket = protocol.read();
+
+ myPacket >> greeting >> count;
+ \endcode
+
+ Only packets returned from QPacketProtocol::read() may be read from. QPacket
+ instances constructed by directly by applications are for transmission only
+ and are considered "write only". Attempting to read data from them will
+ result in undefined behavior.
+
+ \ingroup io
+ \sa QPacketProtocol
+ */
+
+/*!
+ Constructs an empty write-only packet.
+ */
+QPacket::QPacket()
+ : QDataStream(), buf(0)
+{
+ buf = new QBuffer(&b);
+ buf->open(QIODevice::WriteOnly);
+ setDevice(buf);
+ setVersion(QDataStream::Qt_4_7);
+}
+
+/*!
+ Destroys the QPacket instance.
+ */
+QPacket::~QPacket()
+{
+ if (buf) {
+ delete buf;
+ buf = 0;
+ }
+}
+
+/*!
+ Creates a copy of \a other. The initial stream positions are shared, but the
+ two packets are otherwise independent.
+ */
+QPacket::QPacket(const QPacket & other)
+ : QDataStream(), b(other.b), buf(0)
+{
+ buf = new QBuffer(&b);
+ buf->open(other.buf->openMode());
+ setDevice(buf);
+}
+
+/*!
+ \internal
+ */
+QPacket::QPacket(const QByteArray & ba)
+ : QDataStream(), b(ba), buf(0)
+{
+ buf = new QBuffer(&b);
+ buf->open(QIODevice::ReadOnly);
+ setDevice(buf);
+}
+
+/*!
+ Returns true if this packet is empty - that is, contains no data.
+ */
+bool QPacket::isEmpty() const
+{
+ return b.isEmpty();
+}
+
+/*!
+ Returns raw packet data.
+ */
+QByteArray QPacket::data() const
+{
+ return b;
+}
+
+/*!
+ Clears data in the packet. This is useful for reusing one writable packet.
+ For example
+ \code
+ QPacketProtocol protocol(...);
+
+ QPacket packet;
+
+ packet << "Hello world!" << 123;
+ protocol.send(packet);
+
+ packet.clear();
+ packet << "Goodbyte world!" << 789;
+ protocol.send(packet);
+ \endcode
+ */
+void QPacket::clear()
+{
+ QBuffer::OpenMode oldMode = buf->openMode();
+ buf->close();
+ b.clear();
+ buf->setBuffer(&b); // reset QBuffer internals with new size of b.
+ buf->open(oldMode);
+}
+
+/*!
+ \class QPacketAutoSend
+ \internal
+
+ \internal
+ */
+QPacketAutoSend::QPacketAutoSend(QPacketProtocol *_p)
+ : QPacket(), p(_p)
+{
+}
+
+QPacketAutoSend::~QPacketAutoSend()
+{
+ if (!b.isEmpty())
+ p->send(*this);
+}
+
+QT_END_NAMESPACE
+
+#include <qpacketprotocol.moc>
diff --git a/src/qml/debugger/qpacketprotocol_p.h b/src/qml/debugger/qpacketprotocol_p.h
new file mode 100644
index 0000000000..c6123d2836
--- /dev/null
+++ b/src/qml/debugger/qpacketprotocol_p.h
@@ -0,0 +1,137 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QPACKETPROTOCOL_H
+#define QPACKETPROTOCOL_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qobject.h>
+#include <QtCore/qdatastream.h>
+
+#include <private/qtqmlglobal_p.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+
+class QIODevice;
+class QBuffer;
+class QPacket;
+class QPacketAutoSend;
+class QPacketProtocolPrivate;
+
+class Q_QML_PRIVATE_EXPORT QPacketProtocol : public QObject
+{
+ Q_OBJECT
+public:
+ explicit QPacketProtocol(QIODevice *dev, QObject *parent = 0);
+ virtual ~QPacketProtocol();
+
+ qint32 maximumPacketSize() const;
+ qint32 setMaximumPacketSize(qint32);
+
+ QPacketAutoSend send();
+ void send(const QPacket &);
+
+ qint64 packetsAvailable() const;
+ QPacket read();
+
+ bool waitForReadyRead(int msecs = 3000);
+
+ void clear();
+
+ QIODevice *device();
+
+Q_SIGNALS:
+ void readyRead();
+ void invalidPacket();
+ void packetWritten();
+
+private:
+ QPacketProtocolPrivate *d;
+};
+
+
+class Q_QML_PRIVATE_EXPORT QPacket : public QDataStream
+{
+public:
+ QPacket();
+ QPacket(const QPacket &);
+ virtual ~QPacket();
+
+ void clear();
+ bool isEmpty() const;
+ QByteArray data() const;
+
+protected:
+ friend class QPacketProtocol;
+ QPacket(const QByteArray &ba);
+ QByteArray b;
+ QBuffer *buf;
+};
+
+class Q_QML_PRIVATE_EXPORT QPacketAutoSend : public QPacket
+{
+public:
+ virtual ~QPacketAutoSend();
+
+private:
+ friend class QPacketProtocol;
+ QPacketAutoSend(QPacketProtocol *);
+ QPacketProtocol *p;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/qml/debugger/qqmldebug.h b/src/qml/debugger/qqmldebug.h
new file mode 100644
index 0000000000..8036032150
--- /dev/null
+++ b/src/qml/debugger/qqmldebug.h
@@ -0,0 +1,66 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLDEBUG_H
+#define QQMLDEBUG_H
+
+#include <QtQml/qtqmlglobal.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+
+struct Q_QML_EXPORT QQmlDebuggingEnabler
+{
+ QQmlDebuggingEnabler();
+};
+
+// Execute code in constructor before first QQmlEngine is instantiated
+#if defined(QT_DECLARATIVE_DEBUG)
+static QQmlDebuggingEnabler qmlEnableDebuggingHelper;
+#endif
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QQMLDEBUG_H
diff --git a/src/qml/debugger/qqmldebugclient.cpp b/src/qml/debugger/qqmldebugclient.cpp
new file mode 100644
index 0000000000..12276b48fa
--- /dev/null
+++ b/src/qml/debugger/qqmldebugclient.cpp
@@ -0,0 +1,421 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qqmldebugclient_p.h"
+
+#include "qpacketprotocol_p.h"
+
+#include <QtCore/qdebug.h>
+#include <QtCore/qstringlist.h>
+#include <QtNetwork/qnetworkproxy.h>
+
+#include <private/qobject_p.h>
+
+QT_BEGIN_NAMESPACE
+
+const int protocolVersion = 1;
+const QString serverId = QLatin1String("QQmlDebugServer");
+const QString clientId = QLatin1String("QQmlDebugClient");
+
+class QQmlDebugClientPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QQmlDebugClient)
+public:
+ QQmlDebugClientPrivate();
+
+ QString name;
+ QQmlDebugConnection *connection;
+};
+
+class QQmlDebugConnectionPrivate : public QObject
+{
+ Q_OBJECT
+public:
+ QQmlDebugConnectionPrivate(QQmlDebugConnection *c);
+ QQmlDebugConnection *q;
+ QPacketProtocol *protocol;
+ QIODevice *device;
+
+ bool gotHello;
+ QHash <QString, float> serverPlugins;
+ QHash<QString, QQmlDebugClient *> plugins;
+
+ void advertisePlugins();
+ void connectDeviceSignals();
+
+public Q_SLOTS:
+ void connected();
+ void readyRead();
+ void deviceAboutToClose();
+};
+
+QQmlDebugConnectionPrivate::QQmlDebugConnectionPrivate(QQmlDebugConnection *c)
+ : QObject(c), q(c), protocol(0), device(0), gotHello(false)
+{
+ protocol = new QPacketProtocol(q, this);
+ QObject::connect(c, SIGNAL(connected()), this, SLOT(connected()));
+ QObject::connect(protocol, SIGNAL(readyRead()), this, SLOT(readyRead()));
+}
+
+void QQmlDebugConnectionPrivate::advertisePlugins()
+{
+ if (!q->isConnected())
+ return;
+
+ QPacket pack;
+ pack << serverId << 1 << plugins.keys();
+ protocol->send(pack);
+ q->flush();
+}
+
+void QQmlDebugConnectionPrivate::connected()
+{
+ QPacket pack;
+ pack << serverId << 0 << protocolVersion << plugins.keys();
+ protocol->send(pack);
+ q->flush();
+}
+
+void QQmlDebugConnectionPrivate::readyRead()
+{
+ if (!gotHello) {
+ QPacket pack = protocol->read();
+ QString name;
+
+ pack >> name;
+
+ bool validHello = false;
+ if (name == clientId) {
+ int op = -1;
+ pack >> op;
+ if (op == 0) {
+ int version = -1;
+ pack >> version;
+ if (version == protocolVersion) {
+ QStringList pluginNames;
+ QList<float> pluginVersions;
+ pack >> pluginNames;
+ if (!pack.isEmpty())
+ pack >> pluginVersions;
+
+ const int pluginNamesSize = pluginNames.size();
+ const int pluginVersionsSize = pluginVersions.size();
+ for (int i = 0; i < pluginNamesSize; ++i) {
+ float pluginVersion = 1.0;
+ if (i < pluginVersionsSize)
+ pluginVersion = pluginVersions.at(i);
+ serverPlugins.insert(pluginNames.at(i), pluginVersion);
+ }
+
+ validHello = true;
+ }
+ }
+ }
+
+ if (!validHello) {
+ qWarning("QQmlDebugConnection: Invalid hello message");
+ QObject::disconnect(protocol, SIGNAL(readyRead()), this, SLOT(readyRead()));
+ return;
+ }
+ gotHello = true;
+
+ QHash<QString, QQmlDebugClient *>::Iterator iter = plugins.begin();
+ for (; iter != plugins.end(); ++iter) {
+ QQmlDebugClient::State newState = QQmlDebugClient::Unavailable;
+ if (serverPlugins.contains(iter.key()))
+ newState = QQmlDebugClient::Enabled;
+ iter.value()->stateChanged(newState);
+ }
+ }
+
+ while (protocol->packetsAvailable()) {
+ QPacket pack = protocol->read();
+ QString name;
+ pack >> name;
+
+ if (name == clientId) {
+ int op = -1;
+ pack >> op;
+
+ if (op == 1) {
+ // Service Discovery
+ QHash<QString, float> oldServerPlugins = serverPlugins;
+ serverPlugins.clear();
+
+ QStringList pluginNames;
+ QList<float> pluginVersions;
+ pack >> pluginNames;
+ if (!pack.isEmpty())
+ pack >> pluginVersions;
+
+ const int pluginNamesSize = pluginNames.size();
+ const int pluginVersionsSize = pluginVersions.size();
+ for (int i = 0; i < pluginNamesSize; ++i) {
+ float pluginVersion = 1.0;
+ if (i < pluginVersionsSize)
+ pluginVersion = pluginVersions.at(i);
+ serverPlugins.insert(pluginNames.at(i), pluginVersion);
+ }
+
+ QHash<QString, QQmlDebugClient *>::Iterator iter = plugins.begin();
+ for (; iter != plugins.end(); ++iter) {
+ const QString pluginName = iter.key();
+ QQmlDebugClient::State newSate = QQmlDebugClient::Unavailable;
+ if (serverPlugins.contains(pluginName))
+ newSate = QQmlDebugClient::Enabled;
+
+ if (oldServerPlugins.contains(pluginName)
+ != serverPlugins.contains(pluginName)) {
+ iter.value()->stateChanged(newSate);
+ }
+ }
+ } else {
+ qWarning() << "QQmlDebugConnection: Unknown control message id" << op;
+ }
+ } else {
+ QByteArray message;
+ pack >> message;
+
+ QHash<QString, QQmlDebugClient *>::Iterator iter =
+ plugins.find(name);
+ if (iter == plugins.end()) {
+ qWarning() << "QQmlDebugConnection: Message received for missing plugin" << name;
+ } else {
+ (*iter)->messageReceived(message);
+ }
+ }
+ }
+}
+
+void QQmlDebugConnectionPrivate::deviceAboutToClose()
+{
+ // This is nasty syntax but we want to emit our own aboutToClose signal (by calling QIODevice::close())
+ // without calling the underlying device close fn as that would cause an infinite loop
+ q->QIODevice::close();
+}
+
+QQmlDebugConnection::QQmlDebugConnection(QObject *parent)
+ : QIODevice(parent), d(new QQmlDebugConnectionPrivate(this))
+{
+}
+
+QQmlDebugConnection::~QQmlDebugConnection()
+{
+ QHash<QString, QQmlDebugClient*>::iterator iter = d->plugins.begin();
+ for (; iter != d->plugins.end(); ++iter) {
+ iter.value()->d_func()->connection = 0;
+ iter.value()->stateChanged(QQmlDebugClient::NotConnected);
+ }
+}
+
+bool QQmlDebugConnection::isConnected() const
+{
+ return state() == QAbstractSocket::ConnectedState;
+}
+
+qint64 QQmlDebugConnection::readData(char *data, qint64 maxSize)
+{
+ return d->device->read(data, maxSize);
+}
+
+qint64 QQmlDebugConnection::writeData(const char *data, qint64 maxSize)
+{
+ return d->device->write(data, maxSize);
+}
+
+qint64 QQmlDebugConnection::bytesAvailable() const
+{
+ return d->device->bytesAvailable();
+}
+
+bool QQmlDebugConnection::isSequential() const
+{
+ return true;
+}
+
+void QQmlDebugConnection::close()
+{
+ if (isOpen()) {
+ QIODevice::close();
+ d->device->close();
+ emit stateChanged(QAbstractSocket::UnconnectedState);
+
+ QHash<QString, QQmlDebugClient*>::iterator iter = d->plugins.begin();
+ for (; iter != d->plugins.end(); ++iter) {
+ iter.value()->stateChanged(QQmlDebugClient::NotConnected);
+ }
+ }
+}
+
+bool QQmlDebugConnection::waitForConnected(int msecs)
+{
+ QAbstractSocket *socket = qobject_cast<QAbstractSocket*>(d->device);
+ if (socket)
+ return socket->waitForConnected(msecs);
+ return false;
+}
+
+QAbstractSocket::SocketState QQmlDebugConnection::state() const
+{
+ QAbstractSocket *socket = qobject_cast<QAbstractSocket*>(d->device);
+ if (socket)
+ return socket->state();
+
+ return QAbstractSocket::UnconnectedState;
+}
+
+void QQmlDebugConnection::flush()
+{
+ QAbstractSocket *socket = qobject_cast<QAbstractSocket*>(d->device);
+ if (socket) {
+ socket->flush();
+ return;
+ }
+}
+
+void QQmlDebugConnection::connectToHost(const QString &hostName, quint16 port)
+{
+ QTcpSocket *socket = new QTcpSocket(d);
+ socket->setProxy(QNetworkProxy::NoProxy);
+ d->device = socket;
+ d->connectDeviceSignals();
+ d->gotHello = false;
+ connect(socket, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SIGNAL(stateChanged(QAbstractSocket::SocketState)));
+ connect(socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SIGNAL(error(QAbstractSocket::SocketError)));
+ connect(socket, SIGNAL(connected()), this, SIGNAL(connected()));
+ socket->connectToHost(hostName, port);
+ QIODevice::open(ReadWrite | Unbuffered);
+}
+
+void QQmlDebugConnectionPrivate::connectDeviceSignals()
+{
+ connect(device, SIGNAL(bytesWritten(qint64)), q, SIGNAL(bytesWritten(qint64)));
+ connect(device, SIGNAL(readyRead()), q, SIGNAL(readyRead()));
+ connect(device, SIGNAL(aboutToClose()), this, SLOT(deviceAboutToClose()));
+}
+
+//
+
+QQmlDebugClientPrivate::QQmlDebugClientPrivate()
+ : connection(0)
+{
+}
+
+QQmlDebugClient::QQmlDebugClient(const QString &name,
+ QQmlDebugConnection *parent)
+ : QObject(*(new QQmlDebugClientPrivate), parent)
+{
+ Q_D(QQmlDebugClient);
+ d->name = name;
+ d->connection = parent;
+
+ if (!d->connection)
+ return;
+
+ if (d->connection->d->plugins.contains(name)) {
+ qWarning() << "QQmlDebugClient: Conflicting plugin name" << name;
+ d->connection = 0;
+ } else {
+ d->connection->d->plugins.insert(name, this);
+ d->connection->d->advertisePlugins();
+ }
+}
+
+QQmlDebugClient::~QQmlDebugClient()
+{
+ Q_D(QQmlDebugClient);
+ if (d->connection && d->connection->d) {
+ d->connection->d->plugins.remove(d->name);
+ d->connection->d->advertisePlugins();
+ }
+}
+
+QString QQmlDebugClient::name() const
+{
+ Q_D(const QQmlDebugClient);
+ return d->name;
+}
+
+float QQmlDebugClient::serviceVersion() const
+{
+ Q_D(const QQmlDebugClient);
+ if (d->connection->d->serverPlugins.contains(d->name))
+ return d->connection->d->serverPlugins.value(d->name);
+ return -1;
+}
+
+QQmlDebugClient::State QQmlDebugClient::state() const
+{
+ Q_D(const QQmlDebugClient);
+ if (!d->connection
+ || !d->connection->isConnected()
+ || !d->connection->d->gotHello)
+ return NotConnected;
+
+ if (d->connection->d->serverPlugins.contains(d->name))
+ return Enabled;
+
+ return Unavailable;
+}
+
+void QQmlDebugClient::sendMessage(const QByteArray &message)
+{
+ Q_D(QQmlDebugClient);
+ if (state() != Enabled)
+ return;
+
+ QPacket pack;
+ pack << d->name << message;
+ d->connection->d->protocol->send(pack);
+ d->connection->flush();
+}
+
+void QQmlDebugClient::stateChanged(State)
+{
+}
+
+void QQmlDebugClient::messageReceived(const QByteArray &)
+{
+}
+
+QT_END_NAMESPACE
+
+#include <qqmldebugclient.moc>
diff --git a/src/qml/debugger/qqmldebugclient_p.h b/src/qml/debugger/qqmldebugclient_p.h
new file mode 100644
index 0000000000..064e15cf49
--- /dev/null
+++ b/src/qml/debugger/qqmldebugclient_p.h
@@ -0,0 +1,131 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLDEBUGCLIENT_H
+#define QQMLDEBUGCLIENT_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 <QtNetwork/qtcpsocket.h>
+
+#include <private/qtqmlglobal_p.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+
+class QQmlDebugConnectionPrivate;
+class Q_QML_PRIVATE_EXPORT QQmlDebugConnection : public QIODevice
+{
+ Q_OBJECT
+ Q_DISABLE_COPY(QQmlDebugConnection)
+public:
+ QQmlDebugConnection(QObject * = 0);
+ ~QQmlDebugConnection();
+
+ void connectToHost(const QString &hostName, quint16 port);
+
+ qint64 bytesAvailable() const;
+ bool isConnected() const;
+ QAbstractSocket::SocketState state() const;
+ void flush();
+ bool isSequential() const;
+ void close();
+ bool waitForConnected(int msecs = 30000);
+
+signals:
+ void connected();
+ void stateChanged(QAbstractSocket::SocketState socketState);
+ void error(QAbstractSocket::SocketError socketError);
+
+protected:
+ qint64 readData(char *data, qint64 maxSize);
+ qint64 writeData(const char *data, qint64 maxSize);
+
+private:
+ QQmlDebugConnectionPrivate *d;
+ friend class QQmlDebugClient;
+ friend class QQmlDebugClientPrivate;
+};
+
+class QQmlDebugClientPrivate;
+class Q_QML_PRIVATE_EXPORT QQmlDebugClient : public QObject
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QQmlDebugClient)
+ Q_DISABLE_COPY(QQmlDebugClient)
+
+public:
+ enum State { NotConnected, Unavailable, Enabled };
+
+ QQmlDebugClient(const QString &, QQmlDebugConnection *parent);
+ ~QQmlDebugClient();
+
+ QString name() const;
+ float serviceVersion() const;
+ State state() const;
+
+ virtual void sendMessage(const QByteArray &);
+
+protected:
+ virtual void stateChanged(State);
+ virtual void messageReceived(const QByteArray &);
+
+private:
+ friend class QQmlDebugConnection;
+ friend class QQmlDebugConnectionPrivate;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QQMLDEBUGCLIENT_H
diff --git a/src/qml/debugger/qqmldebughelper.cpp b/src/qml/debugger/qqmldebughelper.cpp
new file mode 100644
index 0000000000..7158b3609d
--- /dev/null
+++ b/src/qml/debugger/qqmldebughelper.cpp
@@ -0,0 +1,70 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qqmldebughelper_p.h"
+
+#include <QtCore/QAbstractAnimation>
+#include <QtQml/QJSEngine>
+
+#include <private/qqmlengine_p.h>
+#include <private/qabstractanimation_p.h>
+#include <private/qqmlengine_p.h>
+
+QT_BEGIN_NAMESPACE
+
+void QQmlDebugHelper::setAnimationSlowDownFactor(qreal factor)
+{
+ QUnifiedTimer *timer = QUnifiedTimer::instance();
+ timer->setSlowModeEnabled(factor != 1.0);
+ timer->setSlowdownFactor(factor);
+}
+
+void QQmlDebugHelper::enableDebugging() {
+ qWarning("QQmlDebugHelper::enableDebugging() is deprecated! Add CONFIG += declarative_debug to your .pro file instead.");
+#ifndef QQML_NO_DEBUG_PROTOCOL
+ if (!QQmlEnginePrivate::qml_debugging_enabled) {
+ qWarning("Qml debugging is enabled. Only use this in a safe environment!");
+ }
+ QQmlEnginePrivate::qml_debugging_enabled = true;
+#endif
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/debugger/qqmldebughelper_p.h b/src/qml/debugger/qqmldebughelper_p.h
new file mode 100644
index 0000000000..5d2bcc2be0
--- /dev/null
+++ b/src/qml/debugger/qqmldebughelper_p.h
@@ -0,0 +1,84 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLDEBUGHELPER_P_H
+#define QQMLDEBUGHELPER_P_H
+
+#include <private/qtqmlglobal_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.
+//
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class QQmlEngine;
+
+#ifndef QT_BUILD_QML_LIB
+#warning Use of this header file is deprecated! Add CONFIG += declarative_debug to your .pro file instead.
+#endif
+
+// Helper methods to access private API through a stable interface
+// This is used in the qmljsdebugger library of QtCreator.
+class Q_QML_EXPORT QQmlDebugHelper
+{
+public:
+ static void setAnimationSlowDownFactor(qreal factor);
+
+ // Enables remote debugging functionality
+ // Only use this for debugging in a safe environment!
+ static void enableDebugging();
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QQMLDEBUGHELPER_P_H
diff --git a/src/qml/debugger/qqmldebugserver.cpp b/src/qml/debugger/qqmldebugserver.cpp
new file mode 100644
index 0000000000..8d5c597a78
--- /dev/null
+++ b/src/qml/debugger/qqmldebugserver.cpp
@@ -0,0 +1,540 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qqmldebugserver_p.h"
+#include "qqmldebugservice_p.h"
+#include "qqmldebugservice_p_p.h"
+#include <private/qqmlengine_p.h>
+#include <private/qqmlglobal_p.h>
+
+#include <QtCore/QDir>
+#include <QtCore/QPluginLoader>
+#include <QtCore/QStringList>
+#include <QtCore/qwaitcondition.h>
+
+#include <private/qobject_p.h>
+#include <private/qcoreapplication_p.h>
+
+QT_BEGIN_NAMESPACE
+
+/*
+ QQmlDebug Protocol (Version 1):
+
+ handshake:
+ 1. Client sends
+ "QQmlDebugServer" 0 version pluginNames
+ version: an int representing the highest protocol version the client knows
+ pluginNames: plugins available on client side
+ 2. Server sends
+ "QQmlDebugClient" 0 version pluginNames pluginVersions
+ version: an int representing the highest protocol version the client & server know
+ pluginNames: plugins available on server side. plugins both in the client and server message are enabled.
+ client plugin advertisement
+ 1. Client sends
+ "QQmlDebugServer" 1 pluginNames
+ server plugin advertisement
+ 1. Server sends
+ "QQmlDebugClient" 1 pluginNames pluginVersions
+ plugin communication:
+ Everything send with a header different to "QQmlDebugServer" is sent to the appropriate plugin.
+ */
+
+const int protocolVersion = 1;
+
+// print detailed information about loading of plugins
+DEFINE_BOOL_CONFIG_OPTION(qmlDebugVerbose, QML_DEBUGGER_VERBOSE)
+
+class QQmlDebugServerThread;
+
+class QQmlDebugServerPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QQmlDebugServer)
+public:
+ QQmlDebugServerPrivate();
+
+ void advertisePlugins();
+ QQmlDebugServerConnection *loadConnectionPlugin(const QString &pluginName);
+
+ QQmlDebugServerConnection *connection;
+ QHash<QString, QQmlDebugService *> plugins;
+ mutable QReadWriteLock pluginsLock;
+ QStringList clientPlugins;
+ bool gotHello;
+
+ QMutex messageArrivedMutex;
+ QWaitCondition messageArrivedCondition;
+ QStringList waitingForMessageNames;
+ QQmlDebugServerThread *thread;
+ QPluginLoader loader;
+
+private:
+ // private slot
+ void _q_sendMessages(const QList<QByteArray> &messages);
+};
+
+class QQmlDebugServerThread : public QThread
+{
+public:
+ void setPluginName(const QString &pluginName) {
+ m_pluginName = pluginName;
+ }
+
+ void setPort(int port, bool block) {
+ m_port = port;
+ m_block = block;
+ }
+
+ void run();
+
+private:
+ QString m_pluginName;
+ int m_port;
+ bool m_block;
+};
+
+QQmlDebugServerPrivate::QQmlDebugServerPrivate() :
+ connection(0),
+ gotHello(false),
+ thread(0)
+{
+ // used in _q_sendMessages
+ qRegisterMetaType<QList<QByteArray> >("QList<QByteArray>");
+}
+
+void QQmlDebugServerPrivate::advertisePlugins()
+{
+ Q_Q(QQmlDebugServer);
+
+ if (!gotHello)
+ return;
+
+ QByteArray message;
+ {
+ QDataStream out(&message, QIODevice::WriteOnly);
+ QStringList pluginNames;
+ QList<float> pluginVersions;
+ foreach (QQmlDebugService *service, plugins.values()) {
+ pluginNames << service->name();
+ pluginVersions << service->version();
+ }
+ out << QString(QLatin1String("QQmlDebugClient")) << 1 << pluginNames << pluginVersions;
+ }
+
+ QMetaObject::invokeMethod(q, "_q_sendMessages", Qt::QueuedConnection, Q_ARG(QList<QByteArray>, QList<QByteArray>() << message));
+}
+
+QQmlDebugServerConnection *QQmlDebugServerPrivate::loadConnectionPlugin(
+ const QString &pluginName)
+{
+#ifndef QT_NO_LIBRARY
+ QStringList pluginCandidates;
+ const QStringList paths = QCoreApplication::libraryPaths();
+ foreach (const QString &libPath, paths) {
+ const QDir dir(libPath + QLatin1String("/qmltooling"));
+ if (dir.exists()) {
+ QStringList plugins(dir.entryList(QDir::Files));
+ foreach (const QString &pluginPath, plugins) {
+ if (QFileInfo(pluginPath).fileName().contains(pluginName))
+ pluginCandidates << dir.absoluteFilePath(pluginPath);
+ }
+ }
+ }
+
+ foreach (const QString &pluginPath, pluginCandidates) {
+ if (qmlDebugVerbose())
+ qDebug() << "QQmlDebugServer: Trying to load plugin " << pluginPath << "...";
+
+ loader.setFileName(pluginPath);
+ if (!loader.load()) {
+ if (qmlDebugVerbose())
+ qDebug() << "QQmlDebugServer: Error while loading: " << loader.errorString();
+ continue;
+ }
+ if (QObject *instance = loader.instance())
+ connection = qobject_cast<QQmlDebugServerConnection*>(instance);
+
+ if (connection) {
+ if (qmlDebugVerbose())
+ qDebug() << "QQmlDebugServer: Plugin successfully loaded.";
+
+ return connection;
+ }
+
+ if (qmlDebugVerbose())
+ qDebug() << "QQmlDebugServer: Plugin does not implement interface QQmlDebugServerConnection.";
+
+ loader.unload();
+ }
+#endif
+ return 0;
+}
+
+void QQmlDebugServerThread::run()
+{
+ QQmlDebugServer *server = QQmlDebugServer::instance();
+ QQmlDebugServerConnection *connection
+ = server->d_func()->loadConnectionPlugin(m_pluginName);
+ if (connection) {
+ connection->setServer(QQmlDebugServer::instance());
+ connection->setPort(m_port, m_block);
+ } else {
+ QCoreApplicationPrivate *appD = static_cast<QCoreApplicationPrivate*>(QObjectPrivate::get(qApp));
+ qWarning() << QString::fromAscii("QQmlDebugServer: Ignoring \"-qmljsdebugger=%1\". "
+ "Remote debugger plugin has not been found.").arg(appD->qmljsDebugArgumentsString());
+ }
+
+ exec();
+
+ // make sure events still waiting are processed
+ QEventLoop eventLoop;
+ eventLoop.processEvents(QEventLoop::AllEvents);
+}
+
+bool QQmlDebugServer::hasDebuggingClient() const
+{
+ Q_D(const QQmlDebugServer);
+ return d->connection
+ && d->connection->isConnected()
+ && d->gotHello;
+}
+
+static QQmlDebugServer *qQmlDebugServer = 0;
+
+
+static void cleanup()
+{
+ delete qQmlDebugServer;
+ qQmlDebugServer = 0;
+}
+
+QQmlDebugServer *QQmlDebugServer::instance()
+{
+ static bool commandLineTested = false;
+
+ if (!commandLineTested) {
+ commandLineTested = true;
+
+ QCoreApplicationPrivate *appD = static_cast<QCoreApplicationPrivate*>(QObjectPrivate::get(qApp));
+#ifndef QQML_NO_DEBUG_PROTOCOL
+ // ### remove port definition when protocol is changed
+ int port = 0;
+ bool block = false;
+ bool ok = false;
+
+ // format: qmljsdebugger=port:3768[,block] OR qmljsdebugger=ost[,block]
+ if (!appD->qmljsDebugArgumentsString().isEmpty()) {
+ if (!QQmlEnginePrivate::qml_debugging_enabled) {
+ qWarning() << QString::fromLatin1(
+ "QQmlDebugServer: Ignoring \"-qmljsdebugger=%1\". "
+ "Debugging has not been enabled.").arg(
+ appD->qmljsDebugArgumentsString());
+ return 0;
+ }
+
+ QString pluginName;
+ if (appD->qmljsDebugArgumentsString().indexOf(QLatin1String("port:")) == 0) {
+ int separatorIndex = appD->qmljsDebugArgumentsString().indexOf(QLatin1Char(','));
+ port = appD->qmljsDebugArgumentsString().mid(5, separatorIndex - 5).toInt(&ok);
+ pluginName = QLatin1String("qmldbg_tcp");
+ } else if (appD->qmljsDebugArgumentsString().contains(QLatin1String("ost"))) {
+ pluginName = QLatin1String("qmldbg_ost");
+ ok = true;
+ }
+
+ block = appD->qmljsDebugArgumentsString().contains(QLatin1String("block"));
+
+ if (ok) {
+ qQmlDebugServer = new QQmlDebugServer();
+ QQmlDebugServerThread *thread = new QQmlDebugServerThread;
+ qQmlDebugServer->d_func()->thread = thread;
+ qQmlDebugServer->moveToThread(thread);
+ thread->setPluginName(pluginName);
+ thread->setPort(port, block);
+ thread->start();
+
+ if (block) {
+ QQmlDebugServerPrivate *d = qQmlDebugServer->d_func();
+ d->messageArrivedMutex.lock();
+ d->messageArrivedCondition.wait(&d->messageArrivedMutex);
+ d->messageArrivedMutex.unlock();
+ }
+
+ } else {
+ qWarning() << QString::fromLatin1(
+ "QQmlDebugServer: Ignoring \"-qmljsdebugger=%1\". "
+ "Format is -qmljsdebugger=port:<port>[,block]").arg(
+ appD->qmljsDebugArgumentsString());
+ }
+ }
+#else
+ if (!appD->qmljsDebugArgumentsString().isEmpty()) {
+ qWarning() << QString::fromLatin1(
+ "QQmlDebugServer: Ignoring \"-qmljsdebugger=%1\". "
+ "QtQml is not configured for debugging.").arg(
+ appD->qmljsDebugArgumentsString());
+ }
+#endif
+ }
+
+ return qQmlDebugServer;
+}
+
+QQmlDebugServer::QQmlDebugServer()
+ : QObject(*(new QQmlDebugServerPrivate))
+{
+ qAddPostRoutine(cleanup);
+}
+
+QQmlDebugServer::~QQmlDebugServer()
+{
+ Q_D(QQmlDebugServer);
+
+ QReadLocker(&d->pluginsLock);
+ {
+ foreach (QQmlDebugService *service, d->plugins.values()) {
+ service->stateAboutToBeChanged(QQmlDebugService::NotConnected);
+ service->d_func()->server = 0;
+ service->d_func()->state = QQmlDebugService::NotConnected;
+ service->stateChanged(QQmlDebugService::NotConnected);
+ }
+ }
+
+ if (d->thread) {
+ d->thread->exit();
+ d->thread->wait();
+ delete d->thread;
+ }
+ delete d->connection;
+}
+
+void QQmlDebugServer::receiveMessage(const QByteArray &message)
+{
+ Q_D(QQmlDebugServer);
+
+ QDataStream in(message);
+
+ QString name;
+
+ in >> name;
+ if (name == QLatin1String("QQmlDebugServer")) {
+ int op = -1;
+ in >> op;
+ if (op == 0) {
+ int version;
+ in >> version >> d->clientPlugins;
+
+ // Send the hello answer immediately, since it needs to arrive before
+ // the plugins below start sending messages.
+ QByteArray helloAnswer;
+ {
+ QDataStream out(&helloAnswer, QIODevice::WriteOnly);
+ QStringList pluginNames;
+ QList<float> pluginVersions;
+ foreach (QQmlDebugService *service, d->plugins.values()) {
+ pluginNames << service->name();
+ pluginVersions << service->version();
+ }
+
+ out << QString(QLatin1String("QQmlDebugClient")) << 0 << protocolVersion << pluginNames << pluginVersions;
+ }
+ d->connection->send(QList<QByteArray>() << helloAnswer);
+
+ d->gotHello = true;
+
+ QReadLocker(&d->pluginsLock);
+ QHash<QString, QQmlDebugService*>::ConstIterator iter = d->plugins.constBegin();
+ for (; iter != d->plugins.constEnd(); ++iter) {
+ QQmlDebugService::State newState = QQmlDebugService::Unavailable;
+ if (d->clientPlugins.contains(iter.key()))
+ newState = QQmlDebugService::Enabled;
+ iter.value()->d_func()->state = newState;
+ iter.value()->stateChanged(newState);
+ }
+
+ qWarning("QQmlDebugServer: Connection established");
+ d->messageArrivedCondition.wakeAll();
+
+ } else if (op == 1) {
+
+ // Service Discovery
+ QStringList oldClientPlugins = d->clientPlugins;
+ in >> d->clientPlugins;
+
+ QReadLocker(&d->pluginsLock);
+ QHash<QString, QQmlDebugService*>::ConstIterator iter = d->plugins.constBegin();
+ for (; iter != d->plugins.constEnd(); ++iter) {
+ const QString pluginName = iter.key();
+ QQmlDebugService::State newState = QQmlDebugService::Unavailable;
+ if (d->clientPlugins.contains(pluginName))
+ newState = QQmlDebugService::Enabled;
+
+ if (oldClientPlugins.contains(pluginName)
+ != d->clientPlugins.contains(pluginName)) {
+ iter.value()->d_func()->state = newState;
+ iter.value()->stateChanged(newState);
+ }
+ }
+
+ } else {
+ qWarning("QQmlDebugServer: Invalid control message %d", op);
+ d->connection->disconnect();
+ return;
+ }
+
+ } else {
+ if (d->gotHello) {
+ QByteArray message;
+ in >> message;
+
+ QReadLocker(&d->pluginsLock);
+ QHash<QString, QQmlDebugService *>::Iterator iter = d->plugins.find(name);
+ if (iter == d->plugins.end()) {
+ qWarning() << "QQmlDebugServer: Message received for missing plugin" << name;
+ } else {
+ (*iter)->messageReceived(message);
+
+ if (d->waitingForMessageNames.removeOne(name))
+ d->messageArrivedCondition.wakeAll();
+ }
+ } else {
+ qWarning("QQmlDebugServer: Invalid hello message");
+ }
+
+ }
+}
+
+void QQmlDebugServerPrivate::_q_sendMessages(const QList<QByteArray> &messages)
+{
+ if (connection)
+ connection->send(messages);
+}
+
+QList<QQmlDebugService*> QQmlDebugServer::services() const
+{
+ const Q_D(QQmlDebugServer);
+ QReadLocker(&d->pluginsLock);
+ return d->plugins.values();
+}
+
+QStringList QQmlDebugServer::serviceNames() const
+{
+ const Q_D(QQmlDebugServer);
+ QReadLocker(&d->pluginsLock);
+ return d->plugins.keys();
+}
+
+bool QQmlDebugServer::addService(QQmlDebugService *service)
+{
+ Q_D(QQmlDebugServer);
+ {
+ QWriteLocker(&d->pluginsLock);
+ if (!service || d->plugins.contains(service->name()))
+ return false;
+ d->plugins.insert(service->name(), service);
+ }
+ {
+ QReadLocker(&d->pluginsLock);
+ d->advertisePlugins();
+ QQmlDebugService::State newState = QQmlDebugService::Unavailable;
+ if (d->clientPlugins.contains(service->name()))
+ newState = QQmlDebugService::Enabled;
+ service->d_func()->state = newState;
+ }
+ return true;
+}
+
+bool QQmlDebugServer::removeService(QQmlDebugService *service)
+{
+ Q_D(QQmlDebugServer);
+ {
+ QWriteLocker(&d->pluginsLock);
+ if (!service || !d->plugins.contains(service->name()))
+ return false;
+ d->plugins.remove(service->name());
+ }
+ {
+ QReadLocker(&d->pluginsLock);
+ QQmlDebugService::State newState = QQmlDebugService::NotConnected;
+ service->stateAboutToBeChanged(newState);
+ d->advertisePlugins();
+ service->d_func()->server = 0;
+ service->d_func()->state = newState;
+ service->stateChanged(newState);
+ }
+
+ return true;
+}
+
+void QQmlDebugServer::sendMessages(QQmlDebugService *service,
+ const QList<QByteArray> &messages)
+{
+ QList<QByteArray> prefixedMessages;
+ foreach (const QByteArray &message, messages) {
+ QByteArray prefixed;
+ QDataStream out(&prefixed, QIODevice::WriteOnly);
+ out << service->name() << message;
+ prefixedMessages << prefixed;
+ }
+
+ QMetaObject::invokeMethod(this, "_q_sendMessages", Qt::QueuedConnection, Q_ARG(QList<QByteArray>, prefixedMessages));
+}
+
+bool QQmlDebugServer::waitForMessage(QQmlDebugService *service)
+{
+ Q_D(QQmlDebugServer);
+ QReadLocker(&d->pluginsLock);
+
+ if (!service
+ || !d->plugins.contains(service->name()))
+ return false;
+
+ d->messageArrivedMutex.lock();
+ d->waitingForMessageNames << service->name();
+ do {
+ d->messageArrivedCondition.wait(&d->messageArrivedMutex);
+ } while (d->waitingForMessageNames.contains(service->name()));
+ d->messageArrivedMutex.unlock();
+ return true;
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qqmldebugserver_p.cpp"
diff --git a/src/qml/debugger/qqmldebugserver_p.h b/src/qml/debugger/qqmldebugserver_p.h
new file mode 100644
index 0000000000..9c6b5435c8
--- /dev/null
+++ b/src/qml/debugger/qqmldebugserver_p.h
@@ -0,0 +1,105 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLDEBUGSERVER_H
+#define QQMLDEBUGSERVER_H
+
+#include <QtQml/qtqmlglobal.h>
+#include <private/qqmldebugserverconnection_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.
+//
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+
+class QQmlDebugService;
+
+class QQmlDebugServerPrivate;
+class Q_QML_EXPORT QQmlDebugServer : public QObject
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QQmlDebugServer)
+ Q_DISABLE_COPY(QQmlDebugServer)
+public:
+ ~QQmlDebugServer();
+
+ static QQmlDebugServer *instance();
+
+ void setConnection(QQmlDebugServerConnection *connection);
+
+ bool hasDebuggingClient() const;
+
+ QList<QQmlDebugService*> services() const;
+ QStringList serviceNames() const;
+
+
+ bool addService(QQmlDebugService *service);
+ bool removeService(QQmlDebugService *service);
+
+ void receiveMessage(const QByteArray &message);
+
+ bool waitForMessage(QQmlDebugService *service);
+ void sendMessages(QQmlDebugService *service, const QList<QByteArray> &messages);
+
+private:
+ friend class QQmlDebugService;
+ friend class QQmlDebugServicePrivate;
+ friend class QQmlDebugServerThread;
+ QQmlDebugServer();
+ Q_PRIVATE_SLOT(d_func(), void _q_sendMessages(QList<QByteArray>))
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QQMLDEBUGSERVICE_H
diff --git a/src/qml/debugger/qqmldebugserverconnection_p.h b/src/qml/debugger/qqmldebugserverconnection_p.h
new file mode 100644
index 0000000000..c9092f1911
--- /dev/null
+++ b/src/qml/debugger/qqmldebugserverconnection_p.h
@@ -0,0 +1,85 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLDEBUGSERVERCONNECTION_H
+#define QQMLDEBUGSERVERCONNECTION_H
+
+#include <QtQml/qtqmlglobal.h>
+#include <QtCore/QtPlugin>
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+
+class QQmlDebugServer;
+class Q_QML_EXPORT QQmlDebugServerConnection
+{
+public:
+ QQmlDebugServerConnection() {}
+ virtual ~QQmlDebugServerConnection() {}
+
+ virtual void setServer(QQmlDebugServer *server) = 0;
+ virtual void setPort(int port, bool bock) = 0;
+ virtual bool isConnected() const = 0;
+ virtual void send(const QList<QByteArray> &messages) = 0;
+ virtual void disconnect() = 0;
+ virtual bool waitForMessage() = 0;
+};
+
+Q_DECLARE_INTERFACE(QQmlDebugServerConnection, "com.trolltech.Qt.QQmlDebugServerConnection/1.0")
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QQMLDEBUGSERVERCONNECTION_H
diff --git a/src/qml/debugger/qqmldebugservice.cpp b/src/qml/debugger/qqmldebugservice.cpp
new file mode 100644
index 0000000000..9eb9489566
--- /dev/null
+++ b/src/qml/debugger/qqmldebugservice.cpp
@@ -0,0 +1,268 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qqmldebugservice_p.h"
+#include "qqmldebugservice_p_p.h"
+#include "qqmldebugserver_p.h"
+
+#include <QtCore/QDebug>
+#include <QtCore/QStringList>
+
+QT_BEGIN_NAMESPACE
+
+QQmlDebugServicePrivate::QQmlDebugServicePrivate()
+ : server(0)
+{
+}
+
+QQmlDebugService::QQmlDebugService(const QString &name, float version, QObject *parent)
+ : QObject(*(new QQmlDebugServicePrivate), parent)
+{
+ Q_D(QQmlDebugService);
+ d->name = name;
+ d->version = version;
+ d->server = QQmlDebugServer::instance();
+ d->state = QQmlDebugService::NotConnected;
+
+
+}
+
+QQmlDebugService::QQmlDebugService(QQmlDebugServicePrivate &dd,
+ const QString &name, float version, QObject *parent)
+ : QObject(dd, parent)
+{
+ Q_D(QQmlDebugService);
+ d->name = name;
+ d->version = version;
+ d->server = QQmlDebugServer::instance();
+ d->state = QQmlDebugService::NotConnected;
+}
+
+/**
+ Registers the service. This should be called in the constructor of the inherited class. From
+ then on the service might get asynchronous calls to messageReceived().
+ */
+QQmlDebugService::State QQmlDebugService::registerService()
+{
+ Q_D(QQmlDebugService);
+ if (!d->server)
+ return NotConnected;
+
+ if (d->server->serviceNames().contains(d->name)) {
+ qWarning() << "QQmlDebugService: Conflicting plugin name" << d->name;
+ d->server = 0;
+ } else {
+ d->server->addService(this);
+ }
+ return state();
+}
+
+QQmlDebugService::~QQmlDebugService()
+{
+ Q_D(const QQmlDebugService);
+ if (d->server) {
+ d->server->removeService(this);
+ }
+}
+
+QString QQmlDebugService::name() const
+{
+ Q_D(const QQmlDebugService);
+ return d->name;
+}
+
+float QQmlDebugService::version() const
+{
+ Q_D(const QQmlDebugService);
+ return d->version;
+}
+
+QQmlDebugService::State QQmlDebugService::state() const
+{
+ Q_D(const QQmlDebugService);
+ return d->state;
+}
+
+namespace {
+
+struct ObjectReference
+{
+ QPointer<QObject> object;
+ int id;
+};
+
+struct ObjectReferenceHash
+{
+ ObjectReferenceHash() : nextId(0) {}
+
+ QHash<QObject *, ObjectReference> objects;
+ QHash<int, QObject *> ids;
+
+ int nextId;
+};
+
+}
+Q_GLOBAL_STATIC(ObjectReferenceHash, objectReferenceHash);
+
+
+/*!
+ Returns a unique id for \a object. Calling this method multiple times
+ for the same object will return the same id.
+*/
+int QQmlDebugService::idForObject(QObject *object)
+{
+ if (!object)
+ return -1;
+
+ ObjectReferenceHash *hash = objectReferenceHash();
+ QHash<QObject *, ObjectReference>::Iterator iter =
+ hash->objects.find(object);
+
+ if (iter == hash->objects.end()) {
+ int id = hash->nextId++;
+
+ hash->ids.insert(id, object);
+ iter = hash->objects.insert(object, ObjectReference());
+ iter->object = object;
+ iter->id = id;
+ } else if (iter->object != object) {
+ int id = hash->nextId++;
+
+ hash->ids.remove(iter->id);
+
+ hash->ids.insert(id, object);
+ iter->object = object;
+ iter->id = id;
+ }
+ return iter->id;
+}
+
+/*!
+ Returns the object for unique \a id. If the object has not previously been
+ assigned an id, through idForObject(), then 0 is returned. If the object
+ has been destroyed, 0 is returned.
+*/
+QObject *QQmlDebugService::objectForId(int id)
+{
+ ObjectReferenceHash *hash = objectReferenceHash();
+
+ QHash<int, QObject *>::Iterator iter = hash->ids.find(id);
+ if (iter == hash->ids.end())
+ return 0;
+
+
+ QHash<QObject *, ObjectReference>::Iterator objIter =
+ hash->objects.find(*iter);
+ Q_ASSERT(objIter != hash->objects.end());
+
+ if (objIter->object == 0) {
+ hash->ids.erase(iter);
+ hash->objects.erase(objIter);
+ return 0;
+ } else {
+ return *iter;
+ }
+}
+
+bool QQmlDebugService::isDebuggingEnabled()
+{
+ return QQmlDebugServer::instance() != 0;
+}
+
+bool QQmlDebugService::hasDebuggingClient()
+{
+ return QQmlDebugServer::instance() != 0
+ && QQmlDebugServer::instance()->hasDebuggingClient();
+}
+
+QString QQmlDebugService::objectToString(QObject *obj)
+{
+ if(!obj)
+ return QLatin1String("NULL");
+
+ QString objectName = obj->objectName();
+ if(objectName.isEmpty())
+ objectName = QLatin1String("<unnamed>");
+
+ QString rv = QString::fromUtf8(obj->metaObject()->className()) +
+ QLatin1String(": ") + objectName;
+
+ return rv;
+}
+
+void QQmlDebugService::sendMessage(const QByteArray &message)
+{
+ sendMessages(QList<QByteArray>() << message);
+}
+
+void QQmlDebugService::sendMessages(const QList<QByteArray> &messages)
+{
+ Q_D(QQmlDebugService);
+
+ if (state() != Enabled)
+ return;
+
+ d->server->sendMessages(this, messages);
+}
+
+bool QQmlDebugService::waitForMessage()
+{
+ Q_D(QQmlDebugService);
+
+ if (state() != Enabled)
+ return false;
+
+ return d->server->waitForMessage(this);
+}
+
+void QQmlDebugService::stateAboutToBeChanged(State)
+{
+}
+
+void QQmlDebugService::stateChanged(State)
+{
+}
+
+void QQmlDebugService::messageReceived(const QByteArray &)
+{
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/debugger/qqmldebugservice_p.h b/src/qml/debugger/qqmldebugservice_p.h
new file mode 100644
index 0000000000..f19b64f42b
--- /dev/null
+++ b/src/qml/debugger/qqmldebugservice_p.h
@@ -0,0 +1,113 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLDEBUGSERVICE_H
+#define QQMLDEBUGSERVICE_H
+
+#include <QtCore/qobject.h>
+
+#include <private/qtqmlglobal_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.
+//
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+
+class QQmlDebugServicePrivate;
+class Q_QML_PRIVATE_EXPORT QQmlDebugService : public QObject
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QQmlDebugService)
+ Q_DISABLE_COPY(QQmlDebugService)
+
+public:
+ explicit QQmlDebugService(const QString &, float version, QObject *parent = 0);
+ ~QQmlDebugService();
+
+ QString name() const;
+ float version() const;
+
+ enum State { NotConnected, Unavailable, Enabled };
+ State state() const;
+
+ void sendMessage(const QByteArray &);
+ void sendMessages(const QList<QByteArray> &);
+ bool waitForMessage();
+
+ static int idForObject(QObject *);
+ static QObject *objectForId(int);
+
+ static QString objectToString(QObject *obj);
+
+ static bool isDebuggingEnabled();
+ static bool hasDebuggingClient();
+
+protected:
+ QQmlDebugService(QQmlDebugServicePrivate &dd, const QString &name, float version, QObject *parent = 0);
+
+ State registerService();
+
+ virtual void stateAboutToBeChanged(State);
+ virtual void stateChanged(State);
+ virtual void messageReceived(const QByteArray &);
+
+private:
+ friend class QQmlDebugServer;
+ friend class QQmlDebugServerPrivate;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QQMLDEBUGSERVICE_H
+
diff --git a/src/qml/debugger/qqmldebugservice_p_p.h b/src/qml/debugger/qqmldebugservice_p_p.h
new file mode 100644
index 0000000000..c066e41fe6
--- /dev/null
+++ b/src/qml/debugger/qqmldebugservice_p_p.h
@@ -0,0 +1,82 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLDEBUGSERVICE_P_H
+#define QQMLDEBUGSERVICE_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qglobal.h>
+#include <private/qobject_p.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+
+class QQmlDebugServer;
+
+class QQmlDebugServicePrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QQmlDebugService)
+public:
+ QQmlDebugServicePrivate();
+
+ QString name;
+ float version;
+ QQmlDebugServer *server;
+ QQmlDebugService::State state;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QQMLDEBUGSERVICE_P_H
diff --git a/src/qml/debugger/qqmldebugstatesdelegate_p.h b/src/qml/debugger/qqmldebugstatesdelegate_p.h
new file mode 100644
index 0000000000..6e3cc978f2
--- /dev/null
+++ b/src/qml/debugger/qqmldebugstatesdelegate_p.h
@@ -0,0 +1,98 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLDEBUGSTATESDELEGATE_P_H
+#define QQMLDEBUGSTATESDELEGATE_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtQml/qtqmlglobal.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+
+class QQmlContext;
+class QQmlProperty;
+class QObject;
+class QString;
+class QVariant;
+
+class QQmlDebugStatesDelegate
+{
+protected:
+ QQmlDebugStatesDelegate() {}
+
+public:
+ virtual ~QQmlDebugStatesDelegate() {}
+
+ virtual void buildStatesList(QQmlContext *ctxt, bool cleanList) = 0;
+ virtual void updateBinding(QQmlContext *context,
+ const QQmlProperty &property,
+ const QVariant &expression, bool isLiteralValue,
+ const QString &fileName, int line, int column,
+ bool *inBaseState) = 0;
+ virtual bool setBindingForInvalidProperty(QObject *object,
+ const QString &propertyName,
+ const QVariant &expression,
+ bool isLiteralValue) = 0;
+ virtual void resetBindingForInvalidProperty(QObject *object,
+ const QString &propertyName) = 0;
+
+private:
+ Q_DISABLE_COPY(QQmlDebugStatesDelegate)
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QQMLDEBUGSTATESDELEGATE_P_H
diff --git a/src/qml/debugger/qqmlenginedebug.cpp b/src/qml/debugger/qqmlenginedebug.cpp
new file mode 100644
index 0000000000..597e7aeb04
--- /dev/null
+++ b/src/qml/debugger/qqmlenginedebug.cpp
@@ -0,0 +1,1072 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qqmlenginedebug_p.h"
+
+#include "qqmldebugclient_p.h"
+
+#include "qqmlenginedebugservice_p.h"
+
+#include <private/qobject_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQmlEngineDebugClient : public QQmlDebugClient
+{
+public:
+ QQmlEngineDebugClient(QQmlDebugConnection *client, QQmlEngineDebugPrivate *p);
+
+protected:
+ virtual void stateChanged(State state);
+ virtual void messageReceived(const QByteArray &);
+
+private:
+ QQmlEngineDebugPrivate *priv;
+ friend class QQmlEngineDebugPrivate;
+};
+
+class QQmlEngineDebugPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QQmlEngineDebug)
+public:
+ QQmlEngineDebugPrivate(QQmlDebugConnection *);
+ ~QQmlEngineDebugPrivate();
+
+ void stateChanged(QQmlEngineDebug::State status);
+ void message(const QByteArray &);
+
+ QQmlEngineDebugClient *client;
+ int nextId;
+ int getId();
+
+ void decode(QDataStream &, QQmlDebugContextReference &);
+ void decode(QDataStream &, QQmlDebugObjectReference &, bool simple);
+
+ static void remove(QQmlEngineDebug *, QQmlDebugEnginesQuery *);
+ static void remove(QQmlEngineDebug *, QQmlDebugRootContextQuery *);
+ static void remove(QQmlEngineDebug *, QQmlDebugObjectQuery *);
+ static void remove(QQmlEngineDebug *, QQmlDebugExpressionQuery *);
+ static void remove(QQmlEngineDebug *, QQmlDebugWatch *);
+
+ QHash<int, QQmlDebugEnginesQuery *> enginesQuery;
+ QHash<int, QQmlDebugRootContextQuery *> rootContextQuery;
+ QHash<int, QQmlDebugObjectQuery *> objectQuery;
+ QHash<int, QQmlDebugExpressionQuery *> expressionQuery;
+
+ QHash<int, QQmlDebugWatch *> watched;
+};
+
+QQmlEngineDebugClient::QQmlEngineDebugClient(QQmlDebugConnection *client,
+ QQmlEngineDebugPrivate *p)
+ : QQmlDebugClient(QLatin1String("QQmlEngine"), client), priv(p)
+{
+}
+
+void QQmlEngineDebugClient::stateChanged(State status)
+{
+ if (priv)
+ priv->stateChanged(static_cast<QQmlEngineDebug::State>(status));
+}
+
+void QQmlEngineDebugClient::messageReceived(const QByteArray &data)
+{
+ if (priv)
+ priv->message(data);
+}
+
+QQmlEngineDebugPrivate::QQmlEngineDebugPrivate(QQmlDebugConnection *c)
+ : client(new QQmlEngineDebugClient(c, this)), nextId(0)
+{
+}
+
+QQmlEngineDebugPrivate::~QQmlEngineDebugPrivate()
+{
+ if (client)
+ client->priv = 0;
+ delete client;
+
+ QHash<int, QQmlDebugEnginesQuery*>::iterator enginesIter = enginesQuery.begin();
+ for (; enginesIter != enginesQuery.end(); ++enginesIter) {
+ enginesIter.value()->m_client = 0;
+ if (enginesIter.value()->state() == QQmlDebugQuery::Waiting)
+ enginesIter.value()->setState(QQmlDebugQuery::Error);
+ }
+
+ QHash<int, QQmlDebugRootContextQuery*>::iterator rootContextIter = rootContextQuery.begin();
+ for (; rootContextIter != rootContextQuery.end(); ++rootContextIter) {
+ rootContextIter.value()->m_client = 0;
+ if (rootContextIter.value()->state() == QQmlDebugQuery::Waiting)
+ rootContextIter.value()->setState(QQmlDebugQuery::Error);
+ }
+
+ QHash<int, QQmlDebugObjectQuery*>::iterator objectIter = objectQuery.begin();
+ for (; objectIter != objectQuery.end(); ++objectIter) {
+ objectIter.value()->m_client = 0;
+ if (objectIter.value()->state() == QQmlDebugQuery::Waiting)
+ objectIter.value()->setState(QQmlDebugQuery::Error);
+ }
+
+ QHash<int, QQmlDebugExpressionQuery*>::iterator exprIter = expressionQuery.begin();
+ for (; exprIter != expressionQuery.end(); ++exprIter) {
+ exprIter.value()->m_client = 0;
+ if (exprIter.value()->state() == QQmlDebugQuery::Waiting)
+ exprIter.value()->setState(QQmlDebugQuery::Error);
+ }
+
+ QHash<int, QQmlDebugWatch*>::iterator watchIter = watched.begin();
+ for (; watchIter != watched.end(); ++watchIter) {
+ watchIter.value()->m_client = 0;
+ watchIter.value()->setState(QQmlDebugWatch::Dead);
+ }
+}
+
+int QQmlEngineDebugPrivate::getId()
+{
+ return nextId++;
+}
+
+void QQmlEngineDebugPrivate::remove(QQmlEngineDebug *c, QQmlDebugEnginesQuery *q)
+{
+ if (c && q) {
+ QQmlEngineDebugPrivate *p = (QQmlEngineDebugPrivate *)QObjectPrivate::get(c);
+ p->enginesQuery.remove(q->m_queryId);
+ }
+}
+
+void QQmlEngineDebugPrivate::remove(QQmlEngineDebug *c,
+ QQmlDebugRootContextQuery *q)
+{
+ if (c && q) {
+ QQmlEngineDebugPrivate *p = (QQmlEngineDebugPrivate *)QObjectPrivate::get(c);
+ p->rootContextQuery.remove(q->m_queryId);
+ }
+}
+
+void QQmlEngineDebugPrivate::remove(QQmlEngineDebug *c, QQmlDebugObjectQuery *q)
+{
+ if (c && q) {
+ QQmlEngineDebugPrivate *p = (QQmlEngineDebugPrivate *)QObjectPrivate::get(c);
+ p->objectQuery.remove(q->m_queryId);
+ }
+}
+
+void QQmlEngineDebugPrivate::remove(QQmlEngineDebug *c, QQmlDebugExpressionQuery *q)
+{
+ if (c && q) {
+ QQmlEngineDebugPrivate *p = (QQmlEngineDebugPrivate *)QObjectPrivate::get(c);
+ p->expressionQuery.remove(q->m_queryId);
+ }
+}
+
+void QQmlEngineDebugPrivate::remove(QQmlEngineDebug *c, QQmlDebugWatch *w)
+{
+ if (c && w) {
+ QQmlEngineDebugPrivate *p = (QQmlEngineDebugPrivate *)QObjectPrivate::get(c);
+ p->watched.remove(w->m_queryId);
+ }
+}
+
+void QQmlEngineDebugPrivate::decode(QDataStream &ds, QQmlDebugObjectReference &o,
+ bool simple)
+{
+ QQmlEngineDebugService::QQmlObjectData data;
+ ds >> data;
+ o.m_debugId = data.objectId;
+ o.m_class = data.objectType;
+ o.m_idString = data.idString;
+ o.m_name = data.objectName;
+ o.m_source.m_url = data.url;
+ o.m_source.m_lineNumber = data.lineNumber;
+ o.m_source.m_columnNumber = data.columnNumber;
+ o.m_contextDebugId = data.contextId;
+
+ if (simple)
+ return;
+
+ int childCount;
+ bool recur;
+ ds >> childCount >> recur;
+
+ for (int ii = 0; ii < childCount; ++ii) {
+ o.m_children.append(QQmlDebugObjectReference());
+ decode(ds, o.m_children.last(), !recur);
+ }
+
+ int propCount;
+ ds >> propCount;
+
+ for (int ii = 0; ii < propCount; ++ii) {
+ QQmlEngineDebugService::QQmlObjectProperty data;
+ ds >> data;
+ QQmlDebugPropertyReference prop;
+ prop.m_objectDebugId = o.m_debugId;
+ prop.m_name = data.name;
+ prop.m_binding = data.binding;
+ prop.m_hasNotifySignal = data.hasNotifySignal;
+ prop.m_valueTypeName = data.valueTypeName;
+ switch (data.type) {
+ case QQmlEngineDebugService::QQmlObjectProperty::Basic:
+ case QQmlEngineDebugService::QQmlObjectProperty::List:
+ case QQmlEngineDebugService::QQmlObjectProperty::SignalProperty:
+ {
+ prop.m_value = data.value;
+ break;
+ }
+ case QQmlEngineDebugService::QQmlObjectProperty::Object:
+ {
+ QQmlDebugObjectReference obj;
+ obj.m_debugId = prop.m_value.toInt();
+ prop.m_value = QVariant::fromValue(obj);
+ break;
+ }
+ case QQmlEngineDebugService::QQmlObjectProperty::Unknown:
+ break;
+ }
+ o.m_properties << prop;
+ }
+}
+
+void QQmlEngineDebugPrivate::decode(QDataStream &ds, QQmlDebugContextReference &c)
+{
+ ds >> c.m_name >> c.m_debugId;
+
+ int contextCount;
+ ds >> contextCount;
+
+ for (int ii = 0; ii < contextCount; ++ii) {
+ c.m_contexts.append(QQmlDebugContextReference());
+ decode(ds, c.m_contexts.last());
+ }
+
+ int objectCount;
+ ds >> objectCount;
+
+ for (int ii = 0; ii < objectCount; ++ii) {
+ QQmlDebugObjectReference obj;
+ decode(ds, obj, true);
+
+ obj.m_contextDebugId = c.m_debugId;
+ c.m_objects << obj;
+ }
+}
+
+void QQmlEngineDebugPrivate::stateChanged(QQmlEngineDebug::State status)
+{
+ emit q_func()->stateChanged(status);
+}
+
+void QQmlEngineDebugPrivate::message(const QByteArray &data)
+{
+ QDataStream ds(data);
+
+ QByteArray type;
+ ds >> type;
+
+ //qDebug() << "QQmlEngineDebugPrivate::message()" << type;
+
+ if (type == "LIST_ENGINES_R") {
+ int queryId;
+ ds >> queryId;
+
+ QQmlDebugEnginesQuery *query = enginesQuery.value(queryId);
+ if (!query)
+ return;
+ enginesQuery.remove(queryId);
+
+ int count;
+ ds >> count;
+
+ for (int ii = 0; ii < count; ++ii) {
+ QQmlDebugEngineReference ref;
+ ds >> ref.m_name;
+ ds >> ref.m_debugId;
+ query->m_engines << ref;
+ }
+
+ query->m_client = 0;
+ query->setState(QQmlDebugQuery::Completed);
+ } else if (type == "LIST_OBJECTS_R") {
+ int queryId;
+ ds >> queryId;
+
+ QQmlDebugRootContextQuery *query = rootContextQuery.value(queryId);
+ if (!query)
+ return;
+ rootContextQuery.remove(queryId);
+
+ if (!ds.atEnd())
+ decode(ds, query->m_context);
+
+ query->m_client = 0;
+ query->setState(QQmlDebugQuery::Completed);
+ } else if (type == "FETCH_OBJECT_R") {
+ int queryId;
+ ds >> queryId;
+
+ QQmlDebugObjectQuery *query = objectQuery.value(queryId);
+ if (!query)
+ return;
+ objectQuery.remove(queryId);
+
+ if (!ds.atEnd())
+ decode(ds, query->m_object, false);
+
+ query->m_client = 0;
+ query->setState(QQmlDebugQuery::Completed);
+ } else if (type == "EVAL_EXPRESSION_R") {
+ int queryId;
+ QVariant result;
+ ds >> queryId >> result;
+
+ QQmlDebugExpressionQuery *query = expressionQuery.value(queryId);
+ if (!query)
+ return;
+ expressionQuery.remove(queryId);
+
+ query->m_result = result;
+ query->m_client = 0;
+ query->setState(QQmlDebugQuery::Completed);
+ } else if (type == "WATCH_PROPERTY_R") {
+ int queryId;
+ bool ok;
+ ds >> queryId >> ok;
+
+ QQmlDebugWatch *watch = watched.value(queryId);
+ if (!watch)
+ return;
+
+ watch->setState(ok ? QQmlDebugWatch::Active : QQmlDebugWatch::Inactive);
+ } else if (type == "WATCH_OBJECT_R") {
+ int queryId;
+ bool ok;
+ ds >> queryId >> ok;
+
+ QQmlDebugWatch *watch = watched.value(queryId);
+ if (!watch)
+ return;
+
+ watch->setState(ok ? QQmlDebugWatch::Active : QQmlDebugWatch::Inactive);
+ } else if (type == "WATCH_EXPR_OBJECT_R") {
+ int queryId;
+ bool ok;
+ ds >> queryId >> ok;
+
+ QQmlDebugWatch *watch = watched.value(queryId);
+ if (!watch)
+ return;
+
+ watch->setState(ok ? QQmlDebugWatch::Active : QQmlDebugWatch::Inactive);
+ } else if (type == "UPDATE_WATCH") {
+ int queryId;
+ int debugId;
+ QByteArray name;
+ QVariant value;
+ ds >> queryId >> debugId >> name >> value;
+
+ QQmlDebugWatch *watch = watched.value(queryId, 0);
+ if (!watch)
+ return;
+ emit watch->valueChanged(name, value);
+ } else if (type == "OBJECT_CREATED") {
+ emit q_func()->newObjects();
+ }
+}
+
+QQmlEngineDebug::QQmlEngineDebug(QQmlDebugConnection *client, QObject *parent)
+ : QObject(*(new QQmlEngineDebugPrivate(client)), parent)
+{
+}
+
+QQmlEngineDebug::~QQmlEngineDebug()
+{
+}
+
+QQmlEngineDebug::State QQmlEngineDebug::state() const
+{
+ Q_D(const QQmlEngineDebug);
+
+ return static_cast<QQmlEngineDebug::State>(d->client->state());
+}
+
+QQmlDebugPropertyWatch *QQmlEngineDebug::addWatch(const QQmlDebugPropertyReference &property, QObject *parent)
+{
+ Q_D(QQmlEngineDebug);
+
+ QQmlDebugPropertyWatch *watch = new QQmlDebugPropertyWatch(parent);
+ if (d->client->state() == QQmlDebugClient::Enabled) {
+ int queryId = d->getId();
+ watch->m_queryId = queryId;
+ watch->m_client = this;
+ watch->m_objectDebugId = property.objectDebugId();
+ watch->m_name = property.name();
+ d->watched.insert(queryId, watch);
+
+ QByteArray message;
+ QDataStream ds(&message, QIODevice::WriteOnly);
+ ds << QByteArray("WATCH_PROPERTY") << queryId << property.objectDebugId() << property.name().toUtf8();
+ d->client->sendMessage(message);
+ } else {
+ watch->m_state = QQmlDebugWatch::Dead;
+ }
+
+ return watch;
+}
+
+QQmlDebugWatch *QQmlEngineDebug::addWatch(const QQmlDebugContextReference &, const QString &, QObject *)
+{
+ qWarning("QQmlEngineDebug::addWatch(): Not implemented");
+ return 0;
+}
+
+QQmlDebugObjectExpressionWatch *QQmlEngineDebug::addWatch(const QQmlDebugObjectReference &object, const QString &expr, QObject *parent)
+{
+ Q_D(QQmlEngineDebug);
+ QQmlDebugObjectExpressionWatch *watch = new QQmlDebugObjectExpressionWatch(parent);
+ if (d->client->state() == QQmlDebugClient::Enabled) {
+ int queryId = d->getId();
+ watch->m_queryId = queryId;
+ watch->m_client = this;
+ watch->m_objectDebugId = object.debugId();
+ watch->m_expr = expr;
+ d->watched.insert(queryId, watch);
+
+ QByteArray message;
+ QDataStream ds(&message, QIODevice::WriteOnly);
+ ds << QByteArray("WATCH_EXPR_OBJECT") << queryId << object.debugId() << expr;
+ d->client->sendMessage(message);
+ } else {
+ watch->m_state = QQmlDebugWatch::Dead;
+ }
+ return watch;
+}
+
+QQmlDebugWatch *QQmlEngineDebug::addWatch(const QQmlDebugObjectReference &object, QObject *parent)
+{
+ Q_D(QQmlEngineDebug);
+
+ QQmlDebugWatch *watch = new QQmlDebugWatch(parent);
+ if (d->client->state() == QQmlDebugClient::Enabled) {
+ int queryId = d->getId();
+ watch->m_queryId = queryId;
+ watch->m_client = this;
+ watch->m_objectDebugId = object.debugId();
+ d->watched.insert(queryId, watch);
+
+ QByteArray message;
+ QDataStream ds(&message, QIODevice::WriteOnly);
+ ds << QByteArray("WATCH_OBJECT") << queryId << object.debugId();
+ d->client->sendMessage(message);
+ } else {
+ watch->m_state = QQmlDebugWatch::Dead;
+ }
+
+ return watch;
+}
+
+QQmlDebugWatch *QQmlEngineDebug::addWatch(const QQmlDebugFileReference &, QObject *)
+{
+ qWarning("QQmlEngineDebug::addWatch(): Not implemented");
+ return 0;
+}
+
+void QQmlEngineDebug::removeWatch(QQmlDebugWatch *watch)
+{
+ Q_D(QQmlEngineDebug);
+
+ if (!watch || !watch->m_client)
+ return;
+
+ watch->m_client = 0;
+ watch->setState(QQmlDebugWatch::Inactive);
+
+ d->watched.remove(watch->queryId());
+
+ if (d->client && d->client->state() == QQmlDebugClient::Enabled) {
+ QByteArray message;
+ QDataStream ds(&message, QIODevice::WriteOnly);
+ ds << QByteArray("NO_WATCH") << watch->queryId();
+ d->client->sendMessage(message);
+ }
+}
+
+QQmlDebugEnginesQuery *QQmlEngineDebug::queryAvailableEngines(QObject *parent)
+{
+ Q_D(QQmlEngineDebug);
+
+ QQmlDebugEnginesQuery *query = new QQmlDebugEnginesQuery(parent);
+ if (d->client->state() == QQmlDebugClient::Enabled) {
+ query->m_client = this;
+ int queryId = d->getId();
+ query->m_queryId = queryId;
+ d->enginesQuery.insert(queryId, query);
+
+ QByteArray message;
+ QDataStream ds(&message, QIODevice::WriteOnly);
+ ds << QByteArray("LIST_ENGINES") << queryId;
+ d->client->sendMessage(message);
+ } else {
+ query->m_state = QQmlDebugQuery::Error;
+ }
+
+ return query;
+}
+
+QQmlDebugRootContextQuery *QQmlEngineDebug::queryRootContexts(const QQmlDebugEngineReference &engine, QObject *parent)
+{
+ Q_D(QQmlEngineDebug);
+
+ QQmlDebugRootContextQuery *query = new QQmlDebugRootContextQuery(parent);
+ if (d->client->state() == QQmlDebugClient::Enabled && engine.debugId() != -1) {
+ query->m_client = this;
+ int queryId = d->getId();
+ query->m_queryId = queryId;
+ d->rootContextQuery.insert(queryId, query);
+
+ QByteArray message;
+ QDataStream ds(&message, QIODevice::WriteOnly);
+ ds << QByteArray("LIST_OBJECTS") << queryId << engine.debugId();
+ d->client->sendMessage(message);
+ } else {
+ query->m_state = QQmlDebugQuery::Error;
+ }
+
+ return query;
+}
+
+QQmlDebugObjectQuery *QQmlEngineDebug::queryObject(const QQmlDebugObjectReference &object, QObject *parent)
+{
+ Q_D(QQmlEngineDebug);
+
+ QQmlDebugObjectQuery *query = new QQmlDebugObjectQuery(parent);
+ if (d->client->state() == QQmlDebugClient::Enabled && object.debugId() != -1) {
+ query->m_client = this;
+ int queryId = d->getId();
+ query->m_queryId = queryId;
+ d->objectQuery.insert(queryId, query);
+
+ QByteArray message;
+ QDataStream ds(&message, QIODevice::WriteOnly);
+ ds << QByteArray("FETCH_OBJECT") << queryId << object.debugId()
+ << false << true;
+ d->client->sendMessage(message);
+ } else {
+ query->m_state = QQmlDebugQuery::Error;
+ }
+
+ return query;
+}
+
+QQmlDebugObjectQuery *QQmlEngineDebug::queryObjectRecursive(const QQmlDebugObjectReference &object, QObject *parent)
+{
+ Q_D(QQmlEngineDebug);
+
+ QQmlDebugObjectQuery *query = new QQmlDebugObjectQuery(parent);
+ if (d->client->state() == QQmlDebugClient::Enabled && object.debugId() != -1) {
+ query->m_client = this;
+ int queryId = d->getId();
+ query->m_queryId = queryId;
+ d->objectQuery.insert(queryId, query);
+
+ QByteArray message;
+ QDataStream ds(&message, QIODevice::WriteOnly);
+ ds << QByteArray("FETCH_OBJECT") << queryId << object.debugId()
+ << true << true;
+ d->client->sendMessage(message);
+ } else {
+ query->m_state = QQmlDebugQuery::Error;
+ }
+
+ return query;
+}
+
+QQmlDebugExpressionQuery *QQmlEngineDebug::queryExpressionResult(int objectDebugId, const QString &expr, QObject *parent)
+{
+ Q_D(QQmlEngineDebug);
+
+ QQmlDebugExpressionQuery *query = new QQmlDebugExpressionQuery(parent);
+ if (d->client->state() == QQmlDebugClient::Enabled && objectDebugId != -1) {
+ query->m_client = this;
+ query->m_expr = expr;
+ int queryId = d->getId();
+ query->m_queryId = queryId;
+ d->expressionQuery.insert(queryId, query);
+
+ QByteArray message;
+ QDataStream ds(&message, QIODevice::WriteOnly);
+ ds << QByteArray("EVAL_EXPRESSION") << queryId << objectDebugId << expr;
+ d->client->sendMessage(message);
+ } else {
+ query->m_state = QQmlDebugQuery::Error;
+ }
+
+ return query;
+}
+
+bool QQmlEngineDebug::setBindingForObject(int objectDebugId, const QString &propertyName,
+ const QVariant &bindingExpression,
+ bool isLiteralValue,
+ QString source, int line)
+{
+ Q_D(QQmlEngineDebug);
+
+ if (d->client->state() == QQmlDebugClient::Enabled && objectDebugId != -1) {
+ QByteArray message;
+ QDataStream ds(&message, QIODevice::WriteOnly);
+ ds << QByteArray("SET_BINDING") << objectDebugId << propertyName << bindingExpression << isLiteralValue << source << line;
+ d->client->sendMessage(message);
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool QQmlEngineDebug::resetBindingForObject(int objectDebugId, const QString &propertyName)
+{
+ Q_D(QQmlEngineDebug);
+
+ if (d->client->state() == QQmlDebugClient::Enabled && objectDebugId != -1) {
+ QByteArray message;
+ QDataStream ds(&message, QIODevice::WriteOnly);
+ ds << QByteArray("RESET_BINDING") << objectDebugId << propertyName;
+ d->client->sendMessage(message);
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool QQmlEngineDebug::setMethodBody(int objectDebugId, const QString &methodName,
+ const QString &methodBody)
+{
+ Q_D(QQmlEngineDebug);
+
+ if (d->client->state() == QQmlDebugClient::Enabled && objectDebugId != -1) {
+ QByteArray message;
+ QDataStream ds(&message, QIODevice::WriteOnly);
+ ds << QByteArray("SET_METHOD_BODY") << objectDebugId << methodName << methodBody;
+ d->client->sendMessage(message);
+ return true;
+ } else {
+ return false;
+ }
+}
+
+QQmlDebugWatch::QQmlDebugWatch(QObject *parent)
+ : QObject(parent), m_state(Waiting), m_queryId(-1), m_client(0), m_objectDebugId(-1)
+{
+}
+
+QQmlDebugWatch::~QQmlDebugWatch()
+{
+ if (m_client && m_queryId != -1)
+ QQmlEngineDebugPrivate::remove(m_client, this);
+}
+
+int QQmlDebugWatch::queryId() const
+{
+ return m_queryId;
+}
+
+int QQmlDebugWatch::objectDebugId() const
+{
+ return m_objectDebugId;
+}
+
+QQmlDebugWatch::State QQmlDebugWatch::state() const
+{
+ return m_state;
+}
+
+void QQmlDebugWatch::setState(State s)
+{
+ if (m_state == s)
+ return;
+ m_state = s;
+ emit stateChanged(m_state);
+}
+
+QQmlDebugPropertyWatch::QQmlDebugPropertyWatch(QObject *parent)
+ : QQmlDebugWatch(parent)
+{
+}
+
+QString QQmlDebugPropertyWatch::name() const
+{
+ return m_name;
+}
+
+
+QQmlDebugObjectExpressionWatch::QQmlDebugObjectExpressionWatch(QObject *parent)
+ : QQmlDebugWatch(parent)
+{
+}
+
+QString QQmlDebugObjectExpressionWatch::expression() const
+{
+ return m_expr;
+}
+
+
+QQmlDebugQuery::QQmlDebugQuery(QObject *parent)
+ : QObject(parent), m_state(Waiting)
+{
+}
+
+QQmlDebugQuery::State QQmlDebugQuery::state() const
+{
+ return m_state;
+}
+
+bool QQmlDebugQuery::isWaiting() const
+{
+ return m_state == Waiting;
+}
+
+void QQmlDebugQuery::setState(State s)
+{
+ if (m_state == s)
+ return;
+ m_state = s;
+ emit stateChanged(m_state);
+}
+
+QQmlDebugEnginesQuery::QQmlDebugEnginesQuery(QObject *parent)
+ : QQmlDebugQuery(parent), m_client(0), m_queryId(-1)
+{
+}
+
+QQmlDebugEnginesQuery::~QQmlDebugEnginesQuery()
+{
+ if (m_client && m_queryId != -1)
+ QQmlEngineDebugPrivate::remove(m_client, this);
+}
+
+QList<QQmlDebugEngineReference> QQmlDebugEnginesQuery::engines() const
+{
+ return m_engines;
+}
+
+QQmlDebugRootContextQuery::QQmlDebugRootContextQuery(QObject *parent)
+ : QQmlDebugQuery(parent), m_client(0), m_queryId(-1)
+{
+}
+
+QQmlDebugRootContextQuery::~QQmlDebugRootContextQuery()
+{
+ if (m_client && m_queryId != -1)
+ QQmlEngineDebugPrivate::remove(m_client, this);
+}
+
+QQmlDebugContextReference QQmlDebugRootContextQuery::rootContext() const
+{
+ return m_context;
+}
+
+QQmlDebugObjectQuery::QQmlDebugObjectQuery(QObject *parent)
+ : QQmlDebugQuery(parent), m_client(0), m_queryId(-1)
+{
+}
+
+QQmlDebugObjectQuery::~QQmlDebugObjectQuery()
+{
+ if (m_client && m_queryId != -1)
+ QQmlEngineDebugPrivate::remove(m_client, this);
+}
+
+QQmlDebugObjectReference QQmlDebugObjectQuery::object() const
+{
+ return m_object;
+}
+
+QQmlDebugExpressionQuery::QQmlDebugExpressionQuery(QObject *parent)
+ : QQmlDebugQuery(parent), m_client(0), m_queryId(-1)
+{
+}
+
+QQmlDebugExpressionQuery::~QQmlDebugExpressionQuery()
+{
+ if (m_client && m_queryId != -1)
+ QQmlEngineDebugPrivate::remove(m_client, this);
+}
+
+QVariant QQmlDebugExpressionQuery::expression() const
+{
+ return m_expr;
+}
+
+QVariant QQmlDebugExpressionQuery::result() const
+{
+ return m_result;
+}
+
+QQmlDebugEngineReference::QQmlDebugEngineReference()
+ : m_debugId(-1)
+{
+}
+
+QQmlDebugEngineReference::QQmlDebugEngineReference(int debugId)
+ : m_debugId(debugId)
+{
+}
+
+QQmlDebugEngineReference::QQmlDebugEngineReference(const QQmlDebugEngineReference &o)
+ : m_debugId(o.m_debugId), m_name(o.m_name)
+{
+}
+
+QQmlDebugEngineReference &
+QQmlDebugEngineReference::operator=(const QQmlDebugEngineReference &o)
+{
+ m_debugId = o.m_debugId; m_name = o.m_name;
+ return *this;
+}
+
+int QQmlDebugEngineReference::debugId() const
+{
+ return m_debugId;
+}
+
+QString QQmlDebugEngineReference::name() const
+{
+ return m_name;
+}
+
+QQmlDebugObjectReference::QQmlDebugObjectReference()
+ : m_debugId(-1), m_contextDebugId(-1)
+{
+}
+
+QQmlDebugObjectReference::QQmlDebugObjectReference(int debugId)
+ : m_debugId(debugId), m_contextDebugId(-1)
+{
+}
+
+QQmlDebugObjectReference::QQmlDebugObjectReference(const QQmlDebugObjectReference &o)
+ : m_debugId(o.m_debugId), m_class(o.m_class), m_idString(o.m_idString),
+ m_name(o.m_name), m_source(o.m_source), m_contextDebugId(o.m_contextDebugId),
+ m_properties(o.m_properties), m_children(o.m_children)
+{
+}
+
+QQmlDebugObjectReference &
+QQmlDebugObjectReference::operator=(const QQmlDebugObjectReference &o)
+{
+ m_debugId = o.m_debugId; m_class = o.m_class; m_idString = o.m_idString;
+ m_name = o.m_name; m_source = o.m_source; m_contextDebugId = o.m_contextDebugId;
+ m_properties = o.m_properties; m_children = o.m_children;
+ return *this;
+}
+
+int QQmlDebugObjectReference::debugId() const
+{
+ return m_debugId;
+}
+
+QString QQmlDebugObjectReference::className() const
+{
+ return m_class;
+}
+
+QString QQmlDebugObjectReference::idString() const
+{
+ return m_idString;
+}
+
+QString QQmlDebugObjectReference::name() const
+{
+ return m_name;
+}
+
+QQmlDebugFileReference QQmlDebugObjectReference::source() const
+{
+ return m_source;
+}
+
+int QQmlDebugObjectReference::contextDebugId() const
+{
+ return m_contextDebugId;
+}
+
+QList<QQmlDebugPropertyReference> QQmlDebugObjectReference::properties() const
+{
+ return m_properties;
+}
+
+QList<QQmlDebugObjectReference> QQmlDebugObjectReference::children() const
+{
+ return m_children;
+}
+
+QQmlDebugContextReference::QQmlDebugContextReference()
+ : m_debugId(-1)
+{
+}
+
+QQmlDebugContextReference::QQmlDebugContextReference(const QQmlDebugContextReference &o)
+ : m_debugId(o.m_debugId), m_name(o.m_name), m_objects(o.m_objects), m_contexts(o.m_contexts)
+{
+}
+
+QQmlDebugContextReference &QQmlDebugContextReference::operator=(const QQmlDebugContextReference &o)
+{
+ m_debugId = o.m_debugId; m_name = o.m_name; m_objects = o.m_objects;
+ m_contexts = o.m_contexts;
+ return *this;
+}
+
+int QQmlDebugContextReference::debugId() const
+{
+ return m_debugId;
+}
+
+QString QQmlDebugContextReference::name() const
+{
+ return m_name;
+}
+
+QList<QQmlDebugObjectReference> QQmlDebugContextReference::objects() const
+{
+ return m_objects;
+}
+
+QList<QQmlDebugContextReference> QQmlDebugContextReference::contexts() const
+{
+ return m_contexts;
+}
+
+QQmlDebugFileReference::QQmlDebugFileReference()
+ : m_lineNumber(-1), m_columnNumber(-1)
+{
+}
+
+QQmlDebugFileReference::QQmlDebugFileReference(const QQmlDebugFileReference &o)
+ : m_url(o.m_url), m_lineNumber(o.m_lineNumber), m_columnNumber(o.m_columnNumber)
+{
+}
+
+QQmlDebugFileReference &QQmlDebugFileReference::operator=(const QQmlDebugFileReference &o)
+{
+ m_url = o.m_url; m_lineNumber = o.m_lineNumber; m_columnNumber = o.m_columnNumber;
+ return *this;
+}
+
+QUrl QQmlDebugFileReference::url() const
+{
+ return m_url;
+}
+
+void QQmlDebugFileReference::setUrl(const QUrl &u)
+{
+ m_url = u;
+}
+
+int QQmlDebugFileReference::lineNumber() const
+{
+ return m_lineNumber;
+}
+
+void QQmlDebugFileReference::setLineNumber(int l)
+{
+ m_lineNumber = l;
+}
+
+int QQmlDebugFileReference::columnNumber() const
+{
+ return m_columnNumber;
+}
+
+void QQmlDebugFileReference::setColumnNumber(int c)
+{
+ m_columnNumber = c;
+}
+
+QQmlDebugPropertyReference::QQmlDebugPropertyReference()
+ : m_objectDebugId(-1), m_hasNotifySignal(false)
+{
+}
+
+QQmlDebugPropertyReference::QQmlDebugPropertyReference(const QQmlDebugPropertyReference &o)
+ : m_objectDebugId(o.m_objectDebugId), m_name(o.m_name), m_value(o.m_value),
+ m_valueTypeName(o.m_valueTypeName), m_binding(o.m_binding),
+ m_hasNotifySignal(o.m_hasNotifySignal)
+{
+}
+
+QQmlDebugPropertyReference &QQmlDebugPropertyReference::operator=(const QQmlDebugPropertyReference &o)
+{
+ m_objectDebugId = o.m_objectDebugId; m_name = o.m_name; m_value = o.m_value;
+ m_valueTypeName = o.m_valueTypeName; m_binding = o.m_binding;
+ m_hasNotifySignal = o.m_hasNotifySignal;
+ return *this;
+}
+
+int QQmlDebugPropertyReference::objectDebugId() const
+{
+ return m_objectDebugId;
+}
+
+QString QQmlDebugPropertyReference::name() const
+{
+ return m_name;
+}
+
+QString QQmlDebugPropertyReference::valueTypeName() const
+{
+ return m_valueTypeName;
+}
+
+QVariant QQmlDebugPropertyReference::value() const
+{
+ return m_value;
+}
+
+QString QQmlDebugPropertyReference::binding() const
+{
+ return m_binding;
+}
+
+bool QQmlDebugPropertyReference::hasNotifySignal() const
+{
+ return m_hasNotifySignal;
+}
+
+QT_END_NAMESPACE
+
diff --git a/src/qml/debugger/qqmlenginedebug_p.h b/src/qml/debugger/qqmlenginedebug_p.h
new file mode 100644
index 0000000000..0562d8755b
--- /dev/null
+++ b/src/qml/debugger/qqmlenginedebug_p.h
@@ -0,0 +1,397 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLENGINEDEBUG_H
+#define QQMLENGINEDEBUG_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qobject.h>
+#include <QtCore/qurl.h>
+#include <QtCore/qvariant.h>
+
+#include <private/qtqmlglobal_p.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+
+class QQmlDebugConnection;
+class QQmlDebugWatch;
+class QQmlDebugPropertyWatch;
+class QQmlDebugObjectExpressionWatch;
+class QQmlDebugEnginesQuery;
+class QQmlDebugRootContextQuery;
+class QQmlDebugObjectQuery;
+class QQmlDebugExpressionQuery;
+class QQmlDebugPropertyReference;
+class QQmlDebugContextReference;
+class QQmlDebugObjectReference;
+class QQmlDebugFileReference;
+class QQmlDebugEngineReference;
+class QQmlEngineDebugPrivate;
+class Q_QML_PRIVATE_EXPORT QQmlEngineDebug : public QObject
+{
+ Q_OBJECT
+public:
+ enum State { NotConnected, Unavailable, Enabled };
+
+ explicit QQmlEngineDebug(QQmlDebugConnection *, QObject * = 0);
+ ~QQmlEngineDebug();
+
+ State state() const;
+
+ QQmlDebugPropertyWatch *addWatch(const QQmlDebugPropertyReference &,
+ QObject *parent = 0);
+ QQmlDebugWatch *addWatch(const QQmlDebugContextReference &, const QString &,
+ QObject *parent = 0);
+ QQmlDebugObjectExpressionWatch *addWatch(const QQmlDebugObjectReference &, const QString &,
+ QObject *parent = 0);
+ QQmlDebugWatch *addWatch(const QQmlDebugObjectReference &,
+ QObject *parent = 0);
+ QQmlDebugWatch *addWatch(const QQmlDebugFileReference &,
+ QObject *parent = 0);
+
+ void removeWatch(QQmlDebugWatch *watch);
+
+ QQmlDebugEnginesQuery *queryAvailableEngines(QObject *parent = 0);
+ QQmlDebugRootContextQuery *queryRootContexts(const QQmlDebugEngineReference &,
+ QObject *parent = 0);
+ QQmlDebugObjectQuery *queryObject(const QQmlDebugObjectReference &,
+ QObject *parent = 0);
+ QQmlDebugObjectQuery *queryObjectRecursive(const QQmlDebugObjectReference &,
+ QObject *parent = 0);
+ QQmlDebugExpressionQuery *queryExpressionResult(int objectDebugId,
+ const QString &expr,
+ QObject *parent = 0);
+ bool setBindingForObject(int objectDebugId, const QString &propertyName,
+ const QVariant &bindingExpression, bool isLiteralValue,
+ QString source = QString(), int line = -1);
+ bool resetBindingForObject(int objectDebugId, const QString &propertyName);
+ bool setMethodBody(int objectDebugId, const QString &methodName, const QString &methodBody);
+
+Q_SIGNALS:
+ void newObjects();
+ void stateChanged(State state);
+
+private:
+ Q_DECLARE_PRIVATE(QQmlEngineDebug)
+};
+
+class Q_QML_PRIVATE_EXPORT QQmlDebugWatch : public QObject
+{
+ Q_OBJECT
+public:
+ enum State { Waiting, Active, Inactive, Dead };
+
+ QQmlDebugWatch(QObject *);
+ ~QQmlDebugWatch();
+
+ int queryId() const;
+ int objectDebugId() const;
+ State state() const;
+
+Q_SIGNALS:
+ void stateChanged(QQmlDebugWatch::State);
+ //void objectChanged(int, const QQmlDebugObjectReference &);
+ //void valueChanged(int, const QVariant &);
+
+ // Server sends value as string if it is a user-type variant
+ void valueChanged(const QByteArray &name, const QVariant &value);
+
+private:
+ friend class QQmlEngineDebug;
+ friend class QQmlEngineDebugPrivate;
+ void setState(State);
+ State m_state;
+ int m_queryId;
+ QQmlEngineDebug *m_client;
+ int m_objectDebugId;
+};
+
+class Q_QML_PRIVATE_EXPORT QQmlDebugPropertyWatch : public QQmlDebugWatch
+{
+ Q_OBJECT
+public:
+ QQmlDebugPropertyWatch(QObject *parent);
+
+ QString name() const;
+
+private:
+ friend class QQmlEngineDebug;
+ QString m_name;
+};
+
+class Q_QML_PRIVATE_EXPORT QQmlDebugObjectExpressionWatch : public QQmlDebugWatch
+{
+ Q_OBJECT
+public:
+ QQmlDebugObjectExpressionWatch(QObject *parent);
+
+ QString expression() const;
+
+private:
+ friend class QQmlEngineDebug;
+ QString m_expr;
+ int m_debugId;
+};
+
+
+class Q_QML_PRIVATE_EXPORT QQmlDebugQuery : public QObject
+{
+ Q_OBJECT
+public:
+ enum State { Waiting, Error, Completed };
+
+ State state() const;
+ bool isWaiting() const;
+
+Q_SIGNALS:
+ void stateChanged(QQmlDebugQuery::State);
+
+protected:
+ QQmlDebugQuery(QObject *);
+
+private:
+ friend class QQmlEngineDebug;
+ friend class QQmlEngineDebugPrivate;
+ void setState(State);
+ State m_state;
+};
+
+class Q_QML_PRIVATE_EXPORT QQmlDebugFileReference
+{
+public:
+ QQmlDebugFileReference();
+ QQmlDebugFileReference(const QQmlDebugFileReference &);
+ QQmlDebugFileReference &operator=(const QQmlDebugFileReference &);
+
+ QUrl url() const;
+ void setUrl(const QUrl &);
+ int lineNumber() const;
+ void setLineNumber(int);
+ int columnNumber() const;
+ void setColumnNumber(int);
+
+private:
+ friend class QQmlEngineDebugPrivate;
+ QUrl m_url;
+ int m_lineNumber;
+ int m_columnNumber;
+};
+
+class Q_QML_PRIVATE_EXPORT QQmlDebugEngineReference
+{
+public:
+ QQmlDebugEngineReference();
+ QQmlDebugEngineReference(int);
+ QQmlDebugEngineReference(const QQmlDebugEngineReference &);
+ QQmlDebugEngineReference &operator=(const QQmlDebugEngineReference &);
+
+ int debugId() const;
+ QString name() const;
+
+private:
+ friend class QQmlEngineDebugPrivate;
+ int m_debugId;
+ QString m_name;
+};
+
+class Q_QML_PRIVATE_EXPORT QQmlDebugObjectReference
+{
+public:
+ QQmlDebugObjectReference();
+ QQmlDebugObjectReference(int);
+ QQmlDebugObjectReference(const QQmlDebugObjectReference &);
+ QQmlDebugObjectReference &operator=(const QQmlDebugObjectReference &);
+
+ int debugId() const;
+ QString className() const;
+ QString idString() const;
+ QString name() const;
+
+ QQmlDebugFileReference source() const;
+ int contextDebugId() const;
+
+ QList<QQmlDebugPropertyReference> properties() const;
+ QList<QQmlDebugObjectReference> children() const;
+
+private:
+ friend class QQmlEngineDebugPrivate;
+ int m_debugId;
+ QString m_class;
+ QString m_idString;
+ QString m_name;
+ QQmlDebugFileReference m_source;
+ int m_contextDebugId;
+ QList<QQmlDebugPropertyReference> m_properties;
+ QList<QQmlDebugObjectReference> m_children;
+};
+
+class Q_QML_PRIVATE_EXPORT QQmlDebugContextReference
+{
+public:
+ QQmlDebugContextReference();
+ QQmlDebugContextReference(const QQmlDebugContextReference &);
+ QQmlDebugContextReference &operator=(const QQmlDebugContextReference &);
+
+ int debugId() const;
+ QString name() const;
+
+ QList<QQmlDebugObjectReference> objects() const;
+ QList<QQmlDebugContextReference> contexts() const;
+
+private:
+ friend class QQmlEngineDebugPrivate;
+ int m_debugId;
+ QString m_name;
+ QList<QQmlDebugObjectReference> m_objects;
+ QList<QQmlDebugContextReference> m_contexts;
+};
+
+class Q_QML_PRIVATE_EXPORT QQmlDebugPropertyReference
+{
+public:
+ QQmlDebugPropertyReference();
+ QQmlDebugPropertyReference(const QQmlDebugPropertyReference &);
+ QQmlDebugPropertyReference &operator=(const QQmlDebugPropertyReference &);
+
+ int objectDebugId() const;
+ QString name() const;
+ QVariant value() const;
+ QString valueTypeName() const;
+ QString binding() const;
+ bool hasNotifySignal() const;
+
+private:
+ friend class QQmlEngineDebugPrivate;
+ int m_objectDebugId;
+ QString m_name;
+ QVariant m_value;
+ QString m_valueTypeName;
+ QString m_binding;
+ bool m_hasNotifySignal;
+};
+
+
+class Q_QML_PRIVATE_EXPORT QQmlDebugEnginesQuery : public QQmlDebugQuery
+{
+ Q_OBJECT
+public:
+ virtual ~QQmlDebugEnginesQuery();
+ QList<QQmlDebugEngineReference> engines() const;
+private:
+ friend class QQmlEngineDebug;
+ friend class QQmlEngineDebugPrivate;
+ QQmlDebugEnginesQuery(QObject *);
+ QQmlEngineDebug *m_client;
+ int m_queryId;
+ QList<QQmlDebugEngineReference> m_engines;
+};
+
+class Q_QML_PRIVATE_EXPORT QQmlDebugRootContextQuery : public QQmlDebugQuery
+{
+ Q_OBJECT
+public:
+ virtual ~QQmlDebugRootContextQuery();
+ QQmlDebugContextReference rootContext() const;
+private:
+ friend class QQmlEngineDebug;
+ friend class QQmlEngineDebugPrivate;
+ QQmlDebugRootContextQuery(QObject *);
+ QQmlEngineDebug *m_client;
+ int m_queryId;
+ QQmlDebugContextReference m_context;
+};
+
+class Q_QML_PRIVATE_EXPORT QQmlDebugObjectQuery : public QQmlDebugQuery
+{
+ Q_OBJECT
+public:
+ virtual ~QQmlDebugObjectQuery();
+ QQmlDebugObjectReference object() const;
+private:
+ friend class QQmlEngineDebug;
+ friend class QQmlEngineDebugPrivate;
+ QQmlDebugObjectQuery(QObject *);
+ QQmlEngineDebug *m_client;
+ int m_queryId;
+ QQmlDebugObjectReference m_object;
+
+};
+
+class Q_QML_PRIVATE_EXPORT QQmlDebugExpressionQuery : public QQmlDebugQuery
+{
+ Q_OBJECT
+public:
+ virtual ~QQmlDebugExpressionQuery();
+ QVariant expression() const;
+ QVariant result() const;
+private:
+ friend class QQmlEngineDebug;
+ friend class QQmlEngineDebugPrivate;
+ QQmlDebugExpressionQuery(QObject *);
+ QQmlEngineDebug *m_client;
+ int m_queryId;
+ QVariant m_expr;
+ QVariant m_result;
+};
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(QQmlDebugEngineReference)
+Q_DECLARE_METATYPE(QQmlDebugObjectReference)
+Q_DECLARE_METATYPE(QQmlDebugContextReference)
+Q_DECLARE_METATYPE(QQmlDebugPropertyReference)
+
+QT_END_HEADER
+
+#endif // QQMLENGINEDEBUG_H
diff --git a/src/qml/debugger/qqmlenginedebugservice.cpp b/src/qml/debugger/qqmlenginedebugservice.cpp
new file mode 100644
index 0000000000..be2e826bdf
--- /dev/null
+++ b/src/qml/debugger/qqmlenginedebugservice.cpp
@@ -0,0 +1,733 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qqmlenginedebugservice_p.h"
+
+#include "qqmldebugstatesdelegate_p.h"
+#include <private/qqmlboundsignal_p.h>
+#include <qqmlengine.h>
+#include <private/qqmlmetatype_p.h>
+#include <qqmlproperty.h>
+#include <private/qqmlproperty_p.h>
+#include <private/qqmlbinding_p.h>
+#include <private/qqmlcontext_p.h>
+#include <private/qqmlwatcher_p.h>
+#include <private/qqmlvaluetype_p.h>
+#include <private/qqmlvmemetaobject_p.h>
+#include <private/qqmlexpression_p.h>
+
+#include <QtCore/qdebug.h>
+#include <QtCore/qmetaobject.h>
+
+QT_BEGIN_NAMESPACE
+
+Q_GLOBAL_STATIC(QQmlEngineDebugService, qmlEngineDebugService);
+
+QQmlEngineDebugService *QQmlEngineDebugService::instance()
+{
+ return qmlEngineDebugService();
+}
+
+QQmlEngineDebugService::QQmlEngineDebugService(QObject *parent)
+ : QQmlDebugService(QLatin1String("QQmlEngine"), 1, parent),
+ m_watch(new QQmlWatcher(this)),
+ m_statesDelegate(0)
+{
+ QObject::connect(m_watch, SIGNAL(propertyChanged(int,int,QMetaProperty,QVariant)),
+ this, SLOT(propertyChanged(int,int,QMetaProperty,QVariant)));
+
+ registerService();
+}
+
+QQmlEngineDebugService::~QQmlEngineDebugService()
+{
+ delete m_statesDelegate;
+}
+
+QDataStream &operator<<(QDataStream &ds,
+ const QQmlEngineDebugService::QQmlObjectData &data)
+{
+ ds << data.url << data.lineNumber << data.columnNumber << data.idString
+ << data.objectName << data.objectType << data.objectId << data.contextId;
+ return ds;
+}
+
+QDataStream &operator>>(QDataStream &ds,
+ QQmlEngineDebugService::QQmlObjectData &data)
+{
+ ds >> data.url >> data.lineNumber >> data.columnNumber >> data.idString
+ >> data.objectName >> data.objectType >> data.objectId >> data.contextId;
+ return ds;
+}
+
+QDataStream &operator<<(QDataStream &ds,
+ const QQmlEngineDebugService::QQmlObjectProperty &data)
+{
+ ds << (int)data.type << data.name << data.value << data.valueTypeName
+ << data.binding << data.hasNotifySignal;
+ return ds;
+}
+
+QDataStream &operator>>(QDataStream &ds,
+ QQmlEngineDebugService::QQmlObjectProperty &data)
+{
+ int type;
+ ds >> type >> data.name >> data.value >> data.valueTypeName
+ >> data.binding >> data.hasNotifySignal;
+ data.type = (QQmlEngineDebugService::QQmlObjectProperty::Type)type;
+ return ds;
+}
+
+static inline bool isSignalPropertyName(const QString &signalName)
+{
+ // see QmlCompiler::isSignalPropertyName
+ return signalName.length() >= 3 && signalName.startsWith(QLatin1String("on")) &&
+ signalName.at(2).isLetter() && signalName.at(2).isUpper();
+}
+
+static bool hasValidSignal(QObject *object, const QString &propertyName)
+{
+ if (!isSignalPropertyName(propertyName))
+ return false;
+
+ QString signalName = propertyName.mid(2);
+ signalName[0] = signalName.at(0).toLower();
+
+ int sigIdx = QQmlPropertyPrivate::findSignalByName(object->metaObject(), signalName.toLatin1()).methodIndex();
+
+ if (sigIdx == -1)
+ return false;
+
+ return true;
+}
+
+QQmlEngineDebugService::QQmlObjectProperty
+QQmlEngineDebugService::propertyData(QObject *obj, int propIdx)
+{
+ QQmlObjectProperty rv;
+
+ QMetaProperty prop = obj->metaObject()->property(propIdx);
+
+ rv.type = QQmlObjectProperty::Unknown;
+ rv.valueTypeName = QString::fromUtf8(prop.typeName());
+ rv.name = QString::fromUtf8(prop.name());
+ rv.hasNotifySignal = prop.hasNotifySignal();
+ QQmlAbstractBinding *binding =
+ QQmlPropertyPrivate::binding(QQmlProperty(obj, rv.name));
+ if (binding)
+ rv.binding = binding->expression();
+
+ if (QQmlValueTypeFactory::isValueType(prop.userType())) {
+ rv.type = QQmlObjectProperty::Basic;
+ } else if (QQmlMetaType::isQObject(prop.userType())) {
+ rv.type = QQmlObjectProperty::Object;
+ } else if (QQmlMetaType::isList(prop.userType())) {
+ rv.type = QQmlObjectProperty::List;
+ }
+
+ QVariant value;
+ if (rv.type != QQmlObjectProperty::Unknown && prop.userType() != 0) {
+ value = prop.read(obj);
+ }
+ rv.value = valueContents(value);
+
+ return rv;
+}
+
+QVariant QQmlEngineDebugService::valueContents(const QVariant &value) const
+{
+ int userType = value.userType();
+
+ //QObject * is not streamable.
+ //Convert all such instances to a String value
+
+ if (value.type() == QVariant::List) {
+ QVariantList contents;
+ QVariantList list = value.toList();
+ int count = list.size();
+ for (int i = 0; i < count; i++)
+ contents << valueContents(list.at(i));
+ return contents;
+ }
+
+ if (value.type() == QVariant::Map) {
+ QVariantMap contents;
+ QMapIterator<QString, QVariant> i(value.toMap());
+ while (i.hasNext()) {
+ i.next();
+ contents.insert(i.key(), valueContents(i.value()));
+ }
+ return contents;
+ }
+
+ if (QQmlValueTypeFactory::isValueType(userType))
+ return value;
+
+ if (QQmlMetaType::isQObject(userType)) {
+ QObject *o = QQmlMetaType::toQObject(value);
+ if (o) {
+ QString name = o->objectName();
+ if (name.isEmpty())
+ name = QLatin1String("<unnamed object>");
+ return name;
+ }
+ }
+
+ return QLatin1String("<unknown value>");
+}
+
+void QQmlEngineDebugService::buildObjectDump(QDataStream &message,
+ QObject *object, bool recur, bool dumpProperties)
+{
+ message << objectData(object);
+
+ QObjectList children = object->children();
+
+ int childrenCount = children.count();
+ for (int ii = 0; ii < children.count(); ++ii) {
+ if (qobject_cast<QQmlContext*>(children[ii]) || QQmlBoundSignal::cast(children[ii]))
+ --childrenCount;
+ }
+
+ message << childrenCount << recur;
+
+ QList<QQmlObjectProperty> fakeProperties;
+
+ for (int ii = 0; ii < children.count(); ++ii) {
+ QObject *child = children.at(ii);
+ if (qobject_cast<QQmlContext*>(child))
+ continue;
+ QQmlBoundSignal *signal = QQmlBoundSignal::cast(child);
+ if (signal) {
+ if (!dumpProperties)
+ continue;
+ QQmlObjectProperty prop;
+ prop.type = QQmlObjectProperty::SignalProperty;
+ prop.hasNotifySignal = false;
+ QQmlExpression *expr = signal->expression();
+ if (expr) {
+ prop.value = expr->expression();
+ QObject *scope = expr->scopeObject();
+ if (scope) {
+ QString sig = QLatin1String(scope->metaObject()->method(signal->index()).signature());
+ int lparen = sig.indexOf(QLatin1Char('('));
+ if (lparen >= 0) {
+ QString methodName = sig.mid(0, lparen);
+ prop.name = QLatin1String("on") + methodName[0].toUpper()
+ + methodName.mid(1);
+ }
+ }
+ }
+ fakeProperties << prop;
+ } else {
+ if (recur)
+ buildObjectDump(message, child, recur, dumpProperties);
+ else
+ message << objectData(child);
+ }
+ }
+
+ if (!dumpProperties) {
+ message << 0;
+ return;
+ }
+
+ QList<int> propertyIndexes;
+ for (int ii = 0; ii < object->metaObject()->propertyCount(); ++ii) {
+ if (object->metaObject()->property(ii).isScriptable())
+ propertyIndexes << ii;
+ }
+
+ message << propertyIndexes.size() + fakeProperties.count();
+
+ for (int ii = 0; ii < propertyIndexes.size(); ++ii)
+ message << propertyData(object, propertyIndexes.at(ii));
+
+ for (int ii = 0; ii < fakeProperties.count(); ++ii)
+ message << fakeProperties[ii];
+}
+
+void QQmlEngineDebugService::prepareDeferredObjects(QObject *obj)
+{
+ qmlExecuteDeferred(obj);
+
+ QObjectList children = obj->children();
+ for (int ii = 0; ii < children.count(); ++ii) {
+ QObject *child = children.at(ii);
+ prepareDeferredObjects(child);
+ }
+
+}
+
+void QQmlEngineDebugService::buildObjectList(QDataStream &message, QQmlContext *ctxt)
+{
+ QQmlContextData *p = QQmlContextData::get(ctxt);
+
+ QString ctxtName = ctxt->objectName();
+ int ctxtId = QQmlDebugService::idForObject(ctxt);
+
+ message << ctxtName << ctxtId;
+
+ int count = 0;
+
+ QQmlContextData *child = p->childContexts;
+ while (child) {
+ ++count;
+ child = child->nextChild;
+ }
+
+ message << count;
+
+ child = p->childContexts;
+ while (child) {
+ buildObjectList(message, child->asQQmlContext());
+ child = child->nextChild;
+ }
+
+ // Clean deleted objects
+ QQmlContextPrivate *ctxtPriv = QQmlContextPrivate::get(ctxt);
+ for (int ii = 0; ii < ctxtPriv->instances.count(); ++ii) {
+ if (!ctxtPriv->instances.at(ii)) {
+ ctxtPriv->instances.removeAt(ii);
+ --ii;
+ }
+ }
+
+ message << ctxtPriv->instances.count();
+ for (int ii = 0; ii < ctxtPriv->instances.count(); ++ii) {
+ message << objectData(ctxtPriv->instances.at(ii));
+ }
+}
+
+void QQmlEngineDebugService::buildStatesList(QQmlContext *ctxt, bool cleanList)
+{
+ if (m_statesDelegate)
+ m_statesDelegate->buildStatesList(ctxt, cleanList);
+}
+
+QQmlEngineDebugService::QQmlObjectData
+QQmlEngineDebugService::objectData(QObject *object)
+{
+ QQmlData *ddata = QQmlData::get(object);
+ QQmlObjectData rv;
+ if (ddata && ddata->outerContext) {
+ rv.url = ddata->outerContext->url;
+ rv.lineNumber = ddata->lineNumber;
+ rv.columnNumber = ddata->columnNumber;
+ } else {
+ rv.lineNumber = -1;
+ rv.columnNumber = -1;
+ }
+
+ QQmlContext *context = qmlContext(object);
+ if (context) {
+ QQmlContextData *cdata = QQmlContextData::get(context);
+ if (cdata)
+ rv.idString = cdata->findObjectId(object);
+ }
+
+ rv.objectName = object->objectName();
+ rv.objectId = QQmlDebugService::idForObject(object);
+ rv.contextId = QQmlDebugService::idForObject(qmlContext(object));
+
+ QQmlType *type = QQmlMetaType::qmlType(object->metaObject());
+ if (type) {
+ QString typeName = type->qmlTypeName();
+ int lastSlash = typeName.lastIndexOf(QLatin1Char('/'));
+ rv.objectType = lastSlash < 0 ? typeName : typeName.mid(lastSlash+1);
+ } else {
+ rv.objectType = QString::fromUtf8(object->metaObject()->className());
+ int marker = rv.objectType.indexOf(QLatin1String("_QMLTYPE_"));
+ if (marker != -1)
+ rv.objectType = rv.objectType.left(marker);
+ }
+
+ return rv;
+}
+
+void QQmlEngineDebugService::messageReceived(const QByteArray &message)
+{
+ QMetaObject::invokeMethod(this, "processMessage", Qt::QueuedConnection, Q_ARG(QByteArray, message));
+}
+
+void QQmlEngineDebugService::processMessage(const QByteArray &message)
+{
+ QDataStream ds(message);
+
+ QByteArray type;
+ ds >> type;
+
+ if (type == "LIST_ENGINES") {
+ int queryId;
+ ds >> queryId;
+
+ QByteArray reply;
+ QDataStream rs(&reply, QIODevice::WriteOnly);
+ rs << QByteArray("LIST_ENGINES_R");
+ rs << queryId << m_engines.count();
+
+ for (int ii = 0; ii < m_engines.count(); ++ii) {
+ QQmlEngine *engine = m_engines.at(ii);
+
+ QString engineName = engine->objectName();
+ int engineId = QQmlDebugService::idForObject(engine);
+
+ rs << engineName << engineId;
+ }
+
+ sendMessage(reply);
+ } else if (type == "LIST_OBJECTS") {
+ int queryId;
+ int engineId = -1;
+ ds >> queryId >> engineId;
+
+ QQmlEngine *engine =
+ qobject_cast<QQmlEngine *>(QQmlDebugService::objectForId(engineId));
+
+ QByteArray reply;
+ QDataStream rs(&reply, QIODevice::WriteOnly);
+ rs << QByteArray("LIST_OBJECTS_R") << queryId;
+
+ if (engine) {
+ buildObjectList(rs, engine->rootContext());
+ buildStatesList(engine->rootContext(), true);
+ }
+
+ sendMessage(reply);
+ } else if (type == "FETCH_OBJECT") {
+ int queryId;
+ int objectId;
+ bool recurse;
+ bool dumpProperties = true;
+
+ ds >> queryId >> objectId >> recurse >> dumpProperties;
+
+ QObject *object = QQmlDebugService::objectForId(objectId);
+
+ QByteArray reply;
+ QDataStream rs(&reply, QIODevice::WriteOnly);
+ rs << QByteArray("FETCH_OBJECT_R") << queryId;
+
+ if (object) {
+ if (recurse)
+ prepareDeferredObjects(object);
+ buildObjectDump(rs, object, recurse, dumpProperties);
+ }
+
+ sendMessage(reply);
+ } else if (type == "WATCH_OBJECT") {
+ int queryId;
+ int objectId;
+
+ ds >> queryId >> objectId;
+ bool ok = m_watch->addWatch(queryId, objectId);
+
+ QByteArray reply;
+ QDataStream rs(&reply, QIODevice::WriteOnly);
+ rs << QByteArray("WATCH_OBJECT_R") << queryId << ok;
+
+ sendMessage(reply);
+ } else if (type == "WATCH_PROPERTY") {
+ int queryId;
+ int objectId;
+ QByteArray property;
+
+ ds >> queryId >> objectId >> property;
+ bool ok = m_watch->addWatch(queryId, objectId, property);
+
+ QByteArray reply;
+ QDataStream rs(&reply, QIODevice::WriteOnly);
+ rs << QByteArray("WATCH_PROPERTY_R") << queryId << ok;
+
+ sendMessage(reply);
+ } else if (type == "WATCH_EXPR_OBJECT") {
+ int queryId;
+ int debugId;
+ QString expr;
+
+ ds >> queryId >> debugId >> expr;
+ bool ok = m_watch->addWatch(queryId, debugId, expr);
+
+ QByteArray reply;
+ QDataStream rs(&reply, QIODevice::WriteOnly);
+ rs << QByteArray("WATCH_EXPR_OBJECT_R") << queryId << ok;
+ sendMessage(reply);
+ } else if (type == "NO_WATCH") {
+ int queryId;
+
+ ds >> queryId;
+ m_watch->removeWatch(queryId);
+ } else if (type == "EVAL_EXPRESSION") {
+ int queryId;
+ int objectId;
+ QString expr;
+
+ ds >> queryId >> objectId >> expr;
+
+ QObject *object = QQmlDebugService::objectForId(objectId);
+ QQmlContext *context = qmlContext(object);
+ QVariant result;
+ if (object && context) {
+ QQmlExpression exprObj(context, object, expr);
+ bool undefined = false;
+ QVariant value = exprObj.evaluate(&undefined);
+ if (undefined)
+ result = QLatin1String("<undefined>");
+ else
+ result = valueContents(value);
+ } else {
+ result = QLatin1String("<unknown context>");
+ }
+
+ QByteArray reply;
+ QDataStream rs(&reply, QIODevice::WriteOnly);
+ rs << QByteArray("EVAL_EXPRESSION_R") << queryId << result;
+
+ sendMessage(reply);
+ } else if (type == "SET_BINDING") {
+ int objectId;
+ QString propertyName;
+ QVariant expr;
+ bool isLiteralValue;
+ QString filename;
+ int line;
+ ds >> objectId >> propertyName >> expr >> isLiteralValue;
+ if (!ds.atEnd()) { // backward compatibility from 2.1, 2.2
+ ds >> filename >> line;
+ }
+ setBinding(objectId, propertyName, expr, isLiteralValue, filename, line);
+ } else if (type == "RESET_BINDING") {
+ int objectId;
+ QString propertyName;
+ ds >> objectId >> propertyName;
+ resetBinding(objectId, propertyName);
+ } else if (type == "SET_METHOD_BODY") {
+ int objectId;
+ QString methodName;
+ QString methodBody;
+ ds >> objectId >> methodName >> methodBody;
+ setMethodBody(objectId, methodName, methodBody);
+ }
+}
+
+void QQmlEngineDebugService::setBinding(int objectId,
+ const QString &propertyName,
+ const QVariant &expression,
+ bool isLiteralValue,
+ QString filename,
+ int line,
+ int column)
+{
+ QObject *object = objectForId(objectId);
+ QQmlContext *context = qmlContext(object);
+
+ if (object && context) {
+ QQmlProperty property(object, propertyName, context);
+ if (property.isValid()) {
+
+ bool inBaseState = true;
+ if (m_statesDelegate) {
+ m_statesDelegate->updateBinding(context, property, expression, isLiteralValue,
+ filename, line, column, &inBaseState);
+ }
+
+ if (inBaseState) {
+ if (isLiteralValue) {
+ property.write(expression);
+ } else if (hasValidSignal(object, propertyName)) {
+ QQmlExpression *qmlExpression = new QQmlExpression(context, object, expression.toString());
+ QQmlPropertyPrivate::setSignalExpression(property, qmlExpression);
+ qmlExpression->setSourceLocation(filename, line, column);
+ } else if (property.isProperty()) {
+ QQmlBinding *binding = new QQmlBinding(expression.toString(), object, context);
+ binding->setTarget(property);
+ binding->setSourceLocation(filename, line, column);
+ binding->setNotifyOnValueChanged(true);
+ QQmlAbstractBinding *oldBinding = QQmlPropertyPrivate::setBinding(property, binding);
+ if (oldBinding)
+ oldBinding->destroy();
+ binding->update();
+ } else {
+ qWarning() << "QQmlEngineDebugService::setBinding: unable to set property" << propertyName << "on object" << object;
+ }
+ }
+
+ } else {
+ // not a valid property
+ bool ok = false;
+ if (m_statesDelegate)
+ ok = m_statesDelegate->setBindingForInvalidProperty(object, propertyName, expression, isLiteralValue);
+ if (!ok)
+ qWarning() << "QQmlEngineDebugService::setBinding: unable to set property" << propertyName << "on object" << object;
+ }
+ }
+}
+
+void QQmlEngineDebugService::resetBinding(int objectId, const QString &propertyName)
+{
+ QObject *object = objectForId(objectId);
+ QQmlContext *context = qmlContext(object);
+
+ if (object && context) {
+ if (object->property(propertyName.toLatin1()).isValid()) {
+ QQmlProperty property(object, propertyName);
+ QQmlAbstractBinding *oldBinding = QQmlPropertyPrivate::binding(property);
+ if (oldBinding) {
+ QQmlAbstractBinding *oldBinding = QQmlPropertyPrivate::setBinding(property, 0);
+ if (oldBinding)
+ oldBinding->destroy();
+ }
+ if (property.isResettable()) {
+ // Note: this will reset the property in any case, without regard to states
+ // Right now almost no QQuickItem has reset methods for its properties (with the
+ // notable exception of QQuickAnchors), so this is not a big issue
+ // later on, setBinding does take states into account
+ property.reset();
+ } else {
+ // overwrite with default value
+ if (QQmlType *objType = QQmlMetaType::qmlType(object->metaObject())) {
+ if (QObject *emptyObject = objType->create()) {
+ if (emptyObject->property(propertyName.toLatin1()).isValid()) {
+ QVariant defaultValue = QQmlProperty(emptyObject, propertyName).read();
+ if (defaultValue.isValid()) {
+ setBinding(objectId, propertyName, defaultValue, true);
+ }
+ }
+ delete emptyObject;
+ }
+ }
+ }
+ } else if (hasValidSignal(object, propertyName)) {
+ QQmlProperty property(object, propertyName, context);
+ QQmlPropertyPrivate::setSignalExpression(property, 0);
+ } else {
+ if (m_statesDelegate)
+ m_statesDelegate->resetBindingForInvalidProperty(object, propertyName);
+ }
+ }
+}
+
+void QQmlEngineDebugService::setMethodBody(int objectId, const QString &method, const QString &body)
+{
+ QObject *object = objectForId(objectId);
+ QQmlContext *context = qmlContext(object);
+ if (!object || !context || !context->engine())
+ return;
+ QQmlContextData *contextData = QQmlContextData::get(context);
+ if (!contextData)
+ return;
+
+ QQmlPropertyData dummy;
+ QQmlPropertyData *prop =
+ QQmlPropertyCache::property(context->engine(), object, method, dummy);
+
+ if (!prop || !prop->isVMEFunction())
+ return;
+
+ QMetaMethod metaMethod = object->metaObject()->method(prop->coreIndex);
+ QList<QByteArray> paramNames = metaMethod.parameterNames();
+
+ QString paramStr;
+ for (int ii = 0; ii < paramNames.count(); ++ii) {
+ if (ii != 0) paramStr.append(QLatin1String(","));
+ paramStr.append(QString::fromUtf8(paramNames.at(ii)));
+ }
+
+ QString jsfunction = QLatin1String("(function ") + method + QLatin1String("(") + paramStr +
+ QLatin1String(") {");
+ jsfunction += body;
+ jsfunction += QLatin1String("\n})");
+
+ QQmlVMEMetaObject *vmeMetaObject =
+ static_cast<QQmlVMEMetaObject*>(QObjectPrivate::get(object)->metaObject);
+ Q_ASSERT(vmeMetaObject); // the fact we found the property above should guarentee this
+
+ int lineNumber = vmeMetaObject->vmeMethodLineNumber(prop->coreIndex);
+ vmeMetaObject->setVmeMethod(prop->coreIndex, QQmlExpressionPrivate::evalFunction(contextData, object, jsfunction, contextData->url.toString(), lineNumber));
+}
+
+void QQmlEngineDebugService::propertyChanged(int id, int objectId, const QMetaProperty &property, const QVariant &value)
+{
+ QByteArray reply;
+ QDataStream rs(&reply, QIODevice::WriteOnly);
+
+ rs << QByteArray("UPDATE_WATCH") << id << objectId << QByteArray(property.name()) << valueContents(value);
+
+ sendMessage(reply);
+}
+
+void QQmlEngineDebugService::addEngine(QQmlEngine *engine)
+{
+ Q_ASSERT(engine);
+ Q_ASSERT(!m_engines.contains(engine));
+
+ m_engines.append(engine);
+}
+
+void QQmlEngineDebugService::remEngine(QQmlEngine *engine)
+{
+ Q_ASSERT(engine);
+ Q_ASSERT(m_engines.contains(engine));
+
+ m_engines.removeAll(engine);
+}
+
+void QQmlEngineDebugService::objectCreated(QQmlEngine *engine, QObject *object)
+{
+ Q_ASSERT(engine);
+ Q_ASSERT(m_engines.contains(engine));
+
+ int engineId = QQmlDebugService::idForObject(engine);
+ int objectId = QQmlDebugService::idForObject(object);
+
+ QByteArray reply;
+ QDataStream rs(&reply, QIODevice::WriteOnly);
+
+ rs << QByteArray("OBJECT_CREATED") << engineId << objectId;
+ sendMessage(reply);
+}
+
+void QQmlEngineDebugService::setStatesDelegate(QQmlDebugStatesDelegate *delegate)
+{
+ m_statesDelegate = delegate;
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/debugger/qqmlenginedebugservice_p.h b/src/qml/debugger/qqmlenginedebugservice_p.h
new file mode 100644
index 0000000000..1a92801fcc
--- /dev/null
+++ b/src/qml/debugger/qqmlenginedebugservice_p.h
@@ -0,0 +1,136 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLENGINEDEBUGSERVICE_P_H
+#define QQMLENGINEDEBUGSERVICE_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qqmldebugservice_p.h>
+
+#include <QtCore/qurl.h>
+#include <QtCore/qvariant.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQmlEngine;
+class QQmlContext;
+class QQmlWatcher;
+class QDataStream;
+class QQmlDebugStatesDelegate;
+
+class Q_QML_PRIVATE_EXPORT QQmlEngineDebugService : public QQmlDebugService
+{
+ Q_OBJECT
+public:
+ QQmlEngineDebugService(QObject * = 0);
+ ~QQmlEngineDebugService();
+
+ struct QQmlObjectData {
+ QUrl url;
+ int lineNumber;
+ int columnNumber;
+ QString idString;
+ QString objectName;
+ QString objectType;
+ int objectId;
+ int contextId;
+ };
+
+ struct QQmlObjectProperty {
+ enum Type { Unknown, Basic, Object, List, SignalProperty };
+ Type type;
+ QString name;
+ QVariant value;
+ QString valueTypeName;
+ QString binding;
+ bool hasNotifySignal;
+ };
+
+ void addEngine(QQmlEngine *);
+ void remEngine(QQmlEngine *);
+ void objectCreated(QQmlEngine *, QObject *);
+
+ void setStatesDelegate(QQmlDebugStatesDelegate *);
+
+ static QQmlEngineDebugService *instance();
+
+protected:
+ virtual void messageReceived(const QByteArray &);
+
+private Q_SLOTS:
+ void processMessage(const QByteArray &msg);
+ void propertyChanged(int id, int objectId, const QMetaProperty &property, const QVariant &value);
+
+private:
+ void prepareDeferredObjects(QObject *);
+ void buildObjectList(QDataStream &, QQmlContext *);
+ void buildObjectDump(QDataStream &, QObject *, bool, bool);
+ void buildStatesList(QQmlContext *, bool);
+ QQmlObjectData objectData(QObject *);
+ QQmlObjectProperty propertyData(QObject *, int);
+ QVariant valueContents(const QVariant &defaultValue) const;
+ void setBinding(int objectId, const QString &propertyName, const QVariant &expression, bool isLiteralValue, QString filename = QString(), int line = -1, int column = 0);
+ void resetBinding(int objectId, const QString &propertyName);
+ void setMethodBody(int objectId, const QString &method, const QString &body);
+
+ QList<QQmlEngine *> m_engines;
+ QQmlWatcher *m_watch;
+ QQmlDebugStatesDelegate *m_statesDelegate;
+};
+Q_QML_PRIVATE_EXPORT QDataStream &operator<<(QDataStream &, const QQmlEngineDebugService::QQmlObjectData &);
+Q_QML_PRIVATE_EXPORT QDataStream &operator>>(QDataStream &, QQmlEngineDebugService::QQmlObjectData &);
+Q_QML_PRIVATE_EXPORT QDataStream &operator<<(QDataStream &, const QQmlEngineDebugService::QQmlObjectProperty &);
+Q_QML_PRIVATE_EXPORT QDataStream &operator>>(QDataStream &, QQmlEngineDebugService::QQmlObjectProperty &);
+
+QT_END_NAMESPACE
+
+#endif // QQMLENGINEDEBUGSERVICE_P_H
+
diff --git a/src/qml/debugger/qqmlinspectorinterface_p.h b/src/qml/debugger/qqmlinspectorinterface_p.h
new file mode 100644
index 0000000000..7f52dffa2e
--- /dev/null
+++ b/src/qml/debugger/qqmlinspectorinterface_p.h
@@ -0,0 +1,83 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLINSPECTORINTERFACE_H
+#define QQMLINSPECTORINTERFACE_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtQml/qtqmlglobal.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+
+class Q_QML_EXPORT QQmlInspectorInterface
+{
+public:
+ QQmlInspectorInterface() {}
+ virtual ~QQmlInspectorInterface() {}
+
+ virtual bool canHandleView(QObject *view) = 0;
+
+ virtual void activate(QObject *view) = 0;
+ virtual void deactivate() = 0;
+
+ virtual void clientMessage(const QByteArray &message) = 0;
+};
+
+Q_DECLARE_INTERFACE(QQmlInspectorInterface, "com.trolltech.Qt.QQmlInspectorInterface/1.0")
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QQMLINSPECTORINTERFACE_H
diff --git a/src/qml/debugger/qqmlinspectorservice.cpp b/src/qml/debugger/qqmlinspectorservice.cpp
new file mode 100644
index 0000000000..508d12eefa
--- /dev/null
+++ b/src/qml/debugger/qqmlinspectorservice.cpp
@@ -0,0 +1,186 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qqmlinspectorservice_p.h"
+#include "qqmlinspectorinterface_p.h"
+#include "qqmldebugserver_p.h"
+
+#include <private/qqmlglobal_p.h>
+
+#include <QtCore/QCoreApplication>
+#include <QtCore/QDebug>
+#include <QtCore/QDir>
+#include <QtCore/QPluginLoader>
+
+// print detailed information about loading of plugins
+DEFINE_BOOL_CONFIG_OPTION(qmlDebugVerbose, QML_DEBUGGER_VERBOSE)
+
+QT_BEGIN_NAMESPACE
+
+Q_GLOBAL_STATIC(QQmlInspectorService, serviceInstance)
+
+QQmlInspectorService::QQmlInspectorService()
+ : QQmlDebugService(QLatin1String("QQmlObserverMode"), 1)
+ , m_currentInspectorPlugin(0)
+{
+ registerService();
+}
+
+QQmlInspectorService *QQmlInspectorService::instance()
+{
+ return serviceInstance();
+}
+
+void QQmlInspectorService::addView(QObject *view)
+{
+ m_views.append(view);
+ updateState();
+}
+
+void QQmlInspectorService::removeView(QObject *view)
+{
+ m_views.removeAll(view);
+ updateState();
+}
+
+void QQmlInspectorService::sendMessage(const QByteArray &message)
+{
+ if (state() != Enabled)
+ return;
+
+ QQmlDebugService::sendMessage(message);
+}
+
+void QQmlInspectorService::stateChanged(State /*state*/)
+{
+ QMetaObject::invokeMethod(this, "updateState", Qt::QueuedConnection);
+}
+
+void QQmlInspectorService::updateState()
+{
+ if (m_views.isEmpty()) {
+ if (m_currentInspectorPlugin) {
+ m_currentInspectorPlugin->deactivate();
+ m_currentInspectorPlugin = 0;
+ }
+ return;
+ }
+
+ if (state() == Enabled) {
+ if (m_inspectorPlugins.isEmpty())
+ loadInspectorPlugins();
+
+ if (m_inspectorPlugins.isEmpty()) {
+ qWarning() << "QQmlInspector: No plugins found.";
+ QQmlDebugServer::instance()->removeService(this);
+ return;
+ }
+
+ foreach (QQmlInspectorInterface *inspector, m_inspectorPlugins) {
+ if (inspector->canHandleView(m_views.first())) {
+ m_currentInspectorPlugin = inspector;
+ break;
+ }
+ }
+
+ if (!m_currentInspectorPlugin) {
+ qWarning() << "QQmlInspector: No plugin available for view '" << m_views.first()->metaObject()->className() << "'.";
+ return;
+ }
+ m_currentInspectorPlugin->activate(m_views.first());
+ } else {
+ if (m_currentInspectorPlugin) {
+ m_currentInspectorPlugin->deactivate();
+ m_currentInspectorPlugin = 0;
+ }
+ }
+}
+
+void QQmlInspectorService::messageReceived(const QByteArray &message)
+{
+ QMetaObject::invokeMethod(this, "processMessage", Qt::QueuedConnection, Q_ARG(QByteArray, message));
+}
+
+void QQmlInspectorService::processMessage(const QByteArray &message)
+{
+ if (m_currentInspectorPlugin)
+ m_currentInspectorPlugin->clientMessage(message);
+}
+
+void QQmlInspectorService::loadInspectorPlugins()
+{
+ QStringList pluginCandidates;
+ const QStringList paths = QCoreApplication::libraryPaths();
+ foreach (const QString &libPath, paths) {
+ const QDir dir(libPath + QLatin1String("/qmltooling"));
+ if (dir.exists())
+ foreach (const QString &pluginPath, dir.entryList(QDir::Files))
+ pluginCandidates << dir.absoluteFilePath(pluginPath);
+ }
+
+ foreach (const QString &pluginPath, pluginCandidates) {
+ if (qmlDebugVerbose())
+ qDebug() << "QQmlInspector: Trying to load plugin " << pluginPath << "...";
+
+ QPluginLoader loader(pluginPath);
+ if (!loader.load()) {
+ if (qmlDebugVerbose())
+ qDebug() << "QQmlInspector: Error while loading: " << loader.errorString();
+
+ continue;
+ }
+
+ QQmlInspectorInterface *inspector =
+ qobject_cast<QQmlInspectorInterface*>(loader.instance());
+ if (inspector) {
+ if (qmlDebugVerbose())
+ qDebug() << "QQmlInspector: Plugin successfully loaded.";
+ m_inspectorPlugins << inspector;
+ } else {
+ if (qmlDebugVerbose())
+ qDebug() << "QQmlInspector: Plugin does not implement interface QQmlInspectorInterface.";
+
+ loader.unload();
+ }
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/debugger/qqmlinspectorservice_p.h b/src/qml/debugger/qqmlinspectorservice_p.h
new file mode 100644
index 0000000000..557dc38aa8
--- /dev/null
+++ b/src/qml/debugger/qqmlinspectorservice_p.h
@@ -0,0 +1,101 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLINSPECTORSERVICE_H
+#define QQMLINSPECTORSERVICE_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 "qqmldebugservice_p.h"
+
+#include <QtQml/qtqmlglobal.h>
+#include <QtCore/QList>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+
+class QQmlInspectorInterface;
+
+class Q_QML_EXPORT QQmlInspectorService : public QQmlDebugService
+{
+ Q_OBJECT
+
+public:
+ QQmlInspectorService();
+ static QQmlInspectorService *instance();
+
+ void addView(QObject *);
+ void removeView(QObject *);
+
+ void sendMessage(const QByteArray &message);
+
+protected:
+ virtual void stateChanged(State state);
+ virtual void messageReceived(const QByteArray &);
+
+private slots:
+ void processMessage(const QByteArray &message);
+ void updateState();
+
+private:
+ void loadInspectorPlugins();
+
+ QList<QObject*> m_views;
+ QQmlInspectorInterface *m_currentInspectorPlugin;
+ QList<QQmlInspectorInterface*> m_inspectorPlugins;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QQMLINSPECTORSERVICE_H
diff --git a/src/qml/debugger/qqmlprofilerservice.cpp b/src/qml/debugger/qqmlprofilerservice.cpp
new file mode 100644
index 0000000000..d6a0307836
--- /dev/null
+++ b/src/qml/debugger/qqmlprofilerservice.cpp
@@ -0,0 +1,357 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qqmlprofilerservice_p.h"
+
+#include <QtCore/qdatastream.h>
+#include <QtCore/qurl.h>
+#include <QtCore/qtimer.h>
+#include <QtCore/qthread.h>
+#include <QtCore/qcoreapplication.h>
+
+// this contains QUnifiedTimer
+#include <private/qabstractanimation_p.h>
+
+QT_BEGIN_NAMESPACE
+
+Q_GLOBAL_STATIC(QQmlProfilerService, profilerInstance)
+
+QQmlBindingProfiler::QQmlBindingProfiler(const QString &url, int line, int column)
+{
+ QQmlProfilerService::startRange(QQmlProfilerService::Binding);
+ QQmlProfilerService::rangeLocation(QQmlProfilerService::Binding, url, line, column);
+}
+
+QQmlBindingProfiler::~QQmlBindingProfiler()
+{
+ QQmlProfilerService::endRange(QQmlProfilerService::Binding);
+}
+
+void QQmlBindingProfiler::addDetail(const QString &details)
+{
+ QQmlProfilerService::rangeData(QQmlProfilerService::Binding, details);
+}
+
+// convert to a QByteArray that can be sent to the debug client
+// use of QDataStream can skew results
+// (see tst_qqmldebugtrace::trace() benchmark)
+QByteArray QQmlProfilerData::toByteArray() const
+{
+ QByteArray data;
+ //### using QDataStream is relatively expensive
+ QDataStream ds(&data, QIODevice::WriteOnly);
+ ds << time << messageType << detailType;
+ if (messageType == (int)QQmlProfilerService::RangeData)
+ ds << detailData;
+ if (messageType == (int)QQmlProfilerService::RangeLocation)
+ ds << detailData << line << column;
+ if (messageType == (int)QQmlProfilerService::Event &&
+ detailType == (int)QQmlProfilerService::AnimationFrame)
+ ds << framerate << animationcount;
+ return data;
+}
+
+QQmlProfilerService::QQmlProfilerService()
+ : QQmlDebugService(QLatin1String("CanvasFrameRate"), 1),
+ m_enabled(false), m_messageReceived(false)
+{
+ m_timer.start();
+
+ if (registerService() == Enabled) {
+ // wait for first message indicating whether to trace or not
+ while (!m_messageReceived)
+ waitForMessage();
+
+ QUnifiedTimer::instance()->registerProfilerCallback( &animationFrame );
+ }
+}
+
+QQmlProfilerService::~QQmlProfilerService()
+{
+}
+
+void QQmlProfilerService::initialize()
+{
+ // just make sure that the service is properly registered
+ profilerInstance();
+}
+
+bool QQmlProfilerService::startProfiling()
+{
+ return profilerInstance()->startProfilingImpl();
+}
+
+bool QQmlProfilerService::stopProfiling()
+{
+ return profilerInstance()->stopProfilingImpl();
+}
+
+void QQmlProfilerService::sendStartedProfilingMessage()
+{
+ profilerInstance()->sendStartedProfilingMessageImpl();
+}
+
+void QQmlProfilerService::addEvent(EventType t)
+{
+ profilerInstance()->addEventImpl(t);
+}
+
+void QQmlProfilerService::startRange(RangeType t)
+{
+ profilerInstance()->startRangeImpl(t);
+}
+
+void QQmlProfilerService::rangeData(RangeType t, const QString &data)
+{
+ profilerInstance()->rangeDataImpl(t, data);
+}
+
+void QQmlProfilerService::rangeData(RangeType t, const QUrl &data)
+{
+ profilerInstance()->rangeDataImpl(t, data);
+}
+
+void QQmlProfilerService::rangeLocation(RangeType t, const QString &fileName, int line, int column)
+{
+ profilerInstance()->rangeLocationImpl(t, fileName, line, column);
+}
+
+void QQmlProfilerService::rangeLocation(RangeType t, const QUrl &fileName, int line, int column)
+{
+ profilerInstance()->rangeLocationImpl(t, fileName, line, column);
+}
+
+void QQmlProfilerService::endRange(RangeType t)
+{
+ profilerInstance()->endRangeImpl(t);
+}
+
+void QQmlProfilerService::animationFrame(qint64 delta)
+{
+ profilerInstance()->animationFrameImpl(delta);
+}
+
+void QQmlProfilerService::sendProfilingData()
+{
+ profilerInstance()->sendMessages();
+}
+
+bool QQmlProfilerService::startProfilingImpl()
+{
+ bool success = false;
+ if (!profilingEnabled()) {
+ setProfilingEnabled(true);
+ sendStartedProfilingMessageImpl();
+ success = true;
+ }
+ return success;
+}
+
+bool QQmlProfilerService::stopProfilingImpl()
+{
+ bool success = false;
+ if (profilingEnabled()) {
+ addEventImpl(EndTrace);
+ setProfilingEnabled(false);
+ success = true;
+ }
+ return success;
+}
+
+void QQmlProfilerService::sendStartedProfilingMessageImpl()
+{
+ if (!QQmlDebugService::isDebuggingEnabled() || !m_enabled)
+ return;
+
+ QQmlProfilerData ed = {m_timer.nsecsElapsed(), (int)Event, (int)StartTrace, QString(), -1, -1, 0, 0};
+ QQmlDebugService::sendMessage(ed.toByteArray());
+}
+
+void QQmlProfilerService::addEventImpl(EventType event)
+{
+ if (!QQmlDebugService::isDebuggingEnabled() || !m_enabled)
+ return;
+
+ QQmlProfilerData ed = {m_timer.nsecsElapsed(), (int)Event, (int)event, QString(), -1, -1, 0, 0};
+ processMessage(ed);
+}
+
+void QQmlProfilerService::startRangeImpl(RangeType range)
+{
+ if (!QQmlDebugService::isDebuggingEnabled() || !m_enabled)
+ return;
+
+ QQmlProfilerData rd = {m_timer.nsecsElapsed(), (int)RangeStart, (int)range, QString(), -1, -1, 0, 0};
+ processMessage(rd);
+}
+
+void QQmlProfilerService::rangeDataImpl(RangeType range, const QString &rData)
+{
+ if (!QQmlDebugService::isDebuggingEnabled() || !m_enabled)
+ return;
+
+ QQmlProfilerData rd = {m_timer.nsecsElapsed(), (int)RangeData, (int)range, rData, -1, -1, 0, 0};
+ processMessage(rd);
+}
+
+void QQmlProfilerService::rangeDataImpl(RangeType range, const QUrl &rData)
+{
+ if (!QQmlDebugService::isDebuggingEnabled() || !m_enabled)
+ return;
+
+ QQmlProfilerData rd = {m_timer.nsecsElapsed(), (int)RangeData, (int)range, rData.toString(QUrl::FormattingOption(0x100)), -1, -1, 0, 0};
+ processMessage(rd);
+}
+
+void QQmlProfilerService::rangeLocationImpl(RangeType range, const QString &fileName, int line, int column)
+{
+ if (!QQmlDebugService::isDebuggingEnabled() || !m_enabled)
+ return;
+
+ QQmlProfilerData rd = {m_timer.nsecsElapsed(), (int)RangeLocation, (int)range, fileName, line, column, 0, 0};
+ processMessage(rd);
+}
+
+void QQmlProfilerService::rangeLocationImpl(RangeType range, const QUrl &fileName, int line, int column)
+{
+ if (!QQmlDebugService::isDebuggingEnabled() || !m_enabled)
+ return;
+
+ QQmlProfilerData rd = {m_timer.nsecsElapsed(), (int)RangeLocation, (int)range, fileName.toString(QUrl::FormattingOption(0x100)), line, column, 0, 0};
+ processMessage(rd);
+}
+
+void QQmlProfilerService::endRangeImpl(RangeType range)
+{
+ if (!QQmlDebugService::isDebuggingEnabled() || !m_enabled)
+ return;
+
+ QQmlProfilerData rd = {m_timer.nsecsElapsed(), (int)RangeEnd, (int)range, QString(), -1, -1, 0, 0};
+ processMessage(rd);
+}
+
+void QQmlProfilerService::animationFrameImpl(qint64 delta)
+{
+ Q_ASSERT(QQmlDebugService::isDebuggingEnabled());
+ if (!m_enabled)
+ return;
+
+ int animCount = QUnifiedTimer::instance()->runningAnimationCount();
+
+ if (animCount > 0 && delta > 0) {
+ // trim fps to integer
+ int fps = 1000 / delta;
+ QQmlProfilerData ed = {m_timer.nsecsElapsed(), (int)Event, (int)AnimationFrame, QString(), -1, -1, fps, animCount};
+ processMessage(ed);
+ }
+}
+
+/*
+ Either send the message directly, or queue up
+ a list of messages to send later (via sendMessages)
+*/
+void QQmlProfilerService::processMessage(const QQmlProfilerData &message)
+{
+ QMutexLocker locker(&m_mutex);
+ m_data.append(message);
+}
+
+bool QQmlProfilerService::profilingEnabled()
+{
+ return m_enabled;
+}
+
+void QQmlProfilerService::setProfilingEnabled(bool enable)
+{
+ m_enabled = enable;
+}
+
+/*
+ Send the messages queued up by processMessage
+*/
+void QQmlProfilerService::sendMessages()
+{
+ QMutexLocker locker(&m_mutex);
+ QList<QByteArray> messages;
+ for (int i = 0; i < m_data.count(); ++i)
+ messages << m_data.at(i).toByteArray();
+ m_data.clear();
+
+ //indicate completion
+ QByteArray data;
+ QDataStream ds(&data, QIODevice::WriteOnly);
+ ds << (qint64)-1 << (int)Complete;
+ messages << data;
+
+ QQmlDebugService::sendMessages(messages);
+}
+
+void QQmlProfilerService::stateAboutToBeChanged(QQmlDebugService::State newState)
+{
+ if (state() == newState)
+ return;
+
+ if (state() == Enabled
+ && m_enabled) {
+ stopProfilingImpl();
+ sendMessages();
+ }
+}
+
+void QQmlProfilerService::messageReceived(const QByteArray &message)
+{
+ QByteArray rwData = message;
+ QDataStream stream(&rwData, QIODevice::ReadOnly);
+
+ bool enabled;
+ stream >> enabled;
+
+ m_messageReceived = true;
+
+ if (enabled) {
+ startProfilingImpl();
+ } else {
+ if (stopProfilingImpl())
+ sendMessages();
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/debugger/qqmlprofilerservice_p.h b/src/qml/debugger/qqmlprofilerservice_p.h
new file mode 100644
index 0000000000..a74ce10c74
--- /dev/null
+++ b/src/qml/debugger/qqmlprofilerservice_p.h
@@ -0,0 +1,183 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLPROFILERSERVICE_P_H
+#define QQMLPROFILERSERVICE_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qqmldebugservice_p.h>
+#include <QtCore/qelapsedtimer.h>
+#include <QtCore/qmutex.h>
+#include <QtCore/qvector.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+struct Q_AUTOTEST_EXPORT QQmlProfilerData
+{
+ qint64 time;
+ int messageType;
+ int detailType;
+
+ //###
+ QString detailData; //used by RangeData and RangeLocation
+ int line; //used by RangeLocation
+ int column; //used by RangeLocation
+ int framerate; //used by animation events
+ int animationcount; //used by animation events
+
+ QByteArray toByteArray() const;
+};
+
+Q_DECLARE_TYPEINFO(QQmlProfilerData, Q_MOVABLE_TYPE);
+
+class QUrl;
+class QQmlEngine;
+
+// RAII
+class Q_AUTOTEST_EXPORT QQmlBindingProfiler {
+public:
+ QQmlBindingProfiler(const QString &url, int line, int column);
+ ~QQmlBindingProfiler();
+ void addDetail(const QString &details);
+};
+
+class Q_QML_EXPORT QQmlProfilerService : public QQmlDebugService
+{
+public:
+ enum Message {
+ Event,
+ RangeStart,
+ RangeData,
+ RangeLocation,
+ RangeEnd,
+ Complete, // end of transmission
+
+ MaximumMessage
+ };
+
+ enum EventType {
+ FramePaint,
+ Mouse,
+ Key,
+ AnimationFrame,
+ EndTrace,
+ StartTrace,
+
+ MaximumEventType
+ };
+
+ enum RangeType {
+ Painting,
+ Compiling,
+ Creating,
+ Binding, //running a binding
+ HandlingSignal, //running a signal handler
+
+ MaximumRangeType
+ };
+
+ static void initialize();
+
+ static bool startProfiling();
+ static bool stopProfiling();
+ static void sendStartedProfilingMessage();
+ static void addEvent(EventType);
+ static void startRange(RangeType);
+ static void rangeData(RangeType, const QString &);
+ static void rangeData(RangeType, const QUrl &);
+ static void rangeLocation(RangeType, const QString &, int, int);
+ static void rangeLocation(RangeType, const QUrl &, int, int);
+ static void endRange(RangeType);
+ static void animationFrame(qint64);
+
+ static void sendProfilingData();
+
+ QQmlProfilerService();
+ ~QQmlProfilerService();
+
+protected:
+ virtual void stateAboutToBeChanged(State state);
+ virtual void messageReceived(const QByteArray &);
+
+private:
+ bool startProfilingImpl();
+ bool stopProfilingImpl();
+ void sendStartedProfilingMessageImpl();
+ void addEventImpl(EventType);
+ void startRangeImpl(RangeType);
+ void rangeDataImpl(RangeType, const QString &);
+ void rangeDataImpl(RangeType, const QUrl &);
+ void rangeLocationImpl(RangeType, const QString &, int, int);
+ void rangeLocationImpl(RangeType, const QUrl &, int, int);
+ void endRangeImpl(RangeType);
+ void animationFrameImpl(qint64);
+
+ bool profilingEnabled();
+ void setProfilingEnabled(bool enable);
+ void sendMessages();
+ void processMessage(const QQmlProfilerData &);
+
+private:
+ QElapsedTimer m_timer;
+ bool m_enabled;
+ bool m_messageReceived;
+ QVector<QQmlProfilerData> m_data;
+ QMutex m_mutex;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QQMLPROFILERSERVICE_P_H
+
diff --git a/src/qml/debugger/qv8debugservice.cpp b/src/qml/debugger/qv8debugservice.cpp
new file mode 100644
index 0000000000..ee60bff742
--- /dev/null
+++ b/src/qml/debugger/qv8debugservice.cpp
@@ -0,0 +1,294 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qv8debugservice_p.h"
+#include "qqmldebugservice_p_p.h"
+#include <private/qjsconverter_impl_p.h>
+#include <private/qv8engine_p.h>
+
+#include <QtCore/QHash>
+#include <QtCore/QFileInfo>
+#include <QtCore/QMutex>
+
+//V8 DEBUG SERVICE PROTOCOL
+// <HEADER><COMMAND><DATA>
+// <HEADER> : "V8DEBUG"
+// <COMMAND> : ["connect", "disconnect", "interrupt",
+// "v8request", "v8message", "breakonsignal",
+// "breakaftercompile"]
+// <DATA> : connect, disconnect, interrupt: empty
+// v8request, v8message: <JSONrequest_string>
+// breakonsignal: <signalname_string><enabled_bool>
+// breakaftercompile: <enabled_bool>
+
+const char *V8_DEBUGGER_KEY_VERSION = "version";
+const char *V8_DEBUGGER_KEY_CONNECT = "connect";
+const char *V8_DEBUGGER_KEY_INTERRUPT = "interrupt";
+const char *V8_DEBUGGER_KEY_DISCONNECT = "disconnect";
+const char *V8_DEBUGGER_KEY_REQUEST = "v8request";
+const char *V8_DEBUGGER_KEY_V8MESSAGE = "v8message";
+const char *V8_DEBUGGER_KEY_BREAK_ON_SIGNAL = "breakonsignal";
+const char *V8_DEBUGGER_KEY_BREAK_AFTER_COMPILE = "breakaftercompile";
+
+QT_BEGIN_NAMESPACE
+
+struct SignalHandlerData
+{
+ QString functionName;
+ bool enabled;
+};
+
+Q_GLOBAL_STATIC(QV8DebugService, v8ServiceInstance)
+
+// DebugMessageHandler will call back already when the QV8DebugService constructor is
+// running, we therefore need a plain pointer.
+static QV8DebugService *v8ServiceInstancePtr = 0;
+
+void DebugMessageDispatchHandler()
+{
+ QMetaObject::invokeMethod(v8ServiceInstancePtr, "processDebugMessages", Qt::QueuedConnection);
+}
+
+void DebugMessageHandler(const v8::Debug::Message& message)
+{
+ v8::DebugEvent event = message.GetEvent();
+
+ if (event != v8::Break && event != v8::Exception &&
+ event != v8::AfterCompile && event != v8::BeforeCompile)
+ return;
+ v8ServiceInstancePtr->debugMessageHandler(QJSConverter::toString(message.GetJSON()), event);
+}
+
+class QV8DebugServicePrivate : public QQmlDebugServicePrivate
+{
+public:
+ QV8DebugServicePrivate()
+ : connectReceived(false)
+ , breakAfterCompile(false)
+ , engine(0)
+ {
+ }
+
+ void initializeDebuggerThread();
+
+ static QByteArray packMessage(const QString &type, const QString &message = QString());
+
+ bool connectReceived;
+ bool breakAfterCompile;
+ QMutex initializeMutex;
+ QStringList breakOnSignals;
+ const QV8Engine *engine;
+};
+
+QV8DebugService::QV8DebugService(QObject *parent)
+ : QQmlDebugService(*(new QV8DebugServicePrivate()),
+ QLatin1String("V8Debugger"), 2, parent)
+{
+ Q_D(QV8DebugService);
+ v8ServiceInstancePtr = this;
+ // wait for stateChanged() -> initialize()
+ d->initializeMutex.lock();
+ if (registerService() == Enabled) {
+ init();
+ // ,block mode, client attached
+ while (!d->connectReceived) {
+ waitForMessage();
+ }
+ } else {
+ d->initializeMutex.unlock();
+ }
+}
+
+QV8DebugService::~QV8DebugService()
+{
+}
+
+QV8DebugService *QV8DebugService::instance()
+{
+ return v8ServiceInstance();
+}
+
+void QV8DebugService::initialize(const QV8Engine *engine)
+{
+ // just make sure that the service is properly registered
+ v8ServiceInstance()->setEngine(engine);
+}
+
+void QV8DebugService::setEngine(const QV8Engine *engine)
+{
+ Q_D(QV8DebugService);
+
+ d->engine = engine;
+}
+
+void QV8DebugService::debugMessageHandler(const QString &message, const v8::DebugEvent &event)
+{
+ Q_D(QV8DebugService);
+ sendMessage(QV8DebugServicePrivate::packMessage(QLatin1String(V8_DEBUGGER_KEY_V8MESSAGE), message));
+ if (event == v8::AfterCompile && d->breakAfterCompile)
+ scheduledDebugBreak(true);
+}
+
+void QV8DebugService::signalEmitted(const QString &signal)
+{
+ //This function is only called by QQmlBoundSignal
+ //only if there is a slot connected to the signal. Hence, there
+ //is no need for additional check.
+ Q_D(QV8DebugService);
+
+ //Parse just the name and remove the class info
+ //Normalize to Lower case.
+ QString signalName = signal.left(signal.indexOf(QLatin1String("("))).toLower();
+
+ foreach (const QString &signal, d->breakOnSignals) {
+ if (signal == signalName) {
+ scheduledDebugBreak(true);
+ break;
+ }
+ }
+}
+
+// executed in the gui thread
+void QV8DebugService::init()
+{
+ Q_D(QV8DebugService);
+ v8::Debug::SetMessageHandler2(DebugMessageHandler);
+ v8::Debug::SetDebugMessageDispatchHandler(DebugMessageDispatchHandler);
+ d->initializeMutex.unlock();
+}
+
+// executed in the gui thread
+void QV8DebugService::scheduledDebugBreak(bool schedule)
+{
+ if (schedule)
+ v8::Debug::DebugBreak();
+ else
+ v8::Debug::CancelDebugBreak();
+}
+
+// executed in the debugger thread
+void QV8DebugService::stateChanged(QQmlDebugService::State newState)
+{
+ Q_D(QV8DebugService);
+ if (newState == Enabled) {
+ // execute in GUI thread
+ d->initializeMutex.lock();
+ QMetaObject::invokeMethod(this, "init", Qt::QueuedConnection);
+ }
+}
+
+// executed in the debugger thread
+void QV8DebugService::messageReceived(const QByteArray &message)
+{
+ Q_D(QV8DebugService);
+
+ QDataStream ds(message);
+ QByteArray header;
+ ds >> header;
+
+ if (header == "V8DEBUG") {
+ QByteArray command;
+ QByteArray data;
+ ds >> command >> data;
+
+ if (command == V8_DEBUGGER_KEY_CONNECT) {
+ QMutexLocker locker(&d->initializeMutex);
+ d->connectReceived = true;
+ sendMessage(QV8DebugServicePrivate::packMessage(QLatin1String(V8_DEBUGGER_KEY_CONNECT)));
+
+ } else if (command == V8_DEBUGGER_KEY_INTERRUPT) {
+ // break has to be executed in gui thread
+ QMetaObject::invokeMethod(this, "scheduledDebugBreak", Qt::QueuedConnection, Q_ARG(bool, true));
+ sendMessage(QV8DebugServicePrivate::packMessage(QLatin1String(V8_DEBUGGER_KEY_INTERRUPT)));
+
+ } else if (command == V8_DEBUGGER_KEY_DISCONNECT) {
+ // cancel break has to be executed in gui thread
+ QMetaObject::invokeMethod(this, "scheduledDebugBreak", Qt::QueuedConnection, Q_ARG(bool, false));
+ sendDebugMessage(QString::fromUtf8(data));
+
+ } else if (command == V8_DEBUGGER_KEY_REQUEST) {
+ sendDebugMessage(QString::fromUtf8(data));
+
+ } else if (command == V8_DEBUGGER_KEY_BREAK_ON_SIGNAL) {
+ QDataStream rs(data);
+ QByteArray signal;
+ bool enabled;
+ rs >> signal >> enabled;
+ //Normalize to lower case.
+ QString signalName(QString::fromUtf8(signal).toLower());
+ if (enabled)
+ d->breakOnSignals.append(signalName);
+ else
+ d->breakOnSignals.removeOne(signalName);
+ sendMessage(QV8DebugServicePrivate::packMessage(QLatin1String(V8_DEBUGGER_KEY_BREAK_ON_SIGNAL)));
+
+ } else if (command == V8_DEBUGGER_KEY_BREAK_AFTER_COMPILE) {
+ QDataStream rs(data);
+ rs >> d->breakAfterCompile;
+ sendMessage(QV8DebugServicePrivate::packMessage(QLatin1String(V8_DEBUGGER_KEY_BREAK_AFTER_COMPILE)));
+
+ }
+ }
+}
+
+void QV8DebugService::sendDebugMessage(const QString &message)
+{
+ v8::Debug::SendCommand(message.utf16(), message.size());
+}
+
+void QV8DebugService::processDebugMessages()
+{
+ Q_D(QV8DebugService);
+ v8::HandleScope handleScope;
+ v8::Context::Scope contextScope(d->engine->context());
+ v8::Debug::ProcessDebugMessages();
+}
+
+QByteArray QV8DebugServicePrivate::packMessage(const QString &type, const QString &message)
+{
+ QByteArray reply;
+ QDataStream rs(&reply, QIODevice::WriteOnly);
+ QByteArray cmd("V8DEBUG");
+ rs << cmd << type.toUtf8() << message.toUtf8();
+ return reply;
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/debugger/qv8debugservice_p.h b/src/qml/debugger/qv8debugservice_p.h
new file mode 100644
index 0000000000..8ff4adc778
--- /dev/null
+++ b/src/qml/debugger/qv8debugservice_p.h
@@ -0,0 +1,105 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QV8DEBUGSERVICE_P_H
+#define QV8DEBUGSERVICE_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 "qqmldebugservice_p.h"
+#include <private/qv8debug_p.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+
+class QV8Engine;
+class QV8DebugServicePrivate;
+
+class QV8DebugService : public QQmlDebugService
+{
+ Q_OBJECT
+public:
+ QV8DebugService(QObject *parent = 0);
+ ~QV8DebugService();
+
+ static QV8DebugService *instance();
+ static void initialize(const QV8Engine *engine);
+
+ void debugMessageHandler(const QString &message, const v8::DebugEvent &event);
+
+ void signalEmitted(const QString &signal);
+
+public slots:
+ void processDebugMessages();
+
+private slots:
+ void scheduledDebugBreak(bool schedule);
+ void sendDebugMessage(const QString &message);
+ void init();
+
+protected:
+ void stateChanged(State newState);
+ void messageReceived(const QByteArray &);
+
+private:
+ void setEngine(const QV8Engine *engine);
+
+private:
+ Q_DISABLE_COPY(QV8DebugService)
+ Q_DECLARE_PRIVATE(QV8DebugService)
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QV8DEBUGSERVICE_P_H
diff --git a/src/qml/debugger/qv8profilerservice.cpp b/src/qml/debugger/qv8profilerservice.cpp
new file mode 100644
index 0000000000..eba8b0feef
--- /dev/null
+++ b/src/qml/debugger/qv8profilerservice.cpp
@@ -0,0 +1,287 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qv8profilerservice_p.h"
+#include "qqmldebugservice_p_p.h"
+#include "private/qjsconverter_impl_p.h"
+#include <private/qv8profiler_p.h>
+
+#include <QtCore/QHash>
+
+QT_BEGIN_NAMESPACE
+
+Q_GLOBAL_STATIC(QV8ProfilerService, v8ProfilerInstance)
+
+class DebugServiceOutputStream : public v8::OutputStream
+{
+ QQmlDebugService &_service;
+public:
+ DebugServiceOutputStream(QQmlDebugService &service)
+ : v8::OutputStream(),
+ _service(service) {}
+ void EndOfStream() {}
+ WriteResult WriteAsciiChunk(char *rawData, int size)
+ {
+ QByteArray data;
+ QDataStream ds(&data, QIODevice::WriteOnly);
+ ds << QV8ProfilerService::V8SnapshotChunk << QByteArray(rawData, size);
+ _service.sendMessage(data);
+ return kContinue;
+ }
+};
+
+// convert to a QByteArray that can be sent to the debug client
+QByteArray QV8ProfilerData::toByteArray() const
+{
+ QByteArray data;
+ //### using QDataStream is relatively expensive
+ QDataStream ds(&data, QIODevice::WriteOnly);
+ ds << messageType << filename << functionname << lineNumber << totalTime << selfTime << treeLevel;
+
+ return data;
+}
+
+class QV8ProfilerServicePrivate : public QQmlDebugServicePrivate
+{
+ Q_DECLARE_PUBLIC(QV8ProfilerService)
+
+public:
+ QV8ProfilerServicePrivate()
+ :initialized(false)
+ {
+ }
+
+ void takeSnapshot(v8::HeapSnapshot::Type);
+
+ void printProfileTree(const v8::CpuProfileNode *node, int level = 0);
+ void sendMessages();
+
+ QList<QV8ProfilerData> m_data;
+
+ bool initialized;
+ QList<QString> m_ongoing;
+};
+
+QV8ProfilerService::QV8ProfilerService(QObject *parent)
+ : QQmlDebugService(*(new QV8ProfilerServicePrivate()), QLatin1String("V8Profiler"), 1, parent)
+{
+ Q_D(QV8ProfilerService);
+
+ if (registerService() == Enabled) {
+ // ,block mode, client attached
+ while (!d->initialized)
+ waitForMessage();
+ }
+}
+
+QV8ProfilerService::~QV8ProfilerService()
+{
+}
+
+QV8ProfilerService *QV8ProfilerService::instance()
+{
+ return v8ProfilerInstance();
+}
+
+void QV8ProfilerService::initialize()
+{
+ // just make sure that the service is properly registered
+ v8ProfilerInstance();
+}
+
+void QV8ProfilerService::stateAboutToBeChanged(QQmlDebugService::State newState)
+{
+ Q_D(QV8ProfilerService);
+
+ if (state() == newState)
+ return;
+
+ if (state() == Enabled) {
+ foreach (const QString &title, d->m_ongoing)
+ QMetaObject::invokeMethod(this, "stopProfiling", Qt::QueuedConnection, Q_ARG(QString, title));
+ sendProfilingData();
+ }
+}
+
+void QV8ProfilerService::messageReceived(const QByteArray &message)
+{
+ Q_D(QV8ProfilerService);
+
+ QDataStream ds(message);
+ QByteArray command;
+ QByteArray option;
+ QByteArray title;
+ ds >> command >> option;
+
+ if (command == "V8PROFILER") {
+ ds >> title;
+ QString titleStr = QString::fromUtf8(title);
+ if (option == "start") {
+ QMetaObject::invokeMethod(this, "startProfiling", Qt::QueuedConnection, Q_ARG(QString, titleStr));
+ } else if (option == "stop" && d->initialized) {
+ QMetaObject::invokeMethod(this, "stopProfiling", Qt::QueuedConnection, Q_ARG(QString, titleStr));
+ QMetaObject::invokeMethod(this, "sendProfilingData", Qt::QueuedConnection);
+ }
+ d->initialized = true;
+ }
+
+ if (command == "V8SNAPSHOT") {
+ if (option == "full")
+ QMetaObject::invokeMethod(this, "takeSnapshot", Qt::QueuedConnection);
+ else if (option == "delete") {
+ QMetaObject::invokeMethod(this, "deleteSnapshots", Qt::QueuedConnection);
+ }
+ }
+
+ QQmlDebugService::messageReceived(message);
+}
+
+void QV8ProfilerService::startProfiling(const QString &title)
+{
+ Q_D(QV8ProfilerService);
+ // Start Profiling
+
+ if (d->m_ongoing.contains(title))
+ return;
+
+ v8::HandleScope handle_scope;
+ v8::Handle<v8::String> v8title = v8::String::New(reinterpret_cast<const uint16_t*>(title.data()), title.size());
+ v8::CpuProfiler::StartProfiling(v8title);
+
+ d->m_ongoing.append(title);
+}
+
+void QV8ProfilerService::stopProfiling(const QString &title)
+{
+ Q_D(QV8ProfilerService);
+ // Stop profiling
+
+ if (!d->m_ongoing.contains(title))
+ return;
+ d->m_ongoing.removeOne(title);
+
+ v8::HandleScope handle_scope;
+ v8::Handle<v8::String> v8title = v8::String::New(reinterpret_cast<const uint16_t*>(title.data()), title.size());
+ const v8::CpuProfile *cpuProfile = v8::CpuProfiler::StopProfiling(v8title);
+ if (cpuProfile) {
+ // can happen at start
+ const v8::CpuProfileNode *rootNode = cpuProfile->GetTopDownRoot();
+ d->printProfileTree(rootNode);
+ }
+}
+
+void QV8ProfilerService::takeSnapshot()
+{
+ Q_D(QV8ProfilerService);
+ d->takeSnapshot(v8::HeapSnapshot::kFull);
+}
+
+void QV8ProfilerService::deleteSnapshots()
+{
+ v8::HeapProfiler::DeleteAllSnapshots();
+}
+
+void QV8ProfilerService::sendProfilingData()
+{
+ Q_D(QV8ProfilerService);
+ // Send messages to client
+ d->sendMessages();
+}
+
+void QV8ProfilerServicePrivate::printProfileTree(const v8::CpuProfileNode *node, int level)
+{
+ for (int index = 0 ; index < node->GetChildrenCount() ; index++) {
+ const v8::CpuProfileNode* childNode = node->GetChild(index);
+ QString scriptResourceName = QJSConverter::toString(childNode->GetScriptResourceName());
+ if (scriptResourceName.length() > 0) {
+
+ QV8ProfilerData rd = {(int)QV8ProfilerService::V8Entry, scriptResourceName,
+ QJSConverter::toString(childNode->GetFunctionName()),
+ childNode->GetLineNumber(), childNode->GetTotalTime(), childNode->GetSelfTime(), level};
+ m_data.append(rd);
+
+ // different nodes might have common children: fix at client side
+ if (childNode->GetChildrenCount() > 0) {
+ printProfileTree(childNode, level+1);
+ }
+ }
+ }
+}
+
+void QV8ProfilerServicePrivate::takeSnapshot(v8::HeapSnapshot::Type snapshotType)
+{
+ Q_Q(QV8ProfilerService);
+
+ v8::HandleScope scope;
+ v8::Local<v8::String> title = v8::String::New("");
+
+ DebugServiceOutputStream outputStream(*q);
+ const v8::HeapSnapshot *snapshot = v8::HeapProfiler::TakeSnapshot(title, snapshotType);
+ snapshot->Serialize(&outputStream, v8::HeapSnapshot::kJSON);
+
+ //indicate completion
+ QByteArray data;
+ QDataStream ds(&data, QIODevice::WriteOnly);
+ ds << (int)QV8ProfilerService::V8SnapshotComplete;
+
+ q->sendMessage(data);
+}
+
+void QV8ProfilerServicePrivate::sendMessages()
+{
+ Q_Q(QV8ProfilerService);
+
+ QList<QByteArray> messages;
+ for (int i = 0; i < m_data.count(); ++i)
+ messages << m_data.at(i).toByteArray();
+ q->sendMessages(messages);
+ m_data.clear();
+
+ //indicate completion
+ QByteArray data;
+ QDataStream ds(&data, QIODevice::WriteOnly);
+ ds << (int)QV8ProfilerService::V8Complete;
+
+ q->sendMessage(data);
+}
+
+
+QT_END_NAMESPACE
diff --git a/src/qml/debugger/qv8profilerservice_p.h b/src/qml/debugger/qv8profilerservice_p.h
new file mode 100644
index 0000000000..d408d9ed0e
--- /dev/null
+++ b/src/qml/debugger/qv8profilerservice_p.h
@@ -0,0 +1,119 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QV8PROFILERSERVICE_P_H
+#define QV8PROFILERSERVICE_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qqmldebugservice_p.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+
+struct Q_AUTOTEST_EXPORT QV8ProfilerData
+{
+ int messageType;
+ QString filename;
+ QString functionname;
+ int lineNumber;
+ double totalTime;
+ double selfTime;
+ int treeLevel;
+
+ QByteArray toByteArray() const;
+};
+
+class QQmlEngine;
+class QV8ProfilerServicePrivate;
+
+class Q_AUTOTEST_EXPORT QV8ProfilerService : public QQmlDebugService
+{
+ Q_OBJECT
+public:
+ enum MessageType {
+ V8Entry,
+ V8Complete,
+ V8SnapshotChunk,
+ V8SnapshotComplete,
+
+ V8MaximumMessage
+ };
+
+ QV8ProfilerService(QObject *parent = 0);
+ ~QV8ProfilerService();
+
+ static QV8ProfilerService *instance();
+ static void initialize();
+
+public slots:
+ void startProfiling(const QString &title);
+ void stopProfiling(const QString &title);
+ void takeSnapshot();
+ void deleteSnapshots();
+
+ void sendProfilingData();
+
+protected:
+ void stateAboutToBeChanged(State state);
+ void messageReceived(const QByteArray &);
+
+private:
+ Q_DISABLE_COPY(QV8ProfilerService)
+ Q_DECLARE_PRIVATE(QV8ProfilerService)
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QV8PROFILERSERVICE_P_H
diff --git a/src/qml/qml.pro b/src/qml/qml.pro
new file mode 100644
index 0000000000..0bbfc9ff74
--- /dev/null
+++ b/src/qml/qml.pro
@@ -0,0 +1,37 @@
+load(qt_module)
+
+TARGET = QtQml
+QPRO_PWD = $$PWD
+
+CONFIG += module
+MODULE_PRI += ../../modules/qt_qml.pri
+
+QT = core-private gui gui-private network v8-private
+
+DEFINES += QT_BUILD_QML_LIB QT_NO_URL_CAST_FROM_STRING QT_NO_INTEGER_EVENT_COORDINATES
+
+win32-msvc*|win32-icc:QMAKE_LFLAGS += /BASE:0x66000000
+win32-msvc*:DEFINES *= _CRT_SECURE_NO_WARNINGS
+solaris-cc*:QMAKE_CXXFLAGS_RELEASE -= -O2
+
+unix|win32-g++*:QMAKE_PKGCONFIG_REQUIRES = QtCore QtGui
+
+exists("qqml_enable_gcov") {
+ QMAKE_CXXFLAGS = -fprofile-arcs -ftest-coverage -fno-elide-constructors
+ LIBS += -lgcov
+}
+
+load(qt_module_config)
+
+HEADERS += qtqmlversion.h \
+ qtqmlglobal.h \
+ qtqmlglobal_p.h
+
+#INCLUDEPATH -= $$QMAKE_INCDIR_QT/$$TARGET
+#DESTDIR=.
+
+#modules
+include(util/util.pri)
+include(qml/qml.pri)
+include(debugger/debugger.pri)
+include(animations/animations.pri)
diff --git a/src/qml/qml/ftw/ftw.pri b/src/qml/qml/ftw/ftw.pri
new file mode 100644
index 0000000000..f2fec4e2dd
--- /dev/null
+++ b/src/qml/qml/ftw/ftw.pri
@@ -0,0 +1,29 @@
+HEADERS += \
+ $$PWD/qbitfield_p.h \
+ $$PWD/qintrusivelist_p.h \
+ $$PWD/qpodvector_p.h \
+ $$PWD/qhashedstring_p.h \
+ $$PWD/qqmlrefcount_p.h \
+ $$PWD/qqmlpool_p.h \
+ $$PWD/qfieldlist_p.h \
+ $$PWD/qfastmetabuilder_p.h \
+ $$PWD/qhashfield_p.h \
+ $$PWD/qqmlthread_p.h \
+ $$PWD/qfinitestack_p.h \
+ $$PWD/qrecursionwatcher_p.h \
+ $$PWD/qdeletewatcher_p.h \
+ $$PWD/qrecyclepool_p.h \
+ $$PWD/qflagpointer_p.h \
+ $$PWD/qqmltrace_p.h \
+ $$PWD/qpointervaluepair_p.h \
+ $$PWD/qlazilyallocated_p.h \
+
+SOURCES += \
+ $$PWD/qintrusivelist.cpp \
+ $$PWD/qhashedstring.cpp \
+ $$PWD/qqmlpool.cpp \
+ $$PWD/qfastmetabuilder.cpp \
+ $$PWD/qqmlthread.cpp \
+ $$PWD/qqmltrace.cpp \
+
+contains(QT_CONFIG, clock-gettime):include($$QT_SOURCE_TREE/config.tests/unix/clock-gettime/clock-gettime.pri)
diff --git a/src/qml/qml/ftw/qbitfield_p.h b/src/qml/qml/ftw/qbitfield_p.h
new file mode 100644
index 0000000000..75f80dd896
--- /dev/null
+++ b/src/qml/qml/ftw/qbitfield_p.h
@@ -0,0 +1,165 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QBITFIELD_P_H
+#define QBITFIELD_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qglobal.h>
+
+QT_BEGIN_NAMESPACE
+
+class QBitField
+{
+public:
+ inline QBitField();
+ inline QBitField(const quint32 *, int bits);
+ inline QBitField(const QBitField &);
+ inline ~QBitField();
+
+ inline QBitField &operator=(const QBitField &);
+
+ inline quint32 size() const;
+ inline QBitField united(const QBitField &);
+ inline bool testBit(int) const;
+
+private:
+ quint32 bits:31;
+ quint32 *ownData;
+ const quint32 *data;
+};
+
+QBitField::QBitField()
+: bits(0), ownData(0), data(0)
+{
+}
+
+QBitField::QBitField(const quint32 *bitData, int bitCount)
+: bits((quint32)bitCount), ownData(0), data(bitData)
+{
+}
+
+QBitField::QBitField(const QBitField &other)
+: bits(other.bits), ownData(other.ownData), data(other.data)
+{
+ if (ownData)
+ ++(*ownData);
+}
+
+QBitField::~QBitField()
+{
+ if (ownData)
+ if(0 == --(*ownData)) delete [] ownData;
+}
+
+QBitField &QBitField::operator=(const QBitField &other)
+{
+ if (other.data == data)
+ return *this;
+
+ if (ownData)
+ if(0 == --(*ownData)) delete [] ownData;
+
+ bits = other.bits;
+ ownData = other.ownData;
+ data = other.data;
+
+ if (ownData)
+ ++(*ownData);
+
+ return *this;
+}
+
+inline quint32 QBitField::size() const
+{
+ return bits;
+}
+
+QBitField QBitField::united(const QBitField &o)
+{
+ if (o.bits == 0) {
+ return *this;
+ } else if (bits == 0) {
+ return o;
+ } else {
+ int max = (bits > o.bits)?bits:o.bits;
+ int length = (max + 31) / 32;
+ QBitField rv;
+ rv.bits = max;
+ rv.ownData = new quint32[length + 1];
+ *(rv.ownData) = 1;
+ rv.data = rv.ownData + 1;
+ if (bits > o.bits) {
+ ::memcpy((quint32 *)rv.data, data, length * sizeof(quint32));
+ for (quint32 ii = 0; ii < (o.bits + quint32(31)) / 32; ++ii)
+ ((quint32 *)rv.data)[ii] |= o.data[ii];
+ } else {
+ ::memcpy((quint32 *)rv.data, o.data, length * sizeof(quint32));
+ for (quint32 ii = 0; ii < (bits + quint32(31)) / 32; ++ii)
+ ((quint32 *)rv.data)[ii] |= data[ii];
+ }
+ return rv;
+ }
+}
+
+bool QBitField::testBit(int b) const
+{
+ Q_ASSERT(b >= 0);
+ if ((quint32)b < bits) {
+ return data[b / 32] & (1 << (b % 32));
+ } else {
+ return false;
+ }
+}
+
+QT_END_NAMESPACE
+
+#endif // QBITFIELD_P_H
diff --git a/src/qml/qml/ftw/qdeletewatcher_p.h b/src/qml/qml/ftw/qdeletewatcher_p.h
new file mode 100644
index 0000000000..9f7b100429
--- /dev/null
+++ b/src/qml/qml/ftw/qdeletewatcher_p.h
@@ -0,0 +1,113 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDELETEWATCHER_P_H
+#define QDELETEWATCHER_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qglobal.h>
+
+QT_BEGIN_NAMESPACE
+
+class QDeleteWatchable
+{
+public:
+ inline QDeleteWatchable();
+ inline ~QDeleteWatchable();
+private:
+ friend class QDeleteWatcher;
+ bool *_w;
+};
+
+class QDeleteWatcher {
+public:
+ inline QDeleteWatcher(QDeleteWatchable *data);
+ inline ~QDeleteWatcher();
+ inline bool wasDeleted() const;
+private:
+ void *operator new(size_t);
+ bool *_w;
+ bool _s;
+ QDeleteWatchable *m_d;
+};
+
+QDeleteWatchable::QDeleteWatchable()
+: _w(0)
+{
+}
+
+QDeleteWatchable::~QDeleteWatchable()
+{
+ if (_w) *_w = true;
+}
+
+QDeleteWatcher::QDeleteWatcher(QDeleteWatchable *data)
+: _s(false), m_d(data)
+{
+ if (!m_d->_w)
+ m_d->_w = &_s;
+ _w = m_d->_w;
+}
+
+QDeleteWatcher::~QDeleteWatcher()
+{
+ if (false == *_w && &_s == m_d->_w)
+ m_d->_w = 0;
+}
+
+bool QDeleteWatcher::wasDeleted() const
+{
+ return *_w;
+}
+
+QT_END_NAMESPACE
+
+#endif // QDELETEWATCHER_P_H
diff --git a/src/qml/qml/ftw/qfastmetabuilder.cpp b/src/qml/qml/ftw/qfastmetabuilder.cpp
new file mode 100644
index 0000000000..9663c1e944
--- /dev/null
+++ b/src/qml/qml/ftw/qfastmetabuilder.cpp
@@ -0,0 +1,369 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qfastmetabuilder_p.h"
+
+#include <QtCore/qmetaobject.h>
+
+QT_BEGIN_NAMESPACE
+
+struct QFastMetaBuilderHeader
+{
+ int fieldCount;
+};
+
+struct QMetaObjectPrivate
+{
+ int revision;
+ int className;
+ int classInfoCount, classInfoData;
+ int methodCount, methodData;
+ int propertyCount, propertyData;
+ int enumeratorCount, enumeratorData;
+ int constructorCount, constructorData; //since revision 2
+ int flags; //since revision 3
+ int signalCount; //since revision 4
+};
+
+enum MetaObjectFlag {
+ DynamicMetaObject = 0x01
+};
+
+enum PropertyFlags {
+ Invalid = 0x00000000,
+ Readable = 0x00000001,
+ Writable = 0x00000002,
+ Resettable = 0x00000004,
+ EnumOrFlag = 0x00000008,
+ StdCppSet = 0x00000100,
+// Override = 0x00000200,
+ Constant = 0x00000400,
+ Final = 0x00000800,
+ Designable = 0x00001000,
+ ResolveDesignable = 0x00002000,
+ Scriptable = 0x00004000,
+ ResolveScriptable = 0x00008000,
+ Stored = 0x00010000,
+ ResolveStored = 0x00020000,
+ Editable = 0x00040000,
+ ResolveEditable = 0x00080000,
+ User = 0x00100000,
+ ResolveUser = 0x00200000,
+ Notify = 0x00400000,
+ Revisioned = 0x00800000
+};
+
+enum MethodFlags {
+ AccessPrivate = 0x00,
+ AccessProtected = 0x01,
+ AccessPublic = 0x02,
+ AccessMask = 0x03, //mask
+
+ MethodMethod = 0x00,
+ MethodSignal = 0x04,
+ MethodSlot = 0x08,
+ MethodConstructor = 0x0c,
+ MethodTypeMask = 0x0c,
+
+ MethodCompatibility = 0x10,
+ MethodCloned = 0x20,
+ MethodScriptable = 0x40,
+ MethodRevisioned = 0x80
+};
+
+#define FMBHEADER_FIELD_COUNT 1
+
+#define HEADER_FIELD_COUNT 14
+#define CLASSINFO_FIELD_COUNT 2
+#define METHOD_FIELD_COUNT 5
+#define PROPERTY_FIELD_COUNT 3
+#define PROPERTY_NOTIFY_FIELD_COUNT 1
+
+static inline uint *fieldPointer(QByteArray &data)
+{ return reinterpret_cast<uint *>(data.data()) + FMBHEADER_FIELD_COUNT; }
+
+static inline const uint *fieldPointer(const QByteArray &data)
+{ return reinterpret_cast<const uint *>(data.constData()) + FMBHEADER_FIELD_COUNT; }
+
+static inline QMetaObjectPrivate *priv(QByteArray &data)
+{ return reinterpret_cast<QMetaObjectPrivate*>(fieldPointer(data)); }
+
+static inline const QMetaObjectPrivate *priv(const QByteArray &data)
+{ return reinterpret_cast<const QMetaObjectPrivate*>(fieldPointer(data)); }
+
+static inline QFastMetaBuilderHeader *header(QByteArray &data)
+{ return reinterpret_cast<QFastMetaBuilderHeader*>(data.data()); }
+
+static inline const QFastMetaBuilderHeader *header(const QByteArray &data)
+{ return reinterpret_cast<const QFastMetaBuilderHeader*>(data.constData()); }
+
+QFastMetaBuilder::QFastMetaBuilder()
+: m_zeroPtr(0), m_stringData(0), m_stringDataLength(0), m_stringDataAllocated(0)
+{
+}
+
+QFastMetaBuilder::~QFastMetaBuilder()
+{
+}
+
+QFastMetaBuilder::StringRef QFastMetaBuilder::init(int classNameLength,
+ int propertyCount, int methodCount,
+ int signalCount, int classInfoCount)
+{
+ Q_ASSERT(m_data.isEmpty());
+ Q_ASSERT(classNameLength > 0);
+ Q_ASSERT(propertyCount >= 0);
+ Q_ASSERT(methodCount >= 0);
+ Q_ASSERT(signalCount >= 0);
+ Q_ASSERT(classInfoCount >= 0);
+
+ int fieldCount = FMBHEADER_FIELD_COUNT +
+ HEADER_FIELD_COUNT +
+ propertyCount * (PROPERTY_FIELD_COUNT + PROPERTY_NOTIFY_FIELD_COUNT) +
+ methodCount * (METHOD_FIELD_COUNT) +
+ signalCount * (METHOD_FIELD_COUNT) +
+ classInfoCount * CLASSINFO_FIELD_COUNT;
+
+ m_data.resize(fieldCount * sizeof(uint) + classNameLength + 1);
+ m_stringData = m_data.data() + m_data.size() - classNameLength - 1;
+ m_stringDataLength = classNameLength + 1;
+ m_stringDataAllocated = classNameLength + 1;
+ m_stringData[classNameLength] = 0;
+ m_zeroPtr = classNameLength;
+
+ header(m_data)->fieldCount = fieldCount;
+
+ QMetaObjectPrivate *p = priv(m_data);
+
+ int dataIndex = HEADER_FIELD_COUNT;
+
+ p->revision = 4;
+ p->className = 0;
+
+ // Class infos
+ p->classInfoCount = classInfoCount;
+ if (p->classInfoCount) {
+ p->classInfoData = dataIndex;
+ dataIndex += p->classInfoCount * CLASSINFO_FIELD_COUNT;
+ } else {
+ p->classInfoData = 0;
+ }
+
+ // Methods
+ p->methodCount = methodCount + signalCount;
+ if (p->methodCount) {
+ p->methodData = dataIndex;
+ dataIndex += p->methodCount * METHOD_FIELD_COUNT;
+ } else {
+ p->methodData = 0;
+ }
+ p->signalCount = signalCount;
+
+ // Properties
+ p->propertyCount = propertyCount;
+ if (p->propertyCount) {
+ p->propertyData = dataIndex;
+ dataIndex += p->propertyCount * (PROPERTY_FIELD_COUNT + PROPERTY_NOTIFY_FIELD_COUNT);
+ } else {
+ p->propertyData = 0;
+ }
+
+ // Flags
+ p->flags = DynamicMetaObject; // Always dynamic
+
+ // Enums and constructors not supported
+ p->enumeratorCount = 0;
+ p->enumeratorData = 0;
+ p->constructorCount = 0;
+ p->constructorData = 0;
+
+ StringRef className;
+ className._b = this;
+ className._o = 0;
+ className._l = classNameLength;
+ return className;
+}
+
+// Allocate a string of \a length. \a length should *not* include the null terminator.
+QFastMetaBuilder::StringRef QFastMetaBuilder::newString(int length)
+{
+ Q_ASSERT(length > 0);
+
+ StringRef sr;
+ sr._b = this;
+ sr._o = m_stringDataLength;
+ sr._l = length;
+
+ m_stringDataLength += length + 1 /* for null terminator */;
+
+ return sr;
+}
+
+void QFastMetaBuilder::setClassInfo(int index, const StringRef &key, const StringRef &value)
+{
+ Q_ASSERT(!m_data.isEmpty());
+ Q_ASSERT(!key.isEmpty() && !value.isEmpty());
+
+ QMetaObjectPrivate *p = priv(m_data);
+ Q_ASSERT(index < p->classInfoCount);
+
+ uint *ptr = fieldPointer(m_data) + p->classInfoData + index * CLASSINFO_FIELD_COUNT;
+ // classinfo: key, value
+ ptr[0] = key.offset(); ptr[1] = value.offset();
+}
+
+void QFastMetaBuilder::setProperty(int index, const StringRef &name, const StringRef &type,
+ QMetaType::Type mtype, PropertyFlag flags, int notifySignal)
+{
+ Q_ASSERT(!m_data.isEmpty());
+ Q_ASSERT(!name.isEmpty() && !type.isEmpty());
+
+ QMetaObjectPrivate *p = priv(m_data);
+ Q_ASSERT(index < p->propertyCount);
+
+ uint *ptr = fieldPointer(m_data) + p->propertyData + index * PROPERTY_FIELD_COUNT;
+ // properties: name, type, flags
+ ptr[0] = name.offset();
+ ptr[1] = type.offset();
+ if (notifySignal == -1) {
+ ptr[2] = mtype << 24;
+ ptr[2] |= flags | Scriptable | Readable;
+ *(fieldPointer(m_data) + p->propertyData + p->propertyCount * PROPERTY_FIELD_COUNT + index) = 0;
+ } else {
+ ptr[2] = mtype << 24;
+ ptr[2] |= flags | Scriptable | Readable | Notify;
+ *(fieldPointer(m_data) + p->propertyData + p->propertyCount * PROPERTY_FIELD_COUNT + index) = notifySignal;
+ }
+}
+
+void QFastMetaBuilder::setProperty(int index, const StringRef &name, const StringRef &type,
+ QFastMetaBuilder::PropertyFlag flags, int notifySignal)
+{
+ Q_ASSERT(!m_data.isEmpty());
+ Q_ASSERT(!name.isEmpty() && !type.isEmpty());
+
+ QMetaObjectPrivate *p = priv(m_data);
+ Q_ASSERT(index < p->propertyCount);
+
+ uint *ptr = fieldPointer(m_data) + p->propertyData + index * PROPERTY_FIELD_COUNT;
+ // properties: name, type, flags
+ ptr[0] = name.offset();
+ ptr[1] = type.offset();
+ if (notifySignal == -1) {
+ ptr[2] = flags | Scriptable | Readable;
+ *(fieldPointer(m_data) + p->propertyData + p->propertyCount * PROPERTY_FIELD_COUNT + index) = 0;
+ } else {
+ ptr[2] = flags | Scriptable | Readable | Notify;
+ *(fieldPointer(m_data) + p->propertyData + p->propertyCount * PROPERTY_FIELD_COUNT + index) = notifySignal;
+ }
+}
+
+void QFastMetaBuilder::setSignal(int index, const StringRef &signature,
+ const StringRef &parameterNames,
+ const StringRef &type)
+{
+ Q_ASSERT(!m_data.isEmpty());
+ Q_ASSERT(!signature.isEmpty());
+
+ QMetaObjectPrivate *p = priv(m_data);
+ int mindex = metaObjectIndexForSignal(index);
+
+ uint *ptr = fieldPointer(m_data) + p->methodData + mindex * METHOD_FIELD_COUNT;
+ // methods: signature, parameters, type, tag, flags
+ ptr[0] = signature.offset();
+ ptr[1] = parameterNames.isEmpty()?m_zeroPtr:parameterNames.offset();
+ ptr[2] = type.isEmpty()?m_zeroPtr:type.offset();
+ ptr[3] = m_zeroPtr;
+ ptr[4] = AccessProtected | MethodSignal;
+}
+
+void QFastMetaBuilder::setMethod(int index, const StringRef &signature,
+ const StringRef &parameterNames,
+ const StringRef &type)
+{
+ Q_ASSERT(!m_data.isEmpty());
+ Q_ASSERT(!signature.isEmpty());
+
+ QMetaObjectPrivate *p = priv(m_data);
+ int mindex = metaObjectIndexForMethod(index);
+
+ uint *ptr = fieldPointer(m_data) + p->methodData + mindex * METHOD_FIELD_COUNT;
+ // methods: signature, parameters, type, tag, flags
+ ptr[0] = signature.offset();
+ ptr[1] = parameterNames.isEmpty()?m_zeroPtr:parameterNames.offset();
+ ptr[2] = type.isEmpty()?m_zeroPtr:type.offset();
+ ptr[3] = m_zeroPtr;
+ ptr[4] = AccessProtected | MethodSlot;
+}
+
+int QFastMetaBuilder::metaObjectIndexForSignal(int index) const
+{
+ Q_ASSERT(!m_data.isEmpty());
+ Q_ASSERT(index < priv(m_data)->signalCount);
+ return index;
+}
+
+int QFastMetaBuilder::metaObjectIndexForMethod(int index) const
+{
+ Q_ASSERT(!m_data.isEmpty());
+
+ const QMetaObjectPrivate *p = priv(m_data);
+ Q_ASSERT(index < (p->methodCount - p->signalCount));
+ return index + p->signalCount;
+}
+
+void QFastMetaBuilder::allocateStringData()
+{
+ if (m_stringDataAllocated < m_stringDataLength) {
+ m_data.resize(m_data.size() + m_stringDataLength - m_stringDataAllocated);
+ m_stringDataAllocated = m_stringDataLength;
+ m_stringData = m_data.data() + header(m_data)->fieldCount * sizeof(uint);
+ }
+}
+
+void QFastMetaBuilder::fromData(QMetaObject *output, const QMetaObject *parent, const QByteArray &data)
+{
+ output->d.superdata = parent;
+ output->d.stringdata = data.constData() + header(data)->fieldCount * sizeof(uint);
+ output->d.data = fieldPointer(data);
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/ftw/qfastmetabuilder_p.h b/src/qml/qml/ftw/qfastmetabuilder_p.h
new file mode 100644
index 0000000000..c1f6a3de5c
--- /dev/null
+++ b/src/qml/qml/ftw/qfastmetabuilder_p.h
@@ -0,0 +1,206 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QFASTMETABUILDER_P_H
+#define QFASTMETABUILDER_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of moc. This header file may change from version to version without notice,
+// or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qglobal.h>
+#include <QtCore/qmetatype.h>
+#include <QtCore/qmetaobject.h>
+
+#include <private/qhashedstring_p.h>
+
+QT_BEGIN_NAMESPACE
+
+struct QMetaObject;
+class QFastMetaBuilder
+{
+public:
+ QFastMetaBuilder();
+ ~QFastMetaBuilder();
+
+ struct StringRef {
+ public:
+ inline StringRef();
+ inline StringRef(const StringRef &);
+ inline StringRef &operator=(const StringRef &);
+
+ inline void load(const QHashedStringRef &);
+ inline void load(const QByteArray &);
+ inline void load(const char *);
+
+ inline bool isEmpty() const;
+ inline QFastMetaBuilder *builder() const;
+ inline int offset() const;
+ inline char *data();
+ inline int length() const;
+ private:
+ friend class QFastMetaBuilder;
+
+ QFastMetaBuilder *_b;
+ int _o;
+ int _l;
+ };
+ StringRef newString(int length);
+
+ // Returns class name
+ StringRef init(int classNameLength,
+ int propertyCount, int methodCount,
+ int signalCount, int classInfoCount);
+
+ void setClassInfo(int index, const StringRef &key, const StringRef &value);
+
+ enum PropertyFlag {
+ None = 0x00000000,
+ Writable = 0x00000002,
+ Resettable = 0x00000004,
+ Constant = 0x00000400,
+ Final = 0x00000800
+ };
+ // void setProperty(int index, const StringRef &name, QMetaType::Type type, int notifySignal = -1);
+ void setProperty(int index, const StringRef &name, const StringRef &type,
+ QMetaType::Type mtype, PropertyFlag flags, int notifySignal = -1);
+ void setProperty(int index, const StringRef &name, const StringRef &type,
+ PropertyFlag flags, int notifySignal = -1);
+ void setMethod(int index, const StringRef &signature,
+ const StringRef &parameterNames = StringRef(),
+ const StringRef &type = StringRef());
+ void setSignal(int index, const StringRef &signature,
+ const StringRef &parameterNames = StringRef(),
+ const StringRef &type = StringRef());
+
+ int metaObjectIndexForSignal(int) const;
+ int metaObjectIndexForMethod(int) const;
+
+ QByteArray toData() const { return m_data; }
+ static void fromData(QMetaObject *, const QMetaObject *parent, const QByteArray &);
+private:
+ friend struct StringRef;
+
+ QByteArray m_data;
+ int m_zeroPtr;
+
+ void allocateStringData();
+ char *m_stringData;
+ int m_stringDataLength;
+ int m_stringDataAllocated;
+};
+
+QFastMetaBuilder::StringRef::StringRef()
+: _b(0), _o(0), _l(0)
+{
+}
+
+QFastMetaBuilder::StringRef::StringRef(const StringRef &o)
+: _b(o._b), _o(o._o), _l(o._l)
+{
+}
+
+QFastMetaBuilder::StringRef &QFastMetaBuilder::StringRef::operator=(const StringRef &o)
+{
+ _b = o._b;
+ _o = o._o;
+ _l = o._l;
+ return *this;
+}
+
+bool QFastMetaBuilder::StringRef::isEmpty() const
+{
+ return _l == 0;
+}
+
+QFastMetaBuilder *QFastMetaBuilder::StringRef::builder() const
+{
+ return _b;
+}
+
+int QFastMetaBuilder::StringRef::offset() const
+{
+ return _o;
+}
+
+char *QFastMetaBuilder::StringRef::data()
+{
+ Q_ASSERT(_b);
+ if (_b->m_stringDataLength != _b->m_stringDataAllocated)
+ _b->allocateStringData();
+ return _b->m_stringData + _o;
+}
+
+int QFastMetaBuilder::StringRef::length() const
+{
+ return _l;
+}
+
+void QFastMetaBuilder::StringRef::load(const QHashedStringRef &str)
+{
+ Q_ASSERT(str.utf8length() == _l);
+ str.writeUtf8(data());
+ *(data() + _l) = 0;
+}
+
+void QFastMetaBuilder::StringRef::load(const QByteArray &str)
+{
+ Q_ASSERT(str.length() == _l);
+ strcpy(data(), str.constData());
+}
+
+void QFastMetaBuilder::StringRef::load(const char *str)
+{
+ Q_ASSERT(strlen(str) == (uint)_l);
+ strcpy(data(), str);
+}
+
+QT_END_NAMESPACE
+
+#endif // QFASTMETABUILDER_P_H
+
diff --git a/src/qml/qml/ftw/qfieldlist_p.h b/src/qml/qml/ftw/qfieldlist_p.h
new file mode 100644
index 0000000000..da5074b3cd
--- /dev/null
+++ b/src/qml/qml/ftw/qfieldlist_p.h
@@ -0,0 +1,426 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QFIELDLIST_P_H
+#define QFIELDLIST_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qglobal.h>
+
+#include <private/qflagpointer_p.h>
+
+// QForwardFieldList is a super simple linked list that can only prepend
+template<class N, N *N::*nextMember>
+class QForwardFieldList
+{
+public:
+ inline QForwardFieldList();
+ inline N *first() const;
+ inline N *takeFirst();
+
+ inline void prepend(N *);
+
+ inline bool isEmpty() const;
+ inline bool isOne() const;
+ inline bool isMany() const;
+
+ static inline N *next(N *v);
+
+ inline bool flag() const;
+ inline void setFlag();
+ inline void clearFlag();
+ inline void setFlagValue(bool);
+
+ inline bool flag2() const;
+ inline void setFlag2();
+ inline void clearFlag2();
+ inline void setFlag2Value(bool);
+private:
+ QFlagPointer<N> _first;
+};
+
+// QFieldList is a simple linked list, that can append and prepend and also
+// maintains a count
+template<class N, N *N::*nextMember>
+class QFieldList
+{
+public:
+ inline QFieldList();
+ inline N *first() const;
+ inline N *takeFirst();
+
+ inline void append(N *);
+ inline void prepend(N *);
+
+ inline bool isEmpty() const;
+ inline bool isOne() const;
+ inline bool isMany() const;
+ inline int count() const;
+
+ inline void append(QFieldList<N, nextMember> &);
+ inline void prepend(QFieldList<N, nextMember> &);
+ inline void insertAfter(N *, QFieldList<N, nextMember> &);
+
+ inline void copyAndClear(QFieldList<N, nextMember> &);
+ inline void copyAndClearAppend(QForwardFieldList<N, nextMember> &);
+ inline void copyAndClearPrepend(QForwardFieldList<N, nextMember> &);
+
+ static inline N *next(N *v);
+
+ inline bool flag() const;
+ inline void setFlag();
+ inline void clearFlag();
+ inline void setFlagValue(bool);
+private:
+ N *_first;
+ N *_last;
+ quint32 _flag:1;
+ quint32 _count:31;
+};
+
+template<class N, N *N::*nextMember>
+QForwardFieldList<N, nextMember>::QForwardFieldList()
+{
+}
+
+template<class N, N *N::*nextMember>
+N *QForwardFieldList<N, nextMember>::first() const
+{
+ return *_first;
+}
+
+template<class N, N *N::*nextMember>
+N *QForwardFieldList<N, nextMember>::takeFirst()
+{
+ N *value = *_first;
+ if (value) {
+ _first = next(value);
+ value->*nextMember = 0;
+ }
+ return value;
+}
+
+template<class N, N *N::*nextMember>
+void QForwardFieldList<N, nextMember>::prepend(N *v)
+{
+ Q_ASSERT(v->*nextMember == 0);
+ v->*nextMember = *_first;
+ _first = v;
+}
+
+template<class N, N *N::*nextMember>
+bool QForwardFieldList<N, nextMember>::isEmpty() const
+{
+ return _first.isNull();
+}
+
+template<class N, N *N::*nextMember>
+bool QForwardFieldList<N, nextMember>::isOne() const
+{
+ return *_first && _first->*nextMember == 0;
+}
+
+template<class N, N *N::*nextMember>
+bool QForwardFieldList<N, nextMember>::isMany() const
+{
+ return *_first && _first->*nextMember != 0;
+}
+
+template<class N, N *N::*nextMember>
+N *QForwardFieldList<N, nextMember>::next(N *v)
+{
+ Q_ASSERT(v);
+ return v->*nextMember;
+}
+
+template<class N, N *N::*nextMember>
+bool QForwardFieldList<N, nextMember>::flag() const
+{
+ return _first.flag();
+}
+
+template<class N, N *N::*nextMember>
+void QForwardFieldList<N, nextMember>::setFlag()
+{
+ _first.setFlag();
+}
+
+template<class N, N *N::*nextMember>
+void QForwardFieldList<N, nextMember>::clearFlag()
+{
+ _first.clearFlag();
+}
+
+template<class N, N *N::*nextMember>
+void QForwardFieldList<N, nextMember>::setFlagValue(bool v)
+{
+ _first.setFlagValue(v);
+}
+
+template<class N, N *N::*nextMember>
+bool QForwardFieldList<N, nextMember>::flag2() const
+{
+ return _first.flag2();
+}
+
+template<class N, N *N::*nextMember>
+void QForwardFieldList<N, nextMember>::setFlag2()
+{
+ _first.setFlag2();
+}
+
+template<class N, N *N::*nextMember>
+void QForwardFieldList<N, nextMember>::clearFlag2()
+{
+ _first.clearFlag2();
+}
+
+template<class N, N *N::*nextMember>
+void QForwardFieldList<N, nextMember>::setFlag2Value(bool v)
+{
+ _first.setFlag2Value(v);
+}
+
+template<class N, N *N::*nextMember>
+QFieldList<N, nextMember>::QFieldList()
+: _first(0), _last(0), _flag(0), _count(0)
+{
+}
+
+template<class N, N *N::*nextMember>
+N *QFieldList<N, nextMember>::first() const
+{
+ return _first;
+}
+
+template<class N, N *N::*nextMember>
+N *QFieldList<N, nextMember>::takeFirst()
+{
+ N *value = _first;
+ if (value) {
+ _first = next(value);
+ if (_last == value) {
+ Q_ASSERT(_first == 0);
+ _last = 0;
+ }
+ value->*nextMember = 0;
+ --_count;
+ }
+ return value;
+}
+
+template<class N, N *N::*nextMember>
+void QFieldList<N, nextMember>::append(N *v)
+{
+ Q_ASSERT(v->*nextMember == 0);
+ if (isEmpty()) {
+ _first = v;
+ _last = v;
+ } else {
+ _last->*nextMember = v;
+ _last = v;
+ }
+ ++_count;
+}
+
+template<class N, N *N::*nextMember>
+void QFieldList<N, nextMember>::prepend(N *v)
+{
+ Q_ASSERT(v->*nextMember == 0);
+ if (isEmpty()) {
+ _first = v;
+ _last = v;
+ } else {
+ v->*nextMember = _first;
+ _first = v;
+ }
+ ++_count;
+}
+
+template<class N, N *N::*nextMember>
+bool QFieldList<N, nextMember>::isEmpty() const
+{
+ return _count == 0;
+}
+
+template<class N, N *N::*nextMember>
+bool QFieldList<N, nextMember>::isOne() const
+{
+ return _count == 1;
+}
+
+template<class N, N *N::*nextMember>
+bool QFieldList<N, nextMember>::isMany() const
+{
+ return _count > 1;
+}
+
+template<class N, N *N::*nextMember>
+int QFieldList<N, nextMember>::count() const
+{
+ return _count;
+}
+
+template<class N, N *N::*nextMember>
+N *QFieldList<N, nextMember>::next(N *v)
+{
+ Q_ASSERT(v);
+ return v->*nextMember;
+}
+
+template<class N, N *N::*nextMember>
+void QFieldList<N, nextMember>::append(QFieldList<N, nextMember> &o)
+{
+ if (!o.isEmpty()) {
+ if (isEmpty()) {
+ _first = o._first;
+ _last = o._last;
+ _count = o._count;
+ } else {
+ _last->*nextMember = o._first;
+ _last = o._last;
+ _count += o._count;
+ }
+ o._first = o._last = 0; o._count = 0;
+ }
+}
+
+template<class N, N *N::*nextMember>
+void QFieldList<N, nextMember>::prepend(QFieldList<N, nextMember> &o)
+{
+ if (!o.isEmpty()) {
+ if (isEmpty()) {
+ _first = o._first;
+ _last = o._last;
+ _count = o._count;
+ } else {
+ o._last->*nextMember = _first;
+ _first = o._first;
+ _count += o._count;
+ }
+ o._first = o._last = 0; o._count = 0;
+ }
+}
+
+template<class N, N *N::*nextMember>
+void QFieldList<N, nextMember>::insertAfter(N *after, QFieldList<N, nextMember> &o)
+{
+ if (after == 0) {
+ prepend(o);
+ } else if (after == _last) {
+ append(o);
+ } else if (!o.isEmpty()) {
+ if (isEmpty()) {
+ _first = o._first;
+ _last = o._last;
+ _count = o._count;
+ } else {
+ o._last->*nextMember = after->*nextMember;
+ after->*nextMember = o._first;
+ _count += o._count;
+ }
+ o._first = o._last = 0; o._count = 0;
+ }
+}
+
+template<class N, N *N::*nextMember>
+void QFieldList<N, nextMember>::copyAndClear(QFieldList<N, nextMember> &o)
+{
+ _first = o._first;
+ _last = o._last;
+ _count = o._count;
+ o._first = o._last = 0;
+ o._count = 0;
+}
+
+template<class N, N *N::*nextMember>
+void QFieldList<N, nextMember>::copyAndClearAppend(QForwardFieldList<N, nextMember> &o)
+{
+ _first = 0;
+ _last = 0;
+ _count = 0;
+ while (N *n = o.takeFirst()) append(n);
+}
+
+template<class N, N *N::*nextMember>
+void QFieldList<N, nextMember>::copyAndClearPrepend(QForwardFieldList<N, nextMember> &o)
+{
+ _first = 0;
+ _last = 0;
+ _count = 0;
+ while (N *n = o.takeFirst()) prepend(n);
+}
+
+template<class N, N *N::*nextMember>
+bool QFieldList<N, nextMember>::flag() const
+{
+ return _flag;
+}
+
+template<class N, N *N::*nextMember>
+void QFieldList<N, nextMember>::setFlag()
+{
+ _flag = true;
+}
+
+template<class N, N *N::*nextMember>
+void QFieldList<N, nextMember>::clearFlag()
+{
+ _flag = false;
+}
+
+template<class N, N *N::*nextMember>
+void QFieldList<N, nextMember>::setFlagValue(bool v)
+{
+ _flag = v;
+}
+
+#endif // QFIELDLIST_P_H
diff --git a/src/qml/qml/ftw/qfinitestack_p.h b/src/qml/qml/ftw/qfinitestack_p.h
new file mode 100644
index 0000000000..c5a9fbaedb
--- /dev/null
+++ b/src/qml/qml/ftw/qfinitestack_p.h
@@ -0,0 +1,186 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QFINITESTACK_P_H
+#define QFINITESTACK_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qglobal.h>
+
+QT_BEGIN_NAMESPACE
+
+template<typename T>
+struct QFiniteStack {
+ inline QFiniteStack();
+ inline ~QFiniteStack();
+
+ inline void deallocate();
+ inline void allocate(int size);
+
+ inline bool isEmpty() const;
+ inline const T &top() const;
+ inline T &top();
+ inline void push(const T &o);
+ inline T pop();
+ inline int count() const;
+ inline const T &at(int index) const;
+ inline T &operator[](int index);
+private:
+ T *_array;
+ int _alloc;
+ int _size;
+};
+
+template<typename T>
+QFiniteStack<T>::QFiniteStack()
+: _array(0), _alloc(0), _size(0)
+{
+}
+
+template<typename T>
+QFiniteStack<T>::~QFiniteStack()
+{
+ deallocate();
+}
+
+template<typename T>
+bool QFiniteStack<T>::isEmpty() const
+{
+ return _size == 0;
+}
+
+template<typename T>
+const T &QFiniteStack<T>::top() const
+{
+ return _array[_size - 1];
+}
+
+template<typename T>
+T &QFiniteStack<T>::top()
+{
+ return _array[_size - 1];
+}
+
+template<typename T>
+void QFiniteStack<T>::push(const T &o)
+{
+ if (QTypeInfo<T>::isComplex) {
+ new (_array + _size++) T(o);
+ } else {
+ _array[_size++] = o;
+ }
+}
+
+template<typename T>
+T QFiniteStack<T>::pop()
+{
+ --_size;
+
+ if (QTypeInfo<T>::isComplex) {
+ T rv = _array[_size];
+ (_array + _size)->~T();
+ return rv;
+ } else {
+ return _array[_size];
+ }
+}
+
+template<typename T>
+int QFiniteStack<T>::count() const
+{
+ return _size;
+}
+
+template<typename T>
+const T &QFiniteStack<T>::at(int index) const
+{
+ return _array[index];
+}
+
+template<typename T>
+T &QFiniteStack<T>::operator[](int index)
+{
+ return _array[index];
+}
+
+template<typename T>
+void QFiniteStack<T>::allocate(int size)
+{
+ Q_ASSERT(_array == 0);
+ Q_ASSERT(_alloc == 0);
+ Q_ASSERT(_size == 0);
+
+ if (!size) return;
+
+ _array = (T *)qMalloc(size * sizeof(T));
+ _alloc = size;
+}
+
+template<typename T>
+void QFiniteStack<T>::deallocate()
+{
+ if (QTypeInfo<T>::isComplex) {
+ T *i = _array + _size;
+ while (i != _array)
+ (--i)->~T();
+ }
+
+ qFree(_array);
+
+ _array = 0;
+ _alloc = 0;
+ _size = 0;
+}
+
+QT_END_NAMESPACE
+
+#endif // QFINITESTACK_P_H
+
diff --git a/src/qml/qml/ftw/qflagpointer_p.h b/src/qml/qml/ftw/qflagpointer_p.h
new file mode 100644
index 0000000000..a4b20d9e2a
--- /dev/null
+++ b/src/qml/qml/ftw/qflagpointer_p.h
@@ -0,0 +1,338 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QFLAGPOINTER_P_H
+#define QFLAGPOINTER_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qglobal.h>
+
+QT_BEGIN_NAMESPACE
+
+template<typename T>
+class QFlagPointer {
+public:
+ inline QFlagPointer();
+ inline QFlagPointer(T *);
+ inline QFlagPointer(const QFlagPointer<T> &o);
+
+ inline bool isNull() const;
+
+ inline bool flag() const;
+ inline void setFlag();
+ inline void clearFlag();
+ inline void setFlagValue(bool);
+
+ inline bool flag2() const;
+ inline void setFlag2();
+ inline void clearFlag2();
+ inline void setFlag2Value(bool);
+
+ inline QFlagPointer<T> &operator=(const QFlagPointer &o);
+ inline QFlagPointer<T> &operator=(T *);
+
+ inline T *operator->() const;
+ inline T *operator*() const;
+
+private:
+ quintptr ptr_value;
+
+ static const quintptr FlagBit = 0x1;
+ static const quintptr Flag2Bit = 0x2;
+ static const quintptr FlagsMask = FlagBit | Flag2Bit;
+};
+
+template<typename T, typename T2>
+class QBiPointer {
+public:
+ inline QBiPointer();
+ inline QBiPointer(T *);
+ inline QBiPointer(T2 *);
+ inline QBiPointer(const QBiPointer<T, T2> &o);
+
+ inline bool isNull() const;
+ inline bool isT1() const;
+ inline bool isT2() const;
+
+ inline bool flag() const;
+ inline void setFlag();
+ inline void clearFlag();
+ inline void setFlagValue(bool);
+
+ inline QBiPointer<T, T2> &operator=(const QBiPointer<T, T2> &o);
+ inline QBiPointer<T, T2> &operator=(T *);
+ inline QBiPointer<T, T2> &operator=(T2 *);
+
+ inline T *asT1() const;
+ inline T2 *asT2() const;
+
+private:
+ quintptr ptr_value;
+
+ static const quintptr FlagBit = 0x1;
+ static const quintptr Flag2Bit = 0x2;
+ static const quintptr FlagsMask = FlagBit | Flag2Bit;
+};
+
+template<typename T>
+QFlagPointer<T>::QFlagPointer()
+: ptr_value(0)
+{
+}
+
+template<typename T>
+QFlagPointer<T>::QFlagPointer(T *v)
+: ptr_value(quintptr(v))
+{
+ Q_ASSERT((ptr_value & FlagsMask) == 0);
+}
+
+template<typename T>
+QFlagPointer<T>::QFlagPointer(const QFlagPointer<T> &o)
+: ptr_value(o.ptr_value)
+{
+}
+
+template<typename T>
+bool QFlagPointer<T>::isNull() const
+{
+ return 0 == (ptr_value & (~FlagsMask));
+}
+
+template<typename T>
+bool QFlagPointer<T>::flag() const
+{
+ return ptr_value & FlagBit;
+}
+
+template<typename T>
+void QFlagPointer<T>::setFlag()
+{
+ ptr_value |= FlagBit;
+}
+
+template<typename T>
+void QFlagPointer<T>::clearFlag()
+{
+ ptr_value &= ~FlagBit;
+}
+
+template<typename T>
+void QFlagPointer<T>::setFlagValue(bool v)
+{
+ if (v) setFlag();
+ else clearFlag();
+}
+
+template<typename T>
+bool QFlagPointer<T>::flag2() const
+{
+ return ptr_value & Flag2Bit;
+}
+
+template<typename T>
+void QFlagPointer<T>::setFlag2()
+{
+ ptr_value|= Flag2Bit;
+}
+
+template<typename T>
+void QFlagPointer<T>::clearFlag2()
+{
+ ptr_value &= ~Flag2Bit;
+}
+
+template<typename T>
+void QFlagPointer<T>::setFlag2Value(bool v)
+{
+ if (v) setFlag2();
+ else clearFlag2();
+}
+
+template<typename T>
+QFlagPointer<T> &QFlagPointer<T>::operator=(const QFlagPointer &o)
+{
+ ptr_value = o.ptr_value;
+ return *this;
+}
+
+template<typename T>
+QFlagPointer<T> &QFlagPointer<T>::operator=(T *o)
+{
+ Q_ASSERT((quintptr(o) & FlagsMask) == 0);
+
+ ptr_value = quintptr(o) | (ptr_value & FlagsMask);
+ return *this;
+}
+
+template<typename T>
+T *QFlagPointer<T>::operator->() const
+{
+ return (T *)(ptr_value & ~FlagsMask);
+}
+
+template<typename T>
+T *QFlagPointer<T>::operator*() const
+{
+ return (T *)(ptr_value & ~FlagsMask);
+}
+
+template<typename T, typename T2>
+QBiPointer<T, T2>::QBiPointer()
+: ptr_value(0)
+{
+}
+
+template<typename T, typename T2>
+QBiPointer<T, T2>::QBiPointer(T *v)
+: ptr_value(quintptr(v))
+{
+ Q_ASSERT((quintptr(v) & FlagsMask) == 0);
+}
+
+template<typename T, typename T2>
+QBiPointer<T, T2>::QBiPointer(T2 *v)
+: ptr_value(quintptr(v) | Flag2Bit)
+{
+ Q_ASSERT((quintptr(v) & FlagsMask) == 0);
+}
+
+template<typename T, typename T2>
+QBiPointer<T, T2>::QBiPointer(const QBiPointer<T, T2> &o)
+: ptr_value(o.ptr_value)
+{
+}
+
+template<typename T, typename T2>
+bool QBiPointer<T, T2>::isNull() const
+{
+ return 0 == (ptr_value & (~FlagsMask));
+}
+
+template<typename T, typename T2>
+bool QBiPointer<T, T2>::isT1() const
+{
+ return !(ptr_value & Flag2Bit);
+}
+
+template<typename T, typename T2>
+bool QBiPointer<T, T2>::isT2() const
+{
+ return ptr_value & Flag2Bit;
+}
+
+template<typename T, typename T2>
+bool QBiPointer<T, T2>::flag() const
+{
+ return ptr_value & FlagBit;
+}
+
+template<typename T, typename T2>
+void QBiPointer<T, T2>::setFlag()
+{
+ ptr_value |= FlagBit;
+}
+
+template<typename T, typename T2>
+void QBiPointer<T, T2>::clearFlag()
+{
+ ptr_value &= ~FlagBit;
+}
+
+template<typename T, typename T2>
+void QBiPointer<T, T2>::setFlagValue(bool v)
+{
+ if (v) setFlag();
+ else clearFlag();
+}
+
+template<typename T, typename T2>
+QBiPointer<T, T2> &QBiPointer<T, T2>::operator=(const QBiPointer<T, T2> &o)
+{
+ ptr_value = o.ptr_value;
+ return *this;
+}
+
+template<typename T, typename T2>
+QBiPointer<T, T2> &QBiPointer<T, T2>::operator=(T *o)
+{
+ Q_ASSERT((quintptr(o) & FlagsMask) == 0);
+
+ ptr_value = quintptr(o) | (ptr_value & FlagBit);
+ return *this;
+}
+
+template<typename T, typename T2>
+QBiPointer<T, T2> &QBiPointer<T, T2>::operator=(T2 *o)
+{
+ Q_ASSERT((quintptr(o) & FlagsMask) == 0);
+
+ ptr_value = quintptr(o) | (ptr_value & FlagBit) | Flag2Bit;
+ return *this;
+}
+
+template<typename T, typename T2>
+T *QBiPointer<T, T2>::asT1() const
+{
+ Q_ASSERT(isT1());
+ return (T *)(ptr_value & ~FlagsMask);
+}
+
+template<typename T, typename T2>
+T2 *QBiPointer<T, T2>::asT2() const
+{
+ Q_ASSERT(isT2());
+ return (T2 *)(ptr_value & ~FlagsMask);
+}
+
+QT_END_NAMESPACE
+
+#endif // QFLAGPOINTER_P_H
diff --git a/src/qml/qml/ftw/qhashedstring.cpp b/src/qml/qml/ftw/qhashedstring.cpp
new file mode 100644
index 0000000000..1f09d50ed3
--- /dev/null
+++ b/src/qml/qml/ftw/qhashedstring.cpp
@@ -0,0 +1,490 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qhashedstring_p.h"
+
+// This is a reimplementation of V8's string hash algorithm. It is significantly
+// faster to do it here than call into V8, but it adds the maintainence burden of
+// ensuring that the two hashes are identical. We Q_ASSERT() that the two return
+// the same value. If these asserts start to fail, the hash code needs to be
+// synced with V8.
+namespace String {
+ static const int kMaxArrayIndexSize = 10;
+ static const int kMaxHashCalcLength = 16383;
+ static const int kNofHashBitFields = 2;
+ static const int kHashShift = kNofHashBitFields;
+ static const int kIsNotArrayIndexMask = 1 << 1;
+ static const int kArrayIndexValueBits = 24;
+ static const int kArrayIndexHashLengthShift = kArrayIndexValueBits + kNofHashBitFields;
+ static const int kMaxCachedArrayIndexLength = 7;
+};
+
+template <typename schar>
+uint32_t calculateHash(const schar* chars, int length) {
+ if (length > String::kMaxHashCalcLength) {
+ // V8 trivial hash
+ return (length << String::kHashShift) | String::kIsNotArrayIndexMask;
+ }
+
+ uint32_t raw_running_hash = 0;
+ uint32_t array_index = 0;
+ bool is_array_index = (0 < length && length <= String::kMaxArrayIndexSize);
+ bool is_first_char = true;
+
+ int ii = 0;
+ for (;is_array_index && ii < length; ++ii) {
+ quint32 c = *chars++;
+
+ raw_running_hash += c;
+ raw_running_hash += (raw_running_hash << 10);
+ raw_running_hash ^= (raw_running_hash >> 6);
+
+ if (c < '0' || c > '9') {
+ is_array_index = false;
+ } else {
+ int d = c - '0';
+ if (is_first_char) {
+ is_first_char = false;
+ if (c == '0' && length > 1) {
+ is_array_index = false;
+ continue;
+ }
+ }
+ if (array_index > 429496729U - ((d + 2) >> 3)) {
+ is_array_index = false;
+ } else {
+ array_index = array_index * 10 + d;
+ }
+ }
+ }
+
+ for (;ii < length; ++ii) {
+ raw_running_hash += *chars++;
+ raw_running_hash += (raw_running_hash << 10);
+ raw_running_hash ^= (raw_running_hash >> 6);
+ }
+
+ if (is_array_index) {
+ array_index <<= String::kHashShift;
+ array_index |= length << String::kArrayIndexHashLengthShift;
+ return array_index;
+ } else {
+ raw_running_hash += (raw_running_hash << 3);
+ raw_running_hash ^= (raw_running_hash >> 11);
+ raw_running_hash += (raw_running_hash << 15);
+ if (raw_running_hash == 0) {
+ raw_running_hash = 27;
+ }
+
+ return (raw_running_hash << String::kHashShift) | String::kIsNotArrayIndexMask;
+ }
+}
+
+inline quint32 stringHash(const QChar* data, int length)
+{
+ quint32 rv = calculateHash<quint16>((quint16*)data, length) >> String::kHashShift;
+ Q_ASSERT(rv == v8::String::ComputeHash((uint16_t*)data, length));
+ return rv;
+}
+
+inline quint32 stringHash(const char *data, int length)
+{
+ quint32 rv = calculateHash<quint8>((quint8*)data, length) >> String::kHashShift;
+ Q_ASSERT(rv == v8::String::ComputeHash((char *)data, length));
+ return rv;
+}
+
+void QHashedString::computeHash() const
+{
+ m_hash = stringHash(constData(), length());
+}
+
+void QHashedStringRef::computeHash() const
+{
+ m_hash = stringHash(m_data, m_length);
+}
+
+void QHashedCStringRef::computeHash() const
+{
+ m_hash = stringHash(m_data, m_length);
+}
+
+/*
+ A QHash has initially around pow(2, MinNumBits) buckets. For
+ example, if MinNumBits is 4, it has 17 buckets.
+*/
+const int MinNumBits = 4;
+
+/*
+ The prime_deltas array is a table of selected prime values, even
+ though it doesn't look like one. The primes we are using are 1,
+ 2, 5, 11, 17, 37, 67, 131, 257, ..., i.e. primes in the immediate
+ surrounding of a power of two.
+
+ The primeForNumBits() function returns the prime associated to a
+ power of two. For example, primeForNumBits(8) returns 257.
+*/
+
+static const uchar prime_deltas[] = {
+ 0, 0, 1, 3, 1, 5, 3, 3, 1, 9, 7, 5, 3, 9, 25, 3,
+ 1, 21, 3, 21, 7, 15, 9, 5, 3, 29, 15, 0, 0, 0, 0, 0
+};
+
+static inline int primeForNumBits(int numBits)
+{
+ return (1 << numBits) + prime_deltas[numBits];
+}
+
+void QStringHashData::rehashToSize(int size, IteratorData first,
+ IteratorData (*Iterate)(const IteratorData &),
+ QStringHashNode *skip)
+{
+ short bits = qMax(MinNumBits, (int)numBits);
+ while (primeForNumBits(bits) < size) bits++;
+
+ if (bits > numBits)
+ rehashToBits(bits, first, Iterate, skip);
+}
+
+void QStringHashData::rehashToBits(short bits, IteratorData first,
+ IteratorData (*Iterate)(const IteratorData &),
+ QStringHashNode *skip)
+{
+ numBits = qMax(MinNumBits, (int)bits);
+
+ int nb = primeForNumBits(numBits);
+ if (nb == numBuckets && buckets)
+ return;
+
+ numBuckets = nb;
+
+#ifdef QSTRINGHASH_LINK_DEBUG
+ if (linkCount)
+ qFatal("QStringHash: Illegal attempt to rehash a linked hash.");
+#endif
+
+ delete [] buckets;
+ buckets = new QStringHashNode *[numBuckets];
+ ::memset(buckets, 0, sizeof(QStringHashNode *) * numBuckets);
+
+ IteratorData nodeList = first;
+ while (nodeList.n) {
+ if (nodeList.n != skip) {
+ int bucket = nodeList.n->hash % numBuckets;
+ nodeList.n->next = buckets[bucket];
+ buckets[bucket] = nodeList.n;
+ }
+
+ nodeList = Iterate(nodeList);
+ }
+}
+
+// Copy of QString's qMemCompare
+bool QHashedString::compare(const QChar *lhs, const QChar *rhs, int length)
+{
+ Q_ASSERT(lhs && rhs);
+ const quint16 *a = (const quint16 *)lhs;
+ const quint16 *b = (const quint16 *)rhs;
+
+ if (a == b || !length)
+ return true;
+
+ register union {
+ const quint16 *w;
+ const quint32 *d;
+ quintptr value;
+ } sa, sb;
+ sa.w = a;
+ sb.w = b;
+
+ // check alignment
+ if ((sa.value & 2) == (sb.value & 2)) {
+ // both addresses have the same alignment
+ if (sa.value & 2) {
+ // both addresses are not aligned to 4-bytes boundaries
+ // compare the first character
+ if (*sa.w != *sb.w)
+ return false;
+ --length;
+ ++sa.w;
+ ++sb.w;
+
+ // now both addresses are 4-bytes aligned
+ }
+
+ // both addresses are 4-bytes aligned
+ // do a fast 32-bit comparison
+ register const quint32 *e = sa.d + (length >> 1);
+ for ( ; sa.d != e; ++sa.d, ++sb.d) {
+ if (*sa.d != *sb.d)
+ return false;
+ }
+
+ // do we have a tail?
+ return (length & 1) ? *sa.w == *sb.w : true;
+ } else {
+ // one of the addresses isn't 4-byte aligned but the other is
+ register const quint16 *e = sa.w + length;
+ for ( ; sa.w != e; ++sa.w, ++sb.w) {
+ if (*sa.w != *sb.w)
+ return false;
+ }
+ }
+ return true;
+}
+
+// Unicode stuff
+static inline bool isUnicodeNonCharacter(uint ucs4)
+{
+ // Unicode has a couple of "non-characters" that one can use internally,
+ // but are not allowed to be used for text interchange.
+ //
+ // Those are the last two entries each Unicode Plane (U+FFFE, U+FFFF,
+ // U+1FFFE, U+1FFFF, etc.) as well as the entries between U+FDD0 and
+ // U+FDEF (inclusive)
+
+ return (ucs4 & 0xfffe) == 0xfffe
+ || (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;
+ }
+}
+
+void QHashedStringRef::computeUtf8Length() const
+{
+ if (m_length)
+ m_utf8length = utf8LengthFromUtf16(m_data, m_length);
+ else
+ m_utf8length = 0;
+}
+
+QHashedStringRef QHashedStringRef::mid(int offset, int length) const
+{
+ Q_ASSERT(offset < m_length);
+ return QHashedStringRef(m_data + offset,
+ (length == -1 || (offset + length) > m_length)?(m_length - offset):length);
+}
+
+bool QHashedStringRef::endsWith(const QString &s) const
+{
+ return s.length() < m_length &&
+ QHashedString::compare(s.constData(), m_data + m_length - s.length(), s.length());
+}
+
+bool QHashedStringRef::startsWith(const QString &s) const
+{
+ return s.length() < m_length &&
+ QHashedString::compare(s.constData(), m_data, s.length());
+}
+
+QString QHashedStringRef::toString() const
+{
+ if (m_length == 0)
+ return QString();
+ return QString(m_data, m_length);
+}
+
+QByteArray QHashedStringRef::toUtf8() const
+{
+ if (m_length == 0)
+ return QByteArray();
+
+ QByteArray result;
+ result.resize(utf8length());
+ writeUtf8(result.data());
+ return result;
+}
+
+void QHashedStringRef::writeUtf8(char *output) const
+{
+ if (m_length) {
+ int ulen = utf8length();
+ if (ulen == m_length) {
+ // Must be a latin1 string
+ uchar *o = (uchar *)output;
+ const QChar *c = m_data;
+ while (ulen--)
+ *o++ = (uchar)((*c++).unicode());
+ } else {
+ utf8FromUtf16(output, m_data, m_length);
+ }
+ }
+}
+
+QString QHashedCStringRef::toUtf16() const
+{
+ if (m_length == 0)
+ return QString();
+
+ QString rv;
+ rv.resize(m_length);
+ writeUtf16((uint16_t*)rv.data());
+ return rv;
+}
+
diff --git a/src/qml/qml/ftw/qhashedstring_p.h b/src/qml/qml/ftw/qhashedstring_p.h
new file mode 100644
index 0000000000..f575285ff6
--- /dev/null
+++ b/src/qml/qml/ftw/qhashedstring_p.h
@@ -0,0 +1,1418 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QHASHEDSTRING_P_H
+#define QHASHEDSTRING_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qglobal.h>
+#include <QtCore/qstring.h>
+#include <private/qv8_p.h>
+
+#include <private/qflagpointer_p.h>
+
+QT_BEGIN_NAMESPACE
+
+// Enable this to debug hash linking assumptions.
+// #define QSTRINGHASH_LINK_DEBUG
+
+class QHashedStringRef;
+class Q_AUTOTEST_EXPORT QHashedString : public QString
+{
+public:
+ inline QHashedString();
+ inline QHashedString(const QString &string);
+ inline QHashedString(const QString &string, quint32);
+ inline QHashedString(const QHashedString &string);
+
+ inline QHashedString &operator=(const QHashedString &string);
+ inline bool operator==(const QHashedString &string) const;
+ inline bool operator==(const QHashedStringRef &string) const;
+
+ inline quint32 hash() const;
+ inline quint32 existingHash() const;
+
+ static inline bool isUpper(const QChar &);
+
+ static bool compare(const QChar *lhs, const QChar *rhs, int length);
+ static inline bool compare(const QChar *lhs, const char *rhs, int length);
+ static inline bool compare(const char *lhs, const char *rhs, int length);
+private:
+ friend class QHashedStringRef;
+ friend class QStringHashNode;
+
+ void computeHash() const;
+ mutable quint32 m_hash;
+};
+
+class Q_AUTOTEST_EXPORT QHashedV8String
+{
+public:
+ inline QHashedV8String();
+ explicit inline QHashedV8String(v8::Handle<v8::String>);
+ inline QHashedV8String(const QHashedV8String &string);
+ inline QHashedV8String &operator=(const QHashedV8String &other);
+
+ inline bool operator==(const QHashedV8String &string);
+
+ inline quint32 hash() const;
+ inline int length() const;
+ inline quint32 symbolId() const;
+
+ inline v8::Handle<v8::String> string() const;
+
+ inline QString toString() const;
+
+private:
+ v8::String::CompleteHashData m_hash;
+ v8::Handle<v8::String> m_string;
+};
+
+class QHashedCStringRef;
+class Q_AUTOTEST_EXPORT QHashedStringRef
+{
+public:
+ inline QHashedStringRef();
+ inline QHashedStringRef(const QString &);
+ inline QHashedStringRef(const QStringRef &);
+ inline QHashedStringRef(const QChar *, int);
+ inline QHashedStringRef(const QChar *, int, quint32);
+ inline QHashedStringRef(const QHashedString &);
+ inline QHashedStringRef(const QHashedStringRef &);
+ inline QHashedStringRef &operator=(const QHashedStringRef &);
+
+ inline bool operator==(const QString &string) const;
+ inline bool operator==(const QHashedString &string) const;
+ inline bool operator==(const QHashedStringRef &string) const;
+ inline bool operator==(const QHashedCStringRef &string) const;
+ inline bool operator!=(const QString &string) const;
+ inline bool operator!=(const QHashedString &string) const;
+ inline bool operator!=(const QHashedStringRef &string) const;
+ inline bool operator!=(const QHashedCStringRef &string) const;
+
+ inline quint32 hash() const;
+
+ inline const QChar &at(int) const;
+ inline const QChar *constData() const;
+ bool startsWith(const QString &) const;
+ bool endsWith(const QString &) const;
+ QHashedStringRef mid(int, int) const;
+
+ inline bool isEmpty() const;
+ inline int length() const;
+ inline bool startsWithUpper() const;
+
+ QString toString() const;
+
+ inline int utf8length() const;
+ QByteArray toUtf8() const;
+ void writeUtf8(char *) const;
+private:
+ friend class QHashedString;
+
+ void computeHash() const;
+ void computeUtf8Length() const;
+
+ const QChar *m_data;
+ int m_length;
+ mutable int m_utf8length;
+ mutable quint32 m_hash;
+};
+
+class Q_AUTOTEST_EXPORT QHashedCStringRef
+{
+public:
+ inline QHashedCStringRef();
+ inline QHashedCStringRef(const char *, int);
+ inline QHashedCStringRef(const char *, int, quint32);
+ inline QHashedCStringRef(const QHashedCStringRef &);
+
+ inline quint32 hash() const;
+
+ inline const char *constData() const;
+ inline int length() const;
+
+ QString toUtf16() const;
+ inline int utf16length() const;
+ inline void writeUtf16(QChar *) const;
+ inline void writeUtf16(uint16_t *) const;
+private:
+ friend class QHashedStringRef;
+
+ void computeHash() const;
+
+ const char *m_data;
+ int m_length;
+ mutable quint32 m_hash;
+};
+
+class QStringHashData;
+class Q_AUTOTEST_EXPORT QStringHashNode
+{
+public:
+ QStringHashNode()
+ : length(0), hash(0), symbolId(0), ckey(0)
+ {
+ }
+
+ QStringHashNode(const QHashedString &key)
+ : length(key.length()), hash(key.hash()), symbolId(0)
+ {
+ strData = const_cast<QHashedString &>(key).data_ptr();
+ setQString(true);
+ strData->ref.ref();
+ }
+
+ QStringHashNode(const QHashedCStringRef &key)
+ : length(key.length()), hash(key.hash()), symbolId(0), ckey(key.constData())
+ {
+ }
+
+ QStringHashNode(const QStringHashNode &o)
+ : length(o.length), hash(o.hash), symbolId(o.symbolId), ckey(o.ckey)
+ {
+ setQString(o.isQString());
+ if (isQString()) { strData->ref.ref(); }
+ }
+
+ ~QStringHashNode()
+ {
+ if (isQString()) { if (!strData->ref.deref()) free(strData); }
+ }
+
+ QFlagPointer<QStringHashNode> next;
+
+ qint32 length;
+ quint32 hash;
+ quint32 symbolId;
+
+ union {
+ const char *ckey;
+ QStringData *strData;
+ };
+
+ bool isQString() const { return next.flag(); }
+ void setQString(bool v) { if (v) next.setFlag(); else next.clearFlag(); }
+
+ inline char *cStrData() const { return (char *)ckey; }
+ inline uint16_t *utf16Data() const { return (uint16_t *)strData->data(); }
+
+ inline bool equals(v8::Handle<v8::String> string) {
+ return isQString()?string->Equals(utf16Data(), length):
+ string->Equals(cStrData(), length);
+ }
+
+ inline bool symbolEquals(const QHashedV8String &string) {
+ Q_ASSERT(string.symbolId() != 0);
+ return length == string.length() && hash == string.hash() &&
+ (string.symbolId() == symbolId || equals(string.string()));
+ }
+
+ inline bool equals(const QHashedV8String &string) {
+ return length == string.length() && hash == string.hash() &&
+ equals(string.string());
+ }
+
+ inline bool equals(const QHashedStringRef &string) {
+ return length == string.length() &&
+ hash == string.hash() &&
+ (isQString()?QHashedString::compare(string.constData(), (QChar *)utf16Data(), length):
+ QHashedString::compare(string.constData(), cStrData(), length));
+ }
+
+ inline bool equals(const QHashedCStringRef &string) {
+ return length == string.length() &&
+ hash == string.hash() &&
+ (isQString()?QHashedString::compare((QChar *)utf16Data(), string.constData(), length):
+ QHashedString::compare(string.constData(), cStrData(), length));
+ }
+};
+
+class Q_AUTOTEST_EXPORT QStringHashData
+{
+public:
+ QStringHashData()
+ : buckets(0), numBuckets(0), size(0), numBits(0)
+#ifdef QSTRINGHASH_LINK_DEBUG
+ , linkCount(0)
+#endif
+ {}
+
+ QStringHashNode **buckets;
+ int numBuckets;
+ int size;
+ short numBits;
+#ifdef QSTRINGHASH_LINK_DEBUG
+ int linkCount;
+#endif
+
+ struct IteratorData {
+ IteratorData() : n(0), p(0) {}
+ QStringHashNode *n;
+ void *p;
+ };
+ void rehashToBits(short, IteratorData, IteratorData (*Iterate)(const IteratorData &),
+ QStringHashNode *skip = 0);
+ void rehashToSize(int, IteratorData, IteratorData (*Iterate)(const IteratorData &),
+ QStringHashNode *skip = 0);
+
+private:
+ QStringHashData(const QStringHashData &);
+ QStringHashData &operator=(const QStringHashData &);
+};
+
+template<class T>
+class QStringHash
+{
+public:
+ struct Node : public QStringHashNode {
+ Node(const QHashedString &key, const T &value) : QStringHashNode(key), value(value) {}
+ Node(const QHashedCStringRef &key, const T &value) : QStringHashNode(key), value(value) {}
+ Node(const Node &o) : QStringHashNode(o), value(o.value) {}
+ Node() {}
+ T value;
+ };
+ struct NewedNode : public Node {
+ NewedNode(const QHashedString &key, const T &value) : Node(key, value), nextNewed(0) {}
+ NewedNode(const QHashedCStringRef &key, const T &value) : Node(key, value), nextNewed(0) {}
+ NewedNode(const Node &o) : Node(o), nextNewed(0) {}
+ NewedNode *nextNewed;
+ };
+ struct ReservedNodePool
+ {
+ ReservedNodePool() : count(0), used(0), nodes(0) {}
+ ~ReservedNodePool() { delete [] nodes; }
+ int count;
+ int used;
+ Node *nodes;
+ };
+
+ QStringHashData data;
+ NewedNode *newedNodes;
+ ReservedNodePool *nodePool;
+ const QStringHash<T> *link;
+
+ inline Node *findNode(const QString &) const;
+ inline Node *findNode(const QHashedString &) const;
+ inline Node *findNode(const QHashedStringRef &) const;
+ inline Node *findNode(const QHashedCStringRef &) const;
+ inline Node *findNode(const QHashedV8String &) const;
+ inline Node *findSymbolNode(const QHashedV8String &) const;
+ inline Node *createNode(const Node &o);
+ inline Node *createNode(const QHashedString &, const T &);
+ inline Node *createNode(const QHashedCStringRef &, const T &);
+
+ inline Node *takeNode(const QHashedString &key, const T &value);
+ inline Node *takeNode(const QHashedCStringRef &key, const T &value);
+ inline Node *takeNode(const Node &o);
+
+ inline void copy(const QStringHash<T> &);
+
+ inline QStringHashData::IteratorData iterateFirst() const;
+ static inline QStringHashData::IteratorData iterateNext(const QStringHashData::IteratorData &);
+
+public:
+ inline QStringHash();
+ inline QStringHash(const QStringHash &);
+ inline ~QStringHash();
+
+ QStringHash &operator=(const QStringHash<T> &);
+
+ void copyAndReserve(const QStringHash<T> &other, int additionalReserve);
+ void linkAndReserve(const QStringHash<T> &other, int additionalReserve);
+
+ inline bool isEmpty() const;
+ inline void clear();
+ inline int count() const;
+
+ inline int numBuckets() const;
+ inline bool isLinked() const;
+
+ class ConstIterator {
+ public:
+ inline ConstIterator();
+ inline ConstIterator(const QStringHashData::IteratorData &);
+
+ inline ConstIterator &operator++();
+
+ inline bool operator==(const ConstIterator &o) const;
+ inline bool operator!=(const ConstIterator &o) const;
+
+ inline QHashedString key() const;
+ inline const T &value() const;
+ inline const T &operator*() const;
+
+ inline Node *node() const;
+ private:
+ QStringHashData::IteratorData d;
+ };
+
+ inline void insert(const QString &, const T &);
+ inline void insert(const QHashedString &, const T &);
+ inline void insert(const QHashedStringRef &, const T &);
+ inline void insert(const QHashedCStringRef &, const T &);
+ inline void insert(const ConstIterator &);
+
+ inline T *value(const QString &) const;
+ inline T *value(const QHashedString &) const;
+ inline T *value(const QHashedStringRef &) const;
+ inline T *value(const QHashedV8String &) const;
+ inline T *value(const QHashedCStringRef &) const;
+ inline T *value(const ConstIterator &) const;
+
+ inline bool contains(const QString &) const;
+ inline bool contains(const QHashedString &) const;
+ inline bool contains(const QHashedStringRef &) const;
+ inline bool contains(const QHashedCStringRef &) const;
+ inline bool contains(const ConstIterator &) const;
+
+ inline T &operator[](const QString &);
+ inline T &operator[](const QHashedString &);
+ inline T &operator[](const QHashedStringRef &);
+ inline T &operator[](const QHashedCStringRef &);
+
+ inline ConstIterator begin() const;
+ inline ConstIterator end() const;
+
+ inline void reserve(int);
+};
+
+template<class T>
+QStringHash<T>::QStringHash()
+: newedNodes(0), nodePool(0), link(0)
+{
+}
+
+template<class T>
+QStringHash<T>::QStringHash(const QStringHash<T> &other)
+: newedNodes(0), nodePool(0), link(0)
+{
+ data.numBits = other.data.numBits;
+ data.size = other.data.size;
+ reserve(other.count());
+ copy(other);
+}
+
+template<class T>
+QStringHash<T> &QStringHash<T>::operator=(const QStringHash<T> &other)
+{
+ if (&other == this)
+ return *this;
+
+ clear();
+
+ data.numBits = other.data.numBits;
+ data.size = other.data.size;
+ reserve(other.count());
+ copy(other);
+
+ return *this;
+}
+
+template<class T>
+void QStringHash<T>::copyAndReserve(const QStringHash<T> &other, int additionalReserve)
+{
+ clear();
+ data.numBits = other.data.numBits;
+ reserve(other.count() + additionalReserve);
+ copy(other);
+}
+
+template<class T>
+void QStringHash<T>::linkAndReserve(const QStringHash<T> &other, int additionalReserve)
+{
+ clear();
+
+ if (other.count()) {
+ data.size = other.data.size;
+ data.rehashToSize(other.count() + additionalReserve, iterateFirst(), iterateNext);
+
+ if (data.numBuckets == other.data.numBuckets) {
+ nodePool = new ReservedNodePool;
+ nodePool->count = additionalReserve;
+ nodePool->used = 0;
+ nodePool->nodes = new Node[additionalReserve];
+
+#ifdef QSTRINGHASH_LINK_DEBUG
+ data.linkCount++;
+ const_cast<QStringHash<T>&>(other).data.linkCount++;
+#endif
+
+ for (int ii = 0; ii < data.numBuckets; ++ii) {
+ data.buckets[ii] = 0;
+ Node *n = (Node *)other.data.buckets[ii];
+ data.buckets[ii] = n;
+ }
+
+ link = &other;
+ return;
+ }
+
+ data.size = 0;
+ }
+
+ data.numBits = other.data.numBits;
+ reserve(other.count() + additionalReserve);
+ copy(other);
+}
+
+template<class T>
+QStringHash<T>::~QStringHash()
+{
+ clear();
+}
+
+template<class T>
+void QStringHash<T>::clear()
+{
+#ifdef QSTRINGHASH_LINK_DEBUG
+ if (link) {
+ data.linkCount--;
+ const_cast<QStringHash<T> *>(link)->data.linkCount--;
+ }
+
+ if (data.linkCount)
+ qFatal("QStringHash: Illegal attempt to clear a linked hash.");
+#endif
+
+ // Delete the individually allocated nodes
+ NewedNode *n = newedNodes;
+ while (n) {
+ NewedNode *c = n;
+ n = c->nextNewed;
+ delete c;
+ }
+ // Delete the pool allocated nodes
+ if (nodePool) delete nodePool;
+ delete [] data.buckets;
+
+ data.buckets = 0;
+ data.numBuckets = 0;
+ data.numBits = 0;
+ data.size = 0;
+
+ newedNodes = 0;
+ nodePool = 0;
+ link = 0;
+}
+
+template<class T>
+bool QStringHash<T>::isEmpty() const
+{
+ return data.size== 0;
+}
+
+template<class T>
+int QStringHash<T>::count() const
+{
+ return data.size;
+}
+
+template<class T>
+int QStringHash<T>::numBuckets() const
+{
+ return data.numBuckets;
+}
+
+template<class T>
+bool QStringHash<T>::isLinked() const
+{
+ return link != 0;
+}
+
+template<class T>
+typename QStringHash<T>::Node *QStringHash<T>::takeNode(const QHashedString &key, const T &value)
+{
+ if (nodePool && nodePool->used != nodePool->count) {
+ Node *rv = nodePool->nodes + nodePool->used++;
+ rv->length = key.length();
+ rv->hash = key.hash();
+ rv->strData = const_cast<QHashedString &>(key).data_ptr();
+ rv->strData->ref.ref();
+ rv->setQString(true);
+ rv->value = value;
+ return rv;
+ } else {
+ NewedNode *rv = new NewedNode(key, value);
+ rv->nextNewed = newedNodes;
+ newedNodes = rv;
+ return rv;
+ }
+}
+
+template<class T>
+typename QStringHash<T>::Node *QStringHash<T>::takeNode(const QHashedCStringRef &key, const T &value)
+{
+ if (nodePool && nodePool->used != nodePool->count) {
+ Node *rv = nodePool->nodes + nodePool->used++;
+ rv->length = key.length();
+ rv->hash = key.hash();
+ rv->ckey = key.constData();
+ rv->value = value;
+ return rv;
+ } else {
+ NewedNode *rv = new NewedNode(key, value);
+ rv->nextNewed = newedNodes;
+ newedNodes = rv;
+ return rv;
+ }
+}
+
+template<class T>
+typename QStringHash<T>::Node *QStringHash<T>::takeNode(const Node &o)
+{
+ if (nodePool && nodePool->used != nodePool->count) {
+ Node *rv = nodePool->nodes + nodePool->used++;
+ rv->length = o.length;
+ rv->hash = o.hash;
+ if (o.isQString()) {
+ rv->strData = o.strData;
+ rv->strData->ref.ref();
+ rv->setQString(true);
+ } else {
+ rv->ckey = o.ckey;
+ }
+ rv->symbolId = o.symbolId;
+ rv->value = o.value;
+ return rv;
+ } else {
+ NewedNode *rv = new NewedNode(o);
+ rv->nextNewed = newedNodes;
+ newedNodes = rv;
+ return rv;
+ }
+}
+
+template<class T>
+void QStringHash<T>::copy(const QStringHash<T> &other)
+{
+ Q_ASSERT(data.size == 0);
+
+ data.size = other.data.size;
+
+ // Ensure buckets array is created
+ data.rehashToBits(data.numBits, iterateFirst(), iterateNext);
+
+ if (other.link) {
+ for (ConstIterator iter = other.begin(); iter != other.end(); ++iter) {
+ Node *o = iter.node();
+ Node *n = o->isQString()?findNode(QHashedStringRef((QChar *)o->strData->data(), o->length, o->hash)):
+ findNode(QHashedCStringRef(o->ckey, o->length, o->hash));
+ if (!n) {
+ Node *mynode = takeNode(*o);
+ int bucket = mynode->hash % data.numBuckets;
+ mynode->next = data.buckets[bucket];
+ data.buckets[bucket] = mynode;
+ }
+ }
+ } else {
+ for (ConstIterator iter = other.begin(); iter != other.end(); ++iter) {
+ Node *o = iter.node();
+ Node *mynode = takeNode(*o);
+ int bucket = mynode->hash % data.numBuckets;
+ mynode->next = data.buckets[bucket];
+ data.buckets[bucket] = mynode;
+ }
+ }
+}
+
+template<class T>
+QStringHashData::IteratorData
+QStringHash<T>::iterateNext(const QStringHashData::IteratorData &d)
+{
+ QStringHash<T> *This = (QStringHash<T> *)d.p;
+ Node *node = (Node *)d.n;
+
+ if (This->nodePool && node >= This->nodePool->nodes &&
+ node < (This->nodePool->nodes + This->nodePool->used)) {
+ node--;
+ if (node < This->nodePool->nodes)
+ node = 0;
+ } else {
+ NewedNode *nn = (NewedNode *)node;
+ node = nn->nextNewed;
+
+ if (node == 0 && This->nodePool && This->nodePool->used)
+ node = This->nodePool->nodes + This->nodePool->used - 1;
+ }
+
+ if (node == 0 && This->link)
+ return This->link->iterateFirst();
+
+ QStringHashData::IteratorData rv;
+ rv.n = node;
+ rv.p = d.p;
+ return rv;
+}
+
+template<class T>
+QStringHashData::IteratorData QStringHash<T>::iterateFirst() const
+{
+ Node *n = 0;
+ if (newedNodes)
+ n = newedNodes;
+ else if (nodePool && nodePool->used)
+ n = nodePool->nodes + nodePool->used - 1;
+
+ if (n == 0 && link)
+ return link->iterateFirst();
+
+ QStringHashData::IteratorData rv;
+ rv.n = n;
+ rv.p = const_cast<QStringHash<T> *>(this);
+ return rv;
+}
+
+template<class T>
+typename QStringHash<T>::Node *QStringHash<T>::createNode(const Node &o)
+{
+ Node *n = takeNode(o);
+
+ if (data.size >= data.numBuckets)
+ data.rehashToBits(data.numBits + 1, iterateFirst(), iterateNext, n);
+
+ int bucket = n->hash % data.numBuckets;
+ n->next = data.buckets[bucket];
+ data.buckets[bucket] = n;
+
+ data.size++;
+
+ return n;
+}
+
+template<class T>
+typename QStringHash<T>::Node *QStringHash<T>::createNode(const QHashedString &key, const T &value)
+{
+ Node *n = takeNode(key, value);
+
+ if (data.size >= data.numBuckets)
+ data.rehashToBits(data.numBits + 1, iterateFirst(), iterateNext, n);
+
+ int bucket = key.hash() % data.numBuckets;
+ n->next = data.buckets[bucket];
+ data.buckets[bucket] = n;
+
+ data.size++;
+
+ return n;
+}
+
+template<class T>
+typename QStringHash<T>::Node *QStringHash<T>::createNode(const QHashedCStringRef &key, const T &value)
+{
+ Node *n = takeNode(key, value);
+
+ if (data.size >= data.numBuckets)
+ data.rehashToBits(data.numBits + 1, iterateFirst(), iterateNext, n);
+
+ int bucket = key.hash() % data.numBuckets;
+ n->next = data.buckets[bucket];
+ data.buckets[bucket] = n;
+
+ data.size++;
+
+ return n;
+}
+
+template<class T>
+void QStringHash<T>::insert(const QString &key, const T &value)
+{
+ QHashedStringRef ch(key);
+ // If this is a linked hash, we can't rely on owning the node, so we always
+ // create a new one.
+ Node *n = link?0:findNode(key);
+ if (n) n->value = value;
+ else createNode(QHashedString(key, ch.hash()), value);
+}
+
+template<class T>
+void QStringHash<T>::insert(const QHashedString &key, const T &value)
+{
+ // If this is a linked hash, we can't rely on owning the node, so we always
+ // create a new one.
+ Node *n = link?0:findNode(key);
+ if (n) n->value = value;
+ else createNode(key, value);
+}
+
+template<class T>
+void QStringHash<T>::insert(const QHashedStringRef &key, const T &value)
+{
+ // If this is a linked hash, we can't rely on owning the node, so we always
+ // create a new one.
+ Node *n = link?0:findNode(key);
+ if (n) n->value = value;
+ else createNode(key, value);
+}
+
+template<class T>
+void QStringHash<T>::insert(const QHashedCStringRef &key, const T &value)
+{
+ // If this is a linked hash, we can't rely on owning the node, so we always
+ // create a new one.
+ Node *n = link?0:findNode(key);
+ if (n) n->value = value;
+ else createNode(key, value);
+}
+
+template<class T>
+void QStringHash<T>::insert(const ConstIterator &key)
+{
+ // If this is a linked hash, we can't rely on owning the node, so we always
+ // create a new one.
+ if (key.node()->isQString()) {
+ QHashedStringRef str((QChar *)key.node()->strData->data(), key.node()->length,
+ key.node()->hash);
+
+ Node *n = link?0:findNode(str);
+ if (n) n->value = key.node()->value;
+ else createNode(*key.node());
+ } else {
+ QHashedCStringRef str(key.node()->ckey, key.node()->length, key.node()->hash);
+
+ Node *n = link?0:findNode(str);
+ if (n) n->value = key.node()->value;
+ else createNode(str, key.node()->value);
+ }
+}
+
+template<class T>
+typename QStringHash<T>::Node *QStringHash<T>::findNode(const QString &string) const
+{
+ return findNode(QHashedStringRef(string));
+}
+
+template<class T>
+typename QStringHash<T>::Node *QStringHash<T>::findNode(const QHashedString &string) const
+{
+ return findNode(QHashedStringRef(string.constData(), string.length(), string.hash()));
+}
+
+template<class T>
+typename QStringHash<T>::Node *QStringHash<T>::findNode(const QHashedStringRef &string) const
+{
+ QStringHashNode *node = data.numBuckets?data.buckets[string.hash() % data.numBuckets]:0;
+ while (node && !node->equals(string))
+ node = (*node->next);
+
+ return (Node *)node;
+}
+
+template<class T>
+typename QStringHash<T>::Node *QStringHash<T>::findNode(const QHashedCStringRef &string) const
+{
+ QStringHashNode *node = data.numBuckets?data.buckets[string.hash() % data.numBuckets]:0;
+ while (node && !node->equals(string))
+ node = (*node->next);
+
+ return (Node *)node;
+}
+
+template<class T>
+typename QStringHash<T>::Node *QStringHash<T>::findNode(const QHashedV8String &string) const
+{
+ QStringHashNode *node = data.numBuckets?data.buckets[string.hash() % data.numBuckets]:0;
+ while (node && !node->equals(string))
+ node = (*node->next);
+
+ return (Node *)node;
+}
+
+template<class T>
+typename QStringHash<T>::Node *QStringHash<T>::findSymbolNode(const QHashedV8String &string) const
+{
+ Q_ASSERT(string.symbolId() != 0);
+
+ QStringHashNode *node = data.numBuckets?data.buckets[string.hash() % data.numBuckets]:0;
+ while (node && !node->symbolEquals(string))
+ node = (*node->next);
+
+ if (node)
+ node->symbolId = string.symbolId();
+
+ return (Node *)node;
+}
+
+template<class T>
+T *QStringHash<T>::value(const QString &key) const
+{
+ Node *n = findNode(key);
+ return n?&n->value:0;
+}
+
+template<class T>
+T *QStringHash<T>::value(const QHashedString &key) const
+{
+ Node *n = findNode(key);
+ return n?&n->value:0;
+}
+
+template<class T>
+T *QStringHash<T>::value(const QHashedStringRef &key) const
+{
+ Node *n = findNode(key);
+ return n?&n->value:0;
+}
+
+template<class T>
+T *QStringHash<T>::value(const QHashedCStringRef &key) const
+{
+ Node *n = findNode(key);
+ return n?&n->value:0;
+}
+
+template<class T>
+T *QStringHash<T>::value(const ConstIterator &iter) const
+{
+ Node *n = iter.node();
+ if (n->isQString())
+ return value(QHashedStringRef((QChar *)n->strData->data(), n->length, n->hash));
+ else
+ return value(QHashedCStringRef(n->ckey, n->length, n->hash));
+}
+
+template<class T>
+T *QStringHash<T>::value(const QHashedV8String &string) const
+{
+ Node *n = string.symbolId()?findSymbolNode(string):findNode(string);
+ return n?&n->value:0;
+}
+
+template<class T>
+bool QStringHash<T>::contains(const QString &s) const
+{
+ return 0 != value(s);
+}
+
+template<class T>
+bool QStringHash<T>::contains(const QHashedString &s) const
+{
+ return 0 != value(s);
+}
+
+template<class T>
+bool QStringHash<T>::contains(const QHashedStringRef &s) const
+{
+ return 0 != value(s);
+}
+
+template<class T>
+bool QStringHash<T>::contains(const QHashedCStringRef &s) const
+{
+ return 0 != value(s);
+}
+
+template<class T>
+bool QStringHash<T>::contains(const ConstIterator &s) const
+{
+ return 0 != value(s);
+}
+
+template<class T>
+T &QStringHash<T>::operator[](const QString &key)
+{
+ QHashedStringRef cs(key);
+ Node *n = findNode(cs);
+ if (n) return n->value;
+ else return createNode(QHashedString(key, cs.hash()), T())->value;
+}
+
+template<class T>
+T &QStringHash<T>::operator[](const QHashedString &key)
+{
+ Node *n = findNode(key);
+ if (n) return n->value;
+ else return createNode(key, T())->value;
+}
+
+template<class T>
+T &QStringHash<T>::operator[](const QHashedStringRef &key)
+{
+ Node *n = findNode(key);
+ if (n) return n->value;
+ else return createNode(key, T())->value;
+}
+
+template<class T>
+T &QStringHash<T>::operator[](const QHashedCStringRef &key)
+{
+ Node *n = findNode(key);
+ if (n) return n->value;
+ else return createNode(key, T())->value;
+}
+
+template<class T>
+void QStringHash<T>::reserve(int n)
+{
+ if (nodePool || 0 == n)
+ return;
+
+ nodePool = new ReservedNodePool;
+ nodePool->count = n;
+ nodePool->used = 0;
+ nodePool->nodes = new Node[n];
+
+ data.rehashToSize(n, iterateFirst(), iterateNext);
+}
+
+template<class T>
+QStringHash<T>::ConstIterator::ConstIterator()
+{
+}
+
+template<class T>
+QStringHash<T>::ConstIterator::ConstIterator(const QStringHashData::IteratorData &d)
+: d(d)
+{
+}
+
+template<class T>
+typename QStringHash<T>::ConstIterator &QStringHash<T>::ConstIterator::operator++()
+{
+ d = QStringHash<T>::iterateNext(d);
+ return *this;
+}
+
+template<class T>
+bool QStringHash<T>::ConstIterator::operator==(const ConstIterator &o) const
+{
+ return d.n == o.d.n;
+}
+
+template<class T>
+bool QStringHash<T>::ConstIterator::operator!=(const ConstIterator &o) const
+{
+ return d.n != o.d.n;
+}
+
+template<class T>
+QHashedString QStringHash<T>::ConstIterator::key() const
+{
+ Node *n = (Node *)d.n;
+ if (n->isQString()) {
+ return QHashedString(QString((QChar *)n->strData->data(), n->length), n->hash);
+ } else {
+ return QHashedString(QString::fromLatin1(n->ckey, n->length), n->hash);
+ }
+}
+template<class T>
+const T &QStringHash<T>::ConstIterator::value() const
+{
+ Node *n = (Node *)d.n;
+ return n->value;
+}
+
+template<class T>
+const T &QStringHash<T>::ConstIterator::operator*() const
+{
+ Node *n = (Node *)d.n;
+ return n->value;
+}
+
+template<class T>
+typename QStringHash<T>::Node *QStringHash<T>::ConstIterator::node() const
+{
+ Node *n = (Node *)d.n;
+ return n;
+}
+
+template<class T>
+typename QStringHash<T>::ConstIterator QStringHash<T>::begin() const
+{
+ return ConstIterator(iterateFirst());
+}
+
+template<class T>
+typename QStringHash<T>::ConstIterator QStringHash<T>::end() const
+{
+ return ConstIterator();
+}
+
+inline uint qHash(const QHashedString &string)
+{
+ return uint(string.hash());
+}
+
+inline uint qHash(const QHashedStringRef &string)
+{
+ return uint(string.hash());
+}
+
+QHashedString::QHashedString()
+: QString(), m_hash(0)
+{
+}
+
+QHashedString::QHashedString(const QString &string)
+: QString(string), m_hash(0)
+{
+}
+
+QHashedString::QHashedString(const QString &string, quint32 hash)
+: QString(string), m_hash(hash)
+{
+}
+
+QHashedString::QHashedString(const QHashedString &string)
+: QString(string), m_hash(string.m_hash)
+{
+}
+
+QHashedString &QHashedString::operator=(const QHashedString &string)
+{
+ static_cast<QString &>(*this) = string;
+ m_hash = string.m_hash;
+ return *this;
+}
+
+bool QHashedString::operator==(const QHashedString &string) const
+{
+ return (string.m_hash == m_hash || !string.m_hash || !m_hash) &&
+ static_cast<const QString &>(*this) == static_cast<const QString &>(string);
+}
+
+bool QHashedString::operator==(const QHashedStringRef &string) const
+{
+ return length() == string.m_length &&
+ (string.m_hash == m_hash || !string.m_hash || !m_hash) &&
+ QHashedString::compare(constData(), string.m_data, string.m_length);
+}
+
+quint32 QHashedString::hash() const
+{
+ if (!m_hash) computeHash();
+ return m_hash;
+}
+
+quint32 QHashedString::existingHash() const
+{
+ return m_hash;
+}
+
+bool QHashedString::isUpper(const QChar &qc)
+{
+ ushort c = qc.unicode();
+ // Optimize for _, a-z and A-Z.
+ return ((c != '_' ) && (!(c >= 'a' && c <= 'z')) &&
+ ((c >= 'A' && c <= 'Z') || QChar::category(c) == QChar::Letter_Uppercase));
+}
+
+QHashedV8String::QHashedV8String()
+{
+}
+
+QHashedV8String::QHashedV8String(v8::Handle<v8::String> string)
+: m_hash(string->CompleteHash()), m_string(string)
+{
+ Q_ASSERT(!m_string.IsEmpty());
+}
+
+QHashedV8String::QHashedV8String(const QHashedV8String &string)
+: m_hash(string.m_hash), m_string(string.m_string)
+{
+}
+
+QHashedV8String &QHashedV8String::operator=(const QHashedV8String &other)
+{
+ m_hash = other.m_hash;
+ m_string = other.m_string;
+ return *this;
+}
+
+bool QHashedV8String::operator==(const QHashedV8String &string)
+{
+ return m_hash.hash == string.m_hash.hash && m_hash.length == string.m_hash.length &&
+ m_string.IsEmpty() == m_string.IsEmpty() &&
+ (m_string.IsEmpty() || m_string->StrictEquals(string.m_string));
+}
+
+quint32 QHashedV8String::hash() const
+{
+ return m_hash.hash;
+}
+
+int QHashedV8String::length() const
+{
+ return m_hash.length;
+}
+
+quint32 QHashedV8String::symbolId() const
+{
+ return m_hash.symbol_id;
+}
+
+v8::Handle<v8::String> QHashedV8String::string() const
+{
+ return m_string;
+}
+
+QString QHashedV8String::toString() const
+{
+ QString result;
+ result.reserve(m_hash.length);
+
+ for (int i = 0; i < m_hash.length; ++i)
+ result.append(m_string->GetCharacter(i));
+
+ return result;
+}
+
+QHashedStringRef::QHashedStringRef()
+: m_data(0), m_length(0), m_utf8length(-1), m_hash(0)
+{
+}
+
+QHashedStringRef::QHashedStringRef(const QString &str)
+: m_data(str.constData()), m_length(str.length()), m_utf8length(0), m_hash(0)
+{
+}
+
+QHashedStringRef::QHashedStringRef(const QStringRef &str)
+: m_data(str.constData()), m_length(str.length()), m_utf8length(0), m_hash(0)
+{
+}
+
+QHashedStringRef::QHashedStringRef(const QChar *data, int length)
+: m_data(data), m_length(length), m_utf8length(0), m_hash(0)
+{
+}
+
+QHashedStringRef::QHashedStringRef(const QChar *data, int length, quint32 hash)
+: m_data(data), m_length(length), m_utf8length(0), m_hash(hash)
+{
+}
+
+QHashedStringRef::QHashedStringRef(const QHashedString &string)
+: m_data(string.constData()), m_length(string.length()), m_utf8length(0), m_hash(string.m_hash)
+{
+}
+
+QHashedStringRef::QHashedStringRef(const QHashedStringRef &string)
+: m_data(string.m_data), m_length(string.m_length), m_utf8length(string.m_utf8length),
+ m_hash(string.m_hash)
+{
+}
+
+QHashedStringRef &QHashedStringRef::operator=(const QHashedStringRef &o)
+{
+ m_data = o.m_data;
+ m_length = o.m_length;
+ m_utf8length = o.m_utf8length;
+ m_hash = o.m_hash;
+ return *this;
+}
+
+bool QHashedStringRef::operator==(const QString &string) const
+{
+ return m_length == string.length() &&
+ QHashedString::compare(string.constData(), m_data, m_length);
+}
+
+bool QHashedStringRef::operator==(const QHashedString &string) const
+{
+ return m_length == string.length() &&
+ (m_hash == string.m_hash || !m_hash || !string.m_hash) &&
+ QHashedString::compare(string.constData(), m_data, m_length);
+}
+
+bool QHashedStringRef::operator==(const QHashedStringRef &string) const
+{
+ return m_length == string.m_length &&
+ (m_hash == string.m_hash || !m_hash || !string.m_hash) &&
+ QHashedString::compare(string.m_data, m_data, m_length);
+}
+
+bool QHashedStringRef::operator==(const QHashedCStringRef &string) const
+{
+ return m_length == string.m_length &&
+ (m_hash == string.m_hash || !m_hash || !string.m_hash) &&
+ QHashedString::compare(m_data, string.m_data, m_length);
+}
+
+bool QHashedStringRef::operator!=(const QString &string) const
+{
+ return m_length != string.length() ||
+ !QHashedString::compare(string.constData(), m_data, m_length);
+}
+
+bool QHashedStringRef::operator!=(const QHashedString &string) const
+{
+ return m_length != string.length() ||
+ (m_hash != string.m_hash && m_hash && string.m_hash) ||
+ !QHashedString::compare(string.constData(), m_data, m_length);
+}
+
+bool QHashedStringRef::operator!=(const QHashedStringRef &string) const
+{
+ return m_length != string.m_length ||
+ (m_hash != string.m_hash && m_hash && string.m_hash) ||
+ QHashedString::compare(string.m_data, m_data, m_length);
+}
+
+bool QHashedStringRef::operator!=(const QHashedCStringRef &string) const
+{
+ return m_length != string.m_length ||
+ (m_hash != string.m_hash && m_hash && string.m_hash) ||
+ QHashedString::compare(m_data, string.m_data, m_length);
+}
+
+const QChar &QHashedStringRef::at(int index) const
+{
+ Q_ASSERT(index < m_length);
+ return m_data[index];
+}
+
+const QChar *QHashedStringRef::constData() const
+{
+ return m_data;
+}
+
+bool QHashedStringRef::isEmpty() const
+{
+ return m_length == 0;
+}
+
+int QHashedStringRef::length() const
+{
+ return m_length;
+}
+
+int QHashedStringRef::utf8length() const
+{
+ if (m_utf8length < m_length)
+ computeUtf8Length();
+ return m_utf8length;
+}
+
+bool QHashedStringRef::startsWithUpper() const
+{
+ if (m_length < 1) return false;
+ return QHashedString::isUpper(m_data[0]);
+}
+
+quint32 QHashedStringRef::hash() const
+{
+ if (!m_hash) computeHash();
+ return m_hash;
+}
+
+QHashedCStringRef::QHashedCStringRef()
+: m_data(0), m_length(0), m_hash(0)
+{
+}
+
+QHashedCStringRef::QHashedCStringRef(const char *data, int length)
+: m_data(data), m_length(length), m_hash(0)
+{
+}
+
+QHashedCStringRef::QHashedCStringRef(const char *data, int length, quint32 hash)
+: m_data(data), m_length(length), m_hash(hash)
+{
+}
+
+QHashedCStringRef::QHashedCStringRef(const QHashedCStringRef &o)
+: m_data(o.m_data), m_length(o.m_length), m_hash(o.m_hash)
+{
+}
+
+quint32 QHashedCStringRef::hash() const
+{
+ if (!m_hash) computeHash();
+ return m_hash;
+}
+
+const char *QHashedCStringRef::constData() const
+{
+ return m_data;
+}
+
+int QHashedCStringRef::length() const
+{
+ return m_length;
+}
+
+int QHashedCStringRef::utf16length() const
+{
+ return m_length;
+}
+
+void QHashedCStringRef::writeUtf16(QChar *output) const
+{
+ writeUtf16((uint16_t *)output);
+}
+
+void QHashedCStringRef::writeUtf16(uint16_t *output) const
+{
+ int l = m_length;
+ const char *d = m_data;
+ while (l--)
+ *output++ = *d++;
+}
+
+bool QHashedString::compare(const QChar *lhs, const char *rhs, int length)
+{
+ Q_ASSERT(lhs && rhs);
+ const quint16 *l = (const quint16*)lhs;
+ while (length--)
+ if (*l++ != *rhs++) return false;
+ return true;
+}
+
+bool QHashedString::compare(const char *lhs, const char *rhs, int length)
+{
+ Q_ASSERT(lhs && rhs);
+ return 0 == ::memcmp(lhs, rhs, length);
+}
+
+QT_END_NAMESPACE
+
+#endif // QHASHEDSTRING_P_H
diff --git a/src/qml/qml/ftw/qhashfield_p.h b/src/qml/qml/ftw/qhashfield_p.h
new file mode 100644
index 0000000000..46df9a176c
--- /dev/null
+++ b/src/qml/qml/ftw/qhashfield_p.h
@@ -0,0 +1,120 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QHASHFIELD_P_H
+#define QHASHFIELD_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+
+#include <QtCore/qglobal.h>
+
+QT_BEGIN_NAMESPACE
+
+// QHashField can be used for doing coarse grained set testing, in
+// cases where you do not expect the set to contain the item. For
+// example where you would write:
+// QSet<QString> strings;
+// for (int ii = 0; ii < mystrings.count(); ++ii) {
+// if (strings.contains(mystrings.at(ii)))
+// qFatal("Duplication!");
+// strings.insert(mystrings);
+// }
+// You may write:
+// QHashField strings;
+// for (int ii = 0; ii < mystrings.count(); ++ii) {
+// if (strings.testAndSet(qHash(mystrings.at(ii)))) {
+// // The string *might* be duplicated
+// for (int jj = 0; jj < ii; ++jj) {
+// if (mystrings.at(ii) == mystrings.at(jj))
+// qFatal("Duplication!");
+// }
+// }
+// }
+// For small lists of things, where the hash is cheap to calculate
+// and you don't expect duplication this will be much faster.
+class QHashField {
+public:
+ inline QHashField();
+
+ inline void clear();
+
+ inline bool test(quint32 hash);
+ inline bool testAndSet(quint32 hash);
+private:
+ quint32 m_field;
+};
+
+QHashField::QHashField()
+: m_field(0)
+{
+}
+
+void QHashField::clear()
+{
+ m_field = 0;
+}
+
+bool QHashField::test(quint32 hash)
+{
+ return m_field & (1 << (hash % 31));
+}
+
+bool QHashField::testAndSet(quint32 hash)
+{
+ quint32 mask = 1 << (hash % 31);
+ bool rv = m_field & mask;
+ m_field |= mask;
+ return rv;
+}
+
+QT_END_NAMESPACE
+
+#endif // QHASHFIELD_P_H
diff --git a/src/qml/qml/ftw/qintrusivelist.cpp b/src/qml/qml/ftw/qintrusivelist.cpp
new file mode 100644
index 0000000000..5a1624f1f4
--- /dev/null
+++ b/src/qml/qml/ftw/qintrusivelist.cpp
@@ -0,0 +1,179 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qintrusivelist_p.h"
+
+/*!
+\class QIntrusiveList
+\brief The QIntrusiveList class is a template class that provides a list of objects using static storage.
+\internal
+
+QIntrusiveList creates a linked list of objects. Adding and removing objects from the
+QIntrusiveList is a constant time operation and is very quick. The list performs no memory
+allocations, but does require the objects being added to the list to contain a QIntrusiveListNode
+instance for the list's use. Even so, for small lists QIntrusiveList uses less memory than Qt's
+other list classes.
+
+As QIntrusiveList uses storage inside the objects in the list, each object can only be in one
+list at a time. Objects are inserted by the insert() method. If the object is already
+in a list (including the one it is being inserted into) it is first removed, and then inserted
+at the head of the list. QIntrusiveList is a last-in-first-out list. That is, following an
+insert() the inserted object becomes the list's first() object.
+
+\code
+struct MyObject {
+ MyObject(int value) : value(value) {}
+
+ int value;
+ QIntrusiveListNode node;
+};
+typedef QIntrusiveList<MyObject, &MyObject::node> MyObjectList;
+
+void foo() {
+ MyObjectList list;
+
+ MyObject m0(0);
+ MyObject m1(1);
+ MyObject m2(2);
+
+ list.insert(&m0);
+ list.insert(&m1);
+ list.insert(&m2);
+
+ // QIntrusiveList is LIFO, so will print: 2... 1... 0...
+ for (MyObjectList::iterator iter = list.begin(); iter != list.end(); ++iter) {
+ qWarning() << iter->value;
+ }
+}
+\endcode
+*/
+
+
+/*!
+\fn QIntrusiveList::QIntrusiveList();
+
+Construct an empty list.
+*/
+
+/*!
+\fn QIntrusiveList::~QIntrusiveList();
+
+Destroy the list. All entries are removed.
+*/
+
+/*!
+\fn void QIntrusiveList::insert(N *object);
+
+Insert \a object into the list. If \a object is a member of this, or another list, it will be
+removed and inserted at the head of this list.
+*/
+
+/*!
+\fn void QIntrusiveList::remove(N *object);
+
+Remove \a object from the list. \a object must not be null.
+*/
+
+/*!
+\fn bool QIntrusiveList::contains(N *object) const
+
+Returns true if the list contains \a object; otherwise returns false.
+*/
+
+/*!
+\fn N *QIntrusiveList::first() const
+
+Returns the first entry in this list, or null if the list is empty.
+*/
+
+/*!
+\fn N *QIntrusiveList::next(N *current)
+
+Returns the next object after \a current, or null if \a current is the last object. \a current cannot be null.
+*/
+
+/*!
+\fn iterator QIntrusiveList::begin()
+
+Returns an STL-style interator pointing to the first item in the list.
+
+\sa end()
+*/
+
+/*!
+\fn iterator QIntrusiveList::end()
+
+Returns an STL-style iterator pointing to the imaginary item after the last item in the list.
+
+\sa begin()
+*/
+
+/*!
+iterator &QInplacelist::iterator::erase()
+
+Remove the current object from the list, and return an iterator to the next element.
+*/
+
+
+/*!
+\fn QIntrusiveListNode::QIntrusiveListNode()
+
+Create a QIntrusiveListNode.
+*/
+
+/*!
+\fn QIntrusiveListNode::~QIntrusiveListNode()
+
+Destroy the QIntrusiveListNode. If the node is in a list, it is removed.
+*/
+
+/*!
+\fn void QIntrusiveListNode::remove()
+
+If in a list, remove this node otherwise do nothing.
+*/
+
+/*!
+\fn bool QIntrusiveListNode::isInList() const
+
+Returns true if this node is in a list, false otherwise.
+*/
+
diff --git a/src/qml/qml/ftw/qintrusivelist_p.h b/src/qml/qml/ftw/qintrusivelist_p.h
new file mode 100644
index 0000000000..489b02d656
--- /dev/null
+++ b/src/qml/qml/ftw/qintrusivelist_p.h
@@ -0,0 +1,274 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QINTRUSIVELIST_P_H
+#define QINTRUSIVELIST_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qglobal.h>
+
+QT_BEGIN_NAMESPACE
+
+class QIntrusiveListNode;
+template<class N, QIntrusiveListNode N::*member>
+class QIntrusiveList
+{
+public:
+ inline QIntrusiveList();
+ inline ~QIntrusiveList();
+
+ inline bool isEmpty() const;
+ inline void insert(N *n);
+ inline void remove(N *n);
+ inline bool contains(N *) const;
+
+ class iterator {
+ public:
+ inline iterator();
+ inline iterator(N *value);
+
+ inline N *operator*() const;
+ inline N *operator->() const;
+ inline bool operator==(const iterator &other) const;
+ inline bool operator!=(const iterator &other) const;
+ inline iterator &operator++();
+
+ inline iterator &erase();
+
+ private:
+ N *_value;
+ };
+ typedef iterator Iterator;
+
+ inline N *first() const;
+ static inline N *next(N *current);
+
+ inline iterator begin();
+ inline iterator end();
+
+private:
+ static inline N *nodeToN(QIntrusiveListNode *node);
+
+ QIntrusiveListNode *__first;
+};
+
+class QIntrusiveListNode
+{
+public:
+ inline QIntrusiveListNode();
+ inline ~QIntrusiveListNode();
+
+ inline void remove();
+ inline bool isInList() const;
+
+ QIntrusiveListNode *_next;
+ QIntrusiveListNode**_prev;
+};
+
+template<class N, QIntrusiveListNode N::*member>
+QIntrusiveList<N, member>::iterator::iterator()
+: _value(0)
+{
+}
+
+template<class N, QIntrusiveListNode N::*member>
+QIntrusiveList<N, member>::iterator::iterator(N *value)
+: _value(value)
+{
+}
+
+template<class N, QIntrusiveListNode N::*member>
+N *QIntrusiveList<N, member>::iterator::operator*() const
+{
+ return _value;
+}
+
+template<class N, QIntrusiveListNode N::*member>
+N *QIntrusiveList<N, member>::iterator::operator->() const
+{
+ return _value;
+}
+
+template<class N, QIntrusiveListNode N::*member>
+bool QIntrusiveList<N, member>::iterator::operator==(const iterator &other) const
+{
+ return other._value == _value;
+}
+
+template<class N, QIntrusiveListNode N::*member>
+bool QIntrusiveList<N, member>::iterator::operator!=(const iterator &other) const
+{
+ return other._value != _value;
+}
+
+template<class N, QIntrusiveListNode N::*member>
+typename QIntrusiveList<N, member>::iterator &QIntrusiveList<N, member>::iterator::operator++()
+{
+ _value = QIntrusiveList<N, member>::next(_value);
+ return *this;
+}
+
+template<class N, QIntrusiveListNode N::*member>
+typename QIntrusiveList<N, member>::iterator &QIntrusiveList<N, member>::iterator::erase()
+{
+ N *old = _value;
+ _value = QIntrusiveList<N, member>::next(_value);
+ (old->*member).remove();
+ return *this;
+}
+
+template<class N, QIntrusiveListNode N::*member>
+QIntrusiveList<N, member>::QIntrusiveList()
+: __first(0)
+{
+}
+
+template<class N, QIntrusiveListNode N::*member>
+QIntrusiveList<N, member>::~QIntrusiveList()
+{
+ while (__first) __first->remove();
+}
+
+template<class N, QIntrusiveListNode N::*member>
+bool QIntrusiveList<N, member>::isEmpty() const
+{
+ return __first == 0;
+}
+
+template<class N, QIntrusiveListNode N::*member>
+void QIntrusiveList<N, member>::insert(N *n)
+{
+ QIntrusiveListNode *nnode = &(n->*member);
+ nnode->remove();
+
+ nnode->_next = __first;
+ if (nnode->_next) nnode->_next->_prev = &nnode->_next;
+ __first = nnode;
+ nnode->_prev = &__first;
+}
+
+template<class N, QIntrusiveListNode N::*member>
+void QIntrusiveList<N, member>::remove(N *n)
+{
+ QIntrusiveListNode *nnode = &(n->*member);
+ nnode->remove();
+}
+
+template<class N, QIntrusiveListNode N::*member>
+bool QIntrusiveList<N, member>::contains(N *n) const
+{
+ QIntrusiveListNode *nnode = __first;
+ while (nnode) {
+ if (nodeToN(nnode) == n)
+ return true;
+ nnode = nnode->_next;
+ }
+ return false;
+}
+
+template<class N, QIntrusiveListNode N::*member>
+N *QIntrusiveList<N, member>::first() const
+{
+ return __first?nodeToN(__first):0;
+}
+
+template<class N, QIntrusiveListNode N::*member>
+N *QIntrusiveList<N, member>::next(N *current)
+{
+ QIntrusiveListNode *nextnode = (current->*member)._next;
+ N *nextstruct = nextnode?nodeToN(nextnode):0;
+ return nextstruct;
+}
+
+template<class N, QIntrusiveListNode N::*member>
+typename QIntrusiveList<N, member>::iterator QIntrusiveList<N, member>::begin()
+{
+ return __first?iterator(nodeToN(__first)):iterator();
+}
+
+template<class N, QIntrusiveListNode N::*member>
+typename QIntrusiveList<N, member>::iterator QIntrusiveList<N, member>::end()
+{
+ return iterator();
+}
+
+template<class N, QIntrusiveListNode N::*member>
+N *QIntrusiveList<N, member>::nodeToN(QIntrusiveListNode *node)
+{
+ return (N *)((char *)node - ((char *)&(((N *)0)->*member) - (char *)0));
+}
+
+QIntrusiveListNode::QIntrusiveListNode()
+: _next(0), _prev(0)
+{
+}
+
+QIntrusiveListNode::~QIntrusiveListNode()
+{
+ remove();
+}
+
+void QIntrusiveListNode::remove()
+{
+ if (_prev) *_prev = _next;
+ if (_next) _next->_prev = _prev;
+ _prev = 0;
+ _next = 0;
+}
+
+bool QIntrusiveListNode::isInList() const
+{
+ return _prev != 0;
+}
+
+QT_END_NAMESPACE
+
+#endif // QINTRUSIVELIST_P_H
diff --git a/src/qml/qml/ftw/qlazilyallocated_p.h b/src/qml/qml/ftw/qlazilyallocated_p.h
new file mode 100644
index 0000000000..960d84d5e7
--- /dev/null
+++ b/src/qml/qml/ftw/qlazilyallocated_p.h
@@ -0,0 +1,146 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QLAZILYALLOCATED_P_H
+#define QLAZILYALLOCATED_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qglobal.h>
+
+#include <private/qflagpointer_p.h>
+
+QT_BEGIN_NAMESPACE
+
+template<typename T>
+class QLazilyAllocated {
+public:
+ inline QLazilyAllocated();
+ inline ~QLazilyAllocated();
+
+ inline bool isAllocated() const;
+
+ inline T *operator->() const;
+
+ inline T &value();
+ inline const T &value() const;
+
+ inline bool flag() const;
+ inline void setFlag();
+ inline void clearFlag();
+ inline void setFlagValue(bool);
+private:
+ mutable QFlagPointer<T> d;
+};
+
+template<typename T>
+QLazilyAllocated<T>::QLazilyAllocated()
+{
+}
+
+template<typename T>
+QLazilyAllocated<T>::~QLazilyAllocated()
+{
+ delete *d;
+}
+
+template<typename T>
+bool QLazilyAllocated<T>::isAllocated() const
+{
+ return !d.isNull();
+}
+
+template<typename T>
+T &QLazilyAllocated<T>::value()
+{
+ if (d.isNull()) d = new T;
+ return *(*d);
+}
+
+template<typename T>
+const T &QLazilyAllocated<T>::value() const
+{
+ if (d.isNull()) d = new T;
+ return *(*d);
+}
+
+template<typename T>
+T *QLazilyAllocated<T>::operator->() const
+{
+ return *d;
+}
+
+template<typename T>
+bool QLazilyAllocated<T>::flag() const
+{
+ return d.flag();
+}
+
+template<typename T>
+void QLazilyAllocated<T>::setFlag()
+{
+ d.setFlag();
+}
+
+template<typename T>
+void QLazilyAllocated<T>::clearFlag()
+{
+ d.clearFlag();
+}
+
+template<typename T>
+void QLazilyAllocated<T>::setFlagValue(bool v)
+{
+ d.setFlagValue(v);
+}
+
+QT_END_NAMESPACE
+
+#endif // QLAZILYALLOCATED_P_H
diff --git a/src/qml/qml/ftw/qpodvector_p.h b/src/qml/qml/ftw/qpodvector_p.h
new file mode 100644
index 0000000000..c96692667a
--- /dev/null
+++ b/src/qml/qml/ftw/qpodvector_p.h
@@ -0,0 +1,173 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QPODVECTOR_P_H
+#define QPODVECTOR_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qglobal.h>
+#include <QDebug>
+
+QT_BEGIN_NAMESPACE
+
+template<class T, int Increment=1024>
+class QPODVector
+{
+public:
+ QPODVector()
+ : m_count(0), m_capacity(0), m_data(0) {}
+ ~QPODVector() { if (m_data) ::free(m_data); }
+
+ const T &at(int idx) const {
+ return m_data[idx];
+ }
+
+ T &operator[](int idx) {
+ return m_data[idx];
+ }
+
+ void clear() {
+ m_count = 0;
+ }
+
+ void prepend(const T &v) {
+ insert(0, v);
+ }
+
+ void append(const T &v) {
+ insert(m_count, v);
+ }
+
+ void insert(int idx, const T &v) {
+ if (m_count == m_capacity) {
+ m_capacity += Increment;
+ m_data = (T *)realloc(m_data, m_capacity * sizeof(T));
+ }
+ int moveCount = m_count - idx;
+ if (moveCount)
+ ::memmove(m_data + idx + 1, m_data + idx, moveCount * sizeof(T));
+ m_count++;
+ m_data[idx] = v;
+ }
+
+ void reserve(int count) {
+ if (count >= m_capacity) {
+ m_capacity = (count + (Increment-1)) & (0xFFFFFFFF - Increment + 1);
+ m_data = (T *)realloc(m_data, m_capacity * sizeof(T));
+ }
+ }
+
+ void insertBlank(int idx, int count) {
+ int newSize = m_count + count;
+ reserve(newSize);
+ int moveCount = m_count - idx;
+ if (moveCount)
+ ::memmove(m_data + idx + count, m_data + idx,
+ moveCount * sizeof(T));
+ m_count = newSize;
+ }
+
+ void remove(int idx, int count = 1) {
+ int moveCount = m_count - (idx + count);
+ if (moveCount)
+ ::memmove(m_data + idx, m_data + idx + count,
+ moveCount * sizeof(T));
+ m_count -= count;
+ }
+
+ void removeOne(const T &v) {
+ int idx = 0;
+ while (idx < m_count) {
+ if (m_data[idx] == v) {
+ remove(idx);
+ return;
+ }
+ ++idx;
+ }
+ }
+
+ int find(const T &v) {
+ for (int idx = 0; idx < m_count; ++idx)
+ if (m_data[idx] == v)
+ return idx;
+ return -1;
+ }
+
+ bool contains(const T &v) {
+ return find(v) != -1;
+ }
+
+ int count() const {
+ return m_count;
+ }
+
+ void copyAndClear(QPODVector<T,Increment> &other) {
+ if (other.m_data) ::free(other.m_data);
+ other.m_count = m_count;
+ other.m_capacity = m_capacity;
+ other.m_data = m_data;
+ m_count = 0;
+ m_capacity = 0;
+ m_data = 0;
+ }
+
+ QPODVector<T,Increment> &operator<<(const T &v) { append(v); return *this; }
+private:
+ QPODVector(const QPODVector &);
+ QPODVector &operator=(const QPODVector &);
+ int m_count;
+ int m_capacity;
+ T *m_data;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/qml/qml/ftw/qpointervaluepair_p.h b/src/qml/qml/ftw/qpointervaluepair_p.h
new file mode 100644
index 0000000000..7b0caf49bc
--- /dev/null
+++ b/src/qml/qml/ftw/qpointervaluepair_p.h
@@ -0,0 +1,196 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QPOINTERVALUEPAIR_P_H
+#define QPOINTERVALUEPAIR_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qglobal.h>
+#include <private/qflagpointer_p.h>
+
+QT_BEGIN_NAMESPACE
+
+// QPointerValuePair is intended to help reduce the memory consumption of a class.
+// In the common case, QPointerValuePair behaves like a pointer. In this mode, it
+// consumes the same memory as a regular pointer.
+// Additionally, QPointerValuePair can store an arbitrary value type in *addition*
+// to the pointer. In this case, it uses slightly more memory than the pointer and
+// value type combined.
+// Consequently, this class is most useful in cases where a pointer is always stored
+// and a value type is rarely stored.
+template<typename P, typename V>
+class QPointerValuePair {
+public:
+ inline QPointerValuePair();
+ inline QPointerValuePair(P *);
+ inline ~QPointerValuePair();
+
+ inline bool isNull() const;
+
+ inline bool flag() const;
+ inline void setFlag();
+ inline void clearFlag();
+ inline void setFlagValue(bool);
+
+ inline QPointerValuePair<P, V> &operator=(P *);
+
+ inline P *operator->() const;
+ inline P *operator*() const;
+
+ inline bool hasValue() const;
+ inline V &value();
+ inline const V *constValue() const;
+
+private:
+ struct Value { P *pointer; V value; };
+ QBiPointer<P, Value> d;
+};
+
+template<typename P, typename V>
+QPointerValuePair<P, V>::QPointerValuePair()
+{
+}
+
+template<typename P, typename V>
+QPointerValuePair<P, V>::QPointerValuePair(P *p)
+: d(p)
+{
+}
+
+template<typename P, typename V>
+QPointerValuePair<P, V>::~QPointerValuePair()
+{
+ if (d.isT2()) delete d.asT2();
+}
+
+template<typename P, typename V>
+bool QPointerValuePair<P, V>::isNull() const
+{
+ if (d.isT1()) return 0 == d.asT1();
+ else return d.asT2()->pointer == 0;
+}
+
+template<typename P, typename V>
+bool QPointerValuePair<P, V>::flag() const
+{
+ return d.flag();
+}
+
+template<typename P, typename V>
+void QPointerValuePair<P, V>::setFlag()
+{
+ d.setFlag();
+}
+
+template<typename P, typename V>
+void QPointerValuePair<P, V>::clearFlag()
+{
+ d.clearFlag();
+}
+
+template<typename P, typename V>
+void QPointerValuePair<P, V>::setFlagValue(bool v)
+{
+ d.setFlagValue(v);
+}
+
+template<typename P, typename V>
+QPointerValuePair<P, V> &QPointerValuePair<P, V>::operator=(P *o)
+{
+ if (d.isT1()) d = o;
+ else d.asT2()->pointer = o;
+ return *this;
+}
+
+template<typename P, typename V>
+P *QPointerValuePair<P, V>::operator->() const
+{
+ if (d.isT1()) return d.asT1();
+ else return d.asT2()->pointer;
+}
+
+template<typename P, typename V>
+P *QPointerValuePair<P, V>::operator*() const
+{
+ if (d.isT1()) return d.asT1();
+ else return d.asT2()->pointer;
+}
+
+template<typename P, typename V>
+bool QPointerValuePair<P, V>::hasValue() const
+{
+ return d.isT2();
+}
+
+template<typename P, typename V>
+V &QPointerValuePair<P, V>::value()
+{
+ if (d.isT1()) {
+ P *p = d.asT1();
+ Value *value = new Value;
+ value->pointer = p;
+ d = value;
+ }
+
+ return d.asT2()->value;
+}
+
+// Will return null if hasValue() == false
+template<typename P, typename V>
+const V *QPointerValuePair<P, V>::constValue() const
+{
+ if (d.isT2()) return &d.asT2()->value;
+ else return 0;
+}
+
+QT_END_NAMESPACE
+
+#endif // QPOINTERVALUEPAIR_P_H
diff --git a/src/qml/qml/ftw/qqmlpool.cpp b/src/qml/qml/ftw/qqmlpool.cpp
new file mode 100644
index 0000000000..6fd11d4b1e
--- /dev/null
+++ b/src/qml/qml/ftw/qqmlpool.cpp
@@ -0,0 +1,92 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qqmlpool_p.h"
+
+// #define POOL_DEBUG
+
+QT_BEGIN_NAMESPACE
+
+void QQmlPool::newpage()
+{
+#ifdef POOL_DEBUG
+ qWarning("QQmlPool: Allocating page");
+#endif
+
+ Page *page = (Page *)malloc(sizeof(Page));
+ page->header.next = _page;
+ page->header.free = page->memory;
+ _page = page;
+}
+
+void QQmlPool::clear()
+{
+#ifdef POOL_DEBUG
+ int count = 0;
+#endif
+
+ Class *c = _classList;
+ while (c) {
+ Class *n = c->_next;
+ c->_destroy(c);
+#ifdef POOL_DEBUG
+ ++count;
+#endif
+ c = n;
+ }
+
+#ifdef POOL_DEBUG
+ qWarning("QQmlPool: Destroyed %d objects", count);
+#endif
+
+ Page *p = _page;
+ while (p) {
+ Page *n = p->header.next;
+ free(p);
+ p = n;
+ }
+
+ _classList = 0;
+ _page = 0;
+}
+
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/ftw/qqmlpool_p.h b/src/qml/qml/ftw/qqmlpool_p.h
new file mode 100644
index 0000000000..e4fa03ce34
--- /dev/null
+++ b/src/qml/qml/ftw/qqmlpool_p.h
@@ -0,0 +1,278 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLPOOL_P_H
+#define QQMLPOOL_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtQml/qtqmlglobal.h>
+#include <QtCore/qstring.h>
+#include <QtCore/qurl.h>
+
+QT_BEGIN_NAMESPACE
+
+// Exported for QtQuick1
+class Q_QML_EXPORT QQmlPool
+{
+public:
+ // The class has a destructor that needs to be called
+ class Class {
+ public:
+ inline QQmlPool *pool() const;
+
+ private:
+ void *operator new(size_t);
+ void *operator new(size_t, void *m) { return m; }
+ friend class QQmlPool;
+
+ QQmlPool *_pool;
+ Class *_next;
+ void (*_destroy)(Class *);
+ };
+
+ // The class is plain old data and no destructor needs to
+ // be called
+ class POD {
+ public:
+ inline QQmlPool *pool() const;
+
+ private:
+ void *operator new(size_t);
+ void *operator new(size_t, void *m) { return m; }
+ friend class QQmlPool;
+
+ QQmlPool *_pool;
+ };
+
+ inline QQmlPool();
+ inline ~QQmlPool();
+
+ void clear();
+
+ template<typename T>
+ inline T *New();
+ template<typename T>
+ inline T *NewRaw();
+ template<typename T>
+ inline T *NewRawArray(int length);
+
+ inline QString *NewString(const QString &);
+ inline QByteArray *NewByteArray(const QByteArray &);
+ inline QUrl *NewUrl(const QUrl &);
+
+ template<typename T>
+ struct List {
+ List() : m_length(0), m_data(0) {}
+ List(const List &o) : m_length(o.m_length), m_data(o.m_data) {}
+ List &operator=(const List &o) {
+ m_length = o.m_length;
+ m_data = o.m_data;
+ return *this;
+ }
+
+ int count() const {
+ return m_length;
+ }
+ int length() const {
+ return m_length;
+ }
+ const T &at(int index) const {
+ Q_ASSERT(index < m_length);
+ return m_data[index];
+ };
+ T &operator[](int index) {
+ Q_ASSERT(index < m_length);
+ return m_data[index];
+ };
+ private:
+ friend class QQmlPool;
+ List(T *d, int l) : m_length(l), m_data(d) {}
+ int m_length;
+ T *m_data;
+ };
+
+ template<typename T>
+ inline List<T> NewRawList(int length);
+
+private:
+ struct StringClass : public QString, public Class {
+ };
+ struct ByteArrayClass : public QByteArray, public Class {
+ };
+ struct UrlClass : public QUrl, public Class {
+ };
+
+ inline void *allocate(int size);
+ void newpage();
+
+ template<typename T>
+ inline void initialize(POD *);
+ template<typename T>
+ inline void initialize(Class *);
+ template<typename T>
+ static void destroy(Class *c);
+
+ struct Page {
+ struct Header {
+ Page *next;
+ char *free;
+ } header;
+
+ static const int pageSize = 4 * 4096 - sizeof(Header);
+
+ char memory[pageSize];
+ };
+
+ Page *_page;
+ Class *_classList;
+};
+
+QQmlPool::QQmlPool()
+: _page(0), _classList(0)
+{
+}
+
+QQmlPool::~QQmlPool()
+{
+ clear();
+}
+
+template<typename T>
+T *QQmlPool::New()
+{
+ T *rv = new (allocate(sizeof(T))) T;
+ initialize<T>(rv);
+ rv->_pool = this;
+ return rv;
+}
+
+template<typename T>
+T *QQmlPool::NewRaw()
+{
+ return (T*)allocate(sizeof(T));
+}
+
+template<typename T>
+T *QQmlPool::NewRawArray(int length)
+{
+ return (T*)allocate(length * sizeof(T));
+}
+
+template<typename T>
+QQmlPool::List<T> QQmlPool::NewRawList(int length)
+{
+ return List<T>(NewRawArray<T>(length), length);
+}
+
+QString *QQmlPool::NewString(const QString &s)
+{
+ QString *rv = New<StringClass>();
+ *rv = s;
+ return rv;
+}
+
+QByteArray *QQmlPool::NewByteArray(const QByteArray &s)
+{
+ QByteArray *rv = New<ByteArrayClass>();
+ *rv = s;
+ return rv;
+}
+
+QUrl *QQmlPool::NewUrl(const QUrl &s)
+{
+ QUrl *rv = New<UrlClass>();
+ *rv = s;
+ return rv;
+}
+
+void *QQmlPool::allocate(int size)
+{
+ if (!_page || (_page->header.free + size) > (_page->memory + Page::pageSize))
+ newpage();
+
+ void *rv = _page->header.free;
+ _page->header.free += size + ((8 - size) & 7); // ensure 8 byte alignment;
+ return rv;
+}
+
+template<typename T>
+void QQmlPool::initialize(QQmlPool::POD *)
+{
+}
+
+template<typename T>
+void QQmlPool::initialize(QQmlPool::Class *c)
+{
+ c->_next = _classList;
+ c->_destroy = &destroy<T>;
+ _classList = c;
+}
+
+template<typename T>
+void QQmlPool::destroy(Class *c)
+{
+ static_cast<T *>(c)->~T();
+}
+
+QQmlPool *QQmlPool::Class::pool() const
+{
+ return _pool;
+}
+
+QQmlPool *QQmlPool::POD::pool() const
+{
+ return _pool;
+}
+
+QT_END_NAMESPACE
+
+#endif // QQMLPOOL_P_H
+
diff --git a/src/qml/qml/ftw/qqmlrefcount_p.h b/src/qml/qml/ftw/qqmlrefcount_p.h
new file mode 100644
index 0000000000..497f4ecc0f
--- /dev/null
+++ b/src/qml/qml/ftw/qqmlrefcount_p.h
@@ -0,0 +1,192 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLREFCOUNT_P_H
+#define QQMLREFCOUNT_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qglobal.h>
+#include <QtCore/qatomic.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+
+class QQmlRefCount
+{
+public:
+ inline QQmlRefCount();
+ inline virtual ~QQmlRefCount();
+ inline void addref();
+ inline void release();
+
+protected:
+ inline virtual void destroy();
+
+private:
+ QAtomicInt refCount;
+};
+
+template<class T>
+class QQmlRefPointer
+{
+public:
+ inline QQmlRefPointer();
+ inline QQmlRefPointer(T *);
+ inline QQmlRefPointer(const QQmlRefPointer<T> &);
+ inline ~QQmlRefPointer();
+
+ inline QQmlRefPointer<T> &operator=(const QQmlRefPointer<T> &o);
+ inline QQmlRefPointer<T> &operator=(T *);
+
+ inline bool isNull() const { return !o; }
+
+ inline T* operator->() const { return o; }
+ inline T& operator*() const { return *o; }
+ inline operator T*() const { return o; }
+ inline T* data() const { return o; }
+
+ inline QQmlRefPointer<T> &take(T *);
+
+private:
+ T *o;
+};
+
+QQmlRefCount::QQmlRefCount()
+: refCount(1)
+{
+}
+
+QQmlRefCount::~QQmlRefCount()
+{
+ Q_ASSERT(refCount.load() == 0);
+}
+
+void QQmlRefCount::addref()
+{
+ Q_ASSERT(refCount.load() > 0);
+ refCount.ref();
+}
+
+void QQmlRefCount::release()
+{
+ Q_ASSERT(refCount.load() > 0);
+ if (!refCount.deref())
+ destroy();
+}
+
+void QQmlRefCount::destroy()
+{
+ delete this;
+}
+
+template<class T>
+QQmlRefPointer<T>::QQmlRefPointer()
+: o(0)
+{
+}
+
+template<class T>
+QQmlRefPointer<T>::QQmlRefPointer(T *o)
+: o(o)
+{
+ if (o) o->addref();
+}
+
+template<class T>
+QQmlRefPointer<T>::QQmlRefPointer(const QQmlRefPointer<T> &other)
+: o(other.o)
+{
+ if (o) o->addref();
+}
+
+template<class T>
+QQmlRefPointer<T>::~QQmlRefPointer()
+{
+ if (o) o->release();
+}
+
+template<class T>
+QQmlRefPointer<T> &QQmlRefPointer<T>::operator=(const QQmlRefPointer<T> &other)
+{
+ if (other.o) other.o->addref();
+ if (o) o->release();
+ o = other.o;
+ return *this;
+}
+
+template<class T>
+QQmlRefPointer<T> &QQmlRefPointer<T>::operator=(T *other)
+{
+ if (other) other->addref();
+ if (o) o->release();
+ o = other;
+ return *this;
+}
+
+/*!
+Takes ownership of \a other. take() does *not* add a reference, as it assumes ownership
+of the callers reference of other.
+*/
+template<class T>
+QQmlRefPointer<T> &QQmlRefPointer<T>::take(T *other)
+{
+ if (o) o->release();
+ o = other;
+ return *this;
+}
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QQMLREFCOUNT_P_H
diff --git a/src/qml/qml/ftw/qqmlthread.cpp b/src/qml/qml/ftw/qqmlthread.cpp
new file mode 100644
index 0000000000..423012b934
--- /dev/null
+++ b/src/qml/qml/ftw/qqmlthread.cpp
@@ -0,0 +1,359 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qqmlthread_p.h"
+
+#include <private/qfieldlist_p.h>
+
+#include <QtCore/qmutex.h>
+#include <QtCore/qthread.h>
+#include <QtCore/qcoreevent.h>
+#include <QtCore/qwaitcondition.h>
+#include <QtCore/qcoreapplication.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQmlThreadPrivate : public QThread
+{
+public:
+ QQmlThreadPrivate(QQmlThread *);
+ QQmlThread *q;
+
+ virtual void run();
+
+ inline void lock() { _mutex.lock(); }
+ inline void unlock() { _mutex.unlock(); }
+ inline void wait() { _wait.wait(&_mutex); }
+ inline void wakeOne() { _wait.wakeOne(); }
+ inline void wakeAll() { _wait.wakeAll(); }
+
+ quint32 m_threadProcessing:1; // Set when the thread is processing messages
+ quint32 m_mainProcessing:1; // Set when the main thread is processing messages
+ quint32 m_shutdown:1; // Set by main thread to request a shutdown
+ quint32 m_mainThreadWaiting:1; // Set by main thread if it is waiting for the message queue to empty
+
+ typedef QFieldList<QQmlThread::Message, &QQmlThread::Message::next> MessageList;
+ MessageList threadList;
+ MessageList mainList;
+
+ QQmlThread::Message *mainSync;
+
+ void triggerMainEvent();
+ void triggerThreadEvent();
+
+ void mainEvent();
+ void threadEvent();
+
+protected:
+ virtual bool event(QEvent *);
+
+private:
+ struct MainObject : public QObject {
+ MainObject(QQmlThreadPrivate *p);
+ virtual bool event(QEvent *e);
+ QQmlThreadPrivate *p;
+ };
+ MainObject m_mainObject;
+
+ QMutex _mutex;
+ QWaitCondition _wait;
+};
+
+QQmlThreadPrivate::MainObject::MainObject(QQmlThreadPrivate *p)
+: p(p)
+{
+}
+
+// Trigger mainEvent in main thread. Must be called from thread.
+void QQmlThreadPrivate::triggerMainEvent()
+{
+ Q_ASSERT(q->isThisThread());
+ QCoreApplication::postEvent(&m_mainObject, new QEvent(QEvent::User));
+}
+
+// Trigger even in thread. Must be called from main thread.
+void QQmlThreadPrivate::triggerThreadEvent()
+{
+ Q_ASSERT(!q->isThisThread());
+ QCoreApplication::postEvent(this, new QEvent(QEvent::User));
+}
+
+bool QQmlThreadPrivate::MainObject::event(QEvent *e)
+{
+ if (e->type() == QEvent::User)
+ p->mainEvent();
+ return QObject::event(e);
+}
+
+QQmlThreadPrivate::QQmlThreadPrivate(QQmlThread *q)
+: q(q), m_threadProcessing(false), m_mainProcessing(false), m_shutdown(false),
+ m_mainThreadWaiting(false), mainSync(0), m_mainObject(this)
+{
+}
+
+bool QQmlThreadPrivate::event(QEvent *e)
+{
+ if (e->type() == QEvent::User)
+ threadEvent();
+ return QThread::event(e);
+}
+
+void QQmlThreadPrivate::run()
+{
+ lock();
+
+ wakeOne();
+
+ unlock();
+
+ q->startupThread();
+ exec();
+}
+
+void QQmlThreadPrivate::mainEvent()
+{
+ lock();
+
+ m_mainProcessing = true;
+
+ while (!mainList.isEmpty() || mainSync) {
+ bool isSync = mainSync != 0;
+ QQmlThread::Message *message = isSync?mainSync:mainList.takeFirst();
+ unlock();
+
+ message->call(q);
+ delete message;
+
+ lock();
+
+ if (isSync) {
+ mainSync = 0;
+ wakeOne();
+ }
+ }
+
+ m_mainProcessing = false;
+
+ unlock();
+}
+
+void QQmlThreadPrivate::threadEvent()
+{
+ lock();
+
+ if (m_shutdown) {
+ quit();
+ wakeOne();
+ unlock();
+ q->shutdownThread();
+ } else {
+ m_threadProcessing = true;
+
+ while (!threadList.isEmpty()) {
+ QQmlThread::Message *message = threadList.first();
+
+ unlock();
+
+ message->call(q);
+
+ lock();
+
+ delete threadList.takeFirst();
+ }
+
+ wakeOne();
+
+ m_threadProcessing = false;
+
+ unlock();
+ }
+}
+
+QQmlThread::QQmlThread()
+: d(new QQmlThreadPrivate(this))
+{
+ d->lock();
+ d->start();
+ d->wait();
+ d->unlock();
+ d->moveToThread(d);
+
+}
+
+QQmlThread::~QQmlThread()
+{
+ delete d;
+}
+
+void QQmlThread::shutdown()
+{
+ d->lock();
+ Q_ASSERT(!d->m_shutdown);
+ d->m_shutdown = true;
+ if (d->threadList.isEmpty() && d->m_threadProcessing == false)
+ d->triggerThreadEvent();
+ d->wait();
+ d->unlock();
+ d->QThread::wait();
+}
+
+void QQmlThread::lock()
+{
+ d->lock();
+}
+
+void QQmlThread::unlock()
+{
+ d->unlock();
+}
+
+void QQmlThread::wakeOne()
+{
+ d->wakeOne();
+}
+
+void QQmlThread::wakeAll()
+{
+ d->wakeAll();
+}
+
+void QQmlThread::wait()
+{
+ d->wait();
+}
+
+bool QQmlThread::isThisThread() const
+{
+ return QThread::currentThread() == d;
+}
+
+QThread *QQmlThread::thread() const
+{
+ return const_cast<QThread *>(static_cast<const QThread *>(d));
+}
+
+// Called when the thread starts. Do startup stuff in here.
+void QQmlThread::startupThread()
+{
+}
+
+// Called when the thread shuts down. Do cleanup in here.
+void QQmlThread::shutdownThread()
+{
+}
+
+void QQmlThread::internalCallMethodInThread(Message *message)
+{
+ Q_ASSERT(!isThisThread());
+ d->lock();
+ Q_ASSERT(d->m_mainThreadWaiting == false);
+
+ bool wasEmpty = d->threadList.isEmpty();
+ d->threadList.append(message);
+ if (wasEmpty && d->m_threadProcessing == false)
+ d->triggerThreadEvent();
+
+ d->m_mainThreadWaiting = true;
+
+ do {
+ if (d->mainSync) {
+ QQmlThread::Message *message = d->mainSync;
+ unlock();
+ message->call(this);
+ delete message;
+ lock();
+ d->mainSync = 0;
+ wakeOne();
+ } else {
+ d->wait();
+ }
+ } while (d->mainSync || !d->threadList.isEmpty());
+
+ d->m_mainThreadWaiting = false;
+ d->unlock();
+}
+
+void QQmlThread::internalCallMethodInMain(Message *message)
+{
+ Q_ASSERT(isThisThread());
+
+ d->lock();
+
+ Q_ASSERT(d->mainSync == 0);
+ d->mainSync = message;
+
+ if (d->m_mainThreadWaiting) {
+ d->wakeOne();
+ } else if (d->m_mainProcessing) {
+ // Do nothing - it is already looping
+ } else {
+ d->triggerMainEvent();
+ }
+
+ while (d->mainSync && !d->m_shutdown)
+ d->wait();
+
+ d->unlock();
+}
+
+void QQmlThread::internalPostMethodToThread(Message *message)
+{
+ Q_ASSERT(!isThisThread());
+ d->lock();
+ bool wasEmpty = d->threadList.isEmpty();
+ d->threadList.append(message);
+ if (wasEmpty && d->m_threadProcessing == false)
+ d->triggerThreadEvent();
+ d->unlock();
+}
+
+void QQmlThread::internalPostMethodToMain(Message *message)
+{
+ Q_ASSERT(isThisThread());
+ d->lock();
+ bool wasEmpty = d->mainList.isEmpty();
+ d->mainList.append(message);
+ if (wasEmpty && d->m_mainProcessing == false)
+ d->triggerMainEvent();
+ d->unlock();
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/ftw/qqmlthread_p.h b/src/qml/qml/ftw/qqmlthread_p.h
new file mode 100644
index 0000000000..8a0ec6ceaa
--- /dev/null
+++ b/src/qml/qml/ftw/qqmlthread_p.h
@@ -0,0 +1,318 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLTHREAD_P_H
+#define QQMLTHREAD_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+
+#include <QtCore/qglobal.h>
+
+#include <private/qintrusivelist_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QThread;
+
+class QQmlThreadPrivate;
+class QQmlThread
+{
+public:
+ QQmlThread();
+ virtual ~QQmlThread();
+ void shutdown();
+
+ void lock();
+ void unlock();
+ void wakeOne();
+ void wakeAll();
+ void wait();
+
+ QThread *thread() const;
+ bool isThisThread() const;
+
+ // Synchronously invoke a method in the thread
+ template<class O>
+ inline void callMethodInThread(void (O::*Member)());
+ template<typename T, class V, class O>
+ inline void callMethodInThread(void (O::*Member)(V), const T &);
+ template<typename T, typename T2, class V, class V2, class O>
+ inline void callMethodInThread(void (O::*Member)(V, V2), const T &, const T2 &);
+
+ // Synchronously invoke a method in the main thread. If the main thread is
+ // blocked in a callMethodInThread() call, the call is made from within that
+ // call.
+ template<class O>
+ inline void callMethodInMain(void (O::*Member)());
+ template<typename T, class V, class O>
+ inline void callMethodInMain(void (O::*Member)(V), const T &);
+ template<typename T, typename T2, class V, class V2, class O>
+ inline void callMethodInMain(void (O::*Member)(V, V2), const T &, const T2 &);
+
+ // Asynchronously invoke a method in the thread.
+ template<class O>
+ inline void postMethodToThread(void (O::*Member)());
+ template<typename T, class V, class O>
+ inline void postMethodToThread(void (O::*Member)(V), const T &);
+ template<typename T, typename T2, class V, class V2, class O>
+ inline void postMethodToThread(void (O::*Member)(V, V2), const T &, const T2 &);
+
+ // Asynchronously invoke a method in the main thread.
+ template<class O>
+ inline void postMethodToMain(void (O::*Member)());
+ template<typename T, class V, class O>
+ inline void postMethodToMain(void (O::*Member)(V), const T &);
+ template<typename T, typename T2, class V, class V2, class O>
+ inline void postMethodToMain(void (O::*Member)(V, V2), const T &, const T2 &);
+
+protected:
+ virtual void startupThread();
+ virtual void shutdownThread();
+
+private:
+ friend class QQmlThreadPrivate;
+
+ struct Message {
+ Message() : next(0) {}
+ virtual ~Message() {}
+ Message *next;
+ virtual void call(QQmlThread *) = 0;
+ };
+ void internalCallMethodInThread(Message *);
+ void internalCallMethodInMain(Message *);
+ void internalPostMethodToThread(Message *);
+ void internalPostMethodToMain(Message *);
+ QQmlThreadPrivate *d;
+};
+
+template<class O>
+void QQmlThread::callMethodInThread(void (O::*Member)())
+{
+ struct I : public Message {
+ void (O::*Member)();
+ I(void (O::*Member)()) : Member(Member) {}
+ virtual void call(QQmlThread *thread) {
+ O *me = static_cast<O *>(thread);
+ (me->*Member)();
+ }
+ };
+ internalCallMethodInThread(new I(Member));
+}
+
+template<typename T, class V, class O>
+void QQmlThread::callMethodInThread(void (O::*Member)(V), const T &arg)
+{
+ struct I : public Message {
+ void (O::*Member)(V);
+ T arg;
+ I(void (O::*Member)(V), const T &arg) : Member(Member), arg(arg) {}
+ virtual void call(QQmlThread *thread) {
+ O *me = static_cast<O *>(thread);
+ (me->*Member)(arg);
+ }
+ };
+ internalCallMethodInThread(new I(Member, arg));
+}
+
+template<typename T, typename T2, class V, class V2, class O>
+void QQmlThread::callMethodInThread(void (O::*Member)(V, V2), const T &arg, const T2 &arg2)
+{
+ struct I : public Message {
+ void (O::*Member)(V, V2);
+ T arg;
+ T2 arg2;
+ I(void (O::*Member)(V, V2), const T &arg, const T2 &arg2) : Member(Member), arg(arg), arg2(arg2) {}
+ virtual void call(QQmlThread *thread) {
+ O *me = static_cast<O *>(thread);
+ (me->*Member)(arg, arg2);
+ }
+ };
+ internalCallMethodInThread(new I(Member, arg, arg2));
+}
+
+template<class O>
+void QQmlThread::callMethodInMain(void (O::*Member)())
+{
+ struct I : public Message {
+ void (O::*Member)();
+ I(void (O::*Member)()) : Member(Member) {}
+ virtual void call(QQmlThread *thread) {
+ O *me = static_cast<O *>(thread);
+ (me->*Member)();
+ }
+ };
+ internalCallMethodInMain(new I(Member));
+}
+
+template<typename T, class V, class O>
+void QQmlThread::callMethodInMain(void (O::*Member)(V), const T &arg)
+{
+ struct I : public Message {
+ void (O::*Member)(V);
+ T arg;
+ I(void (O::*Member)(V), const T &arg) : Member(Member), arg(arg) {}
+ virtual void call(QQmlThread *thread) {
+ O *me = static_cast<O *>(thread);
+ (me->*Member)(arg);
+ }
+ };
+ internalCallMethodInMain(new I(Member, arg));
+}
+
+template<typename T, typename T2, class V, class V2, class O>
+void QQmlThread::callMethodInMain(void (O::*Member)(V, V2), const T &arg, const T2 &arg2)
+{
+ struct I : public Message {
+ void (O::*Member)(V, V2);
+ T arg;
+ T2 arg2;
+ I(void (O::*Member)(V, V2), const T &arg, const T2 &arg2) : Member(Member), arg(arg), arg2(arg2) {}
+ virtual void call(QQmlThread *thread) {
+ O *me = static_cast<O *>(thread);
+ (me->*Member)(arg, arg2);
+ }
+ };
+ internalCallMethodInMain(new I(Member, arg, arg2));
+}
+
+template<class O>
+void QQmlThread::postMethodToThread(void (O::*Member)())
+{
+ struct I : public Message {
+ void (O::*Member)();
+ I(void (O::*Member)()) : Member(Member) {}
+ virtual void call(QQmlThread *thread) {
+ O *me = static_cast<O *>(thread);
+ (me->*Member)();
+ }
+ };
+ internalPostMethodToThread(new I(Member));
+}
+
+template<typename T, class V, class O>
+void QQmlThread::postMethodToThread(void (O::*Member)(V), const T &arg)
+{
+ struct I : public Message {
+ void (O::*Member)(V);
+ T arg;
+ I(void (O::*Member)(V), const T &arg) : Member(Member), arg(arg) {}
+ virtual void call(QQmlThread *thread) {
+ O *me = static_cast<O *>(thread);
+ (me->*Member)(arg);
+ }
+ };
+ internalPostMethodToThread(new I(Member, arg));
+}
+
+template<typename T, typename T2, class V, class V2, class O>
+void QQmlThread::postMethodToThread(void (O::*Member)(V, V2), const T &arg, const T2 &arg2)
+{
+ struct I : public Message {
+ void (O::*Member)(V, V2);
+ T arg;
+ T2 arg2;
+ I(void (O::*Member)(V, V2), const T &arg, const T2 &arg2) : Member(Member), arg(arg), arg2(arg2) {}
+ virtual void call(QQmlThread *thread) {
+ O *me = static_cast<O *>(thread);
+ (me->*Member)(arg, arg2);
+ }
+ };
+ internalPostMethodToThread(new I(Member, arg, arg2));
+}
+
+template<class O>
+void QQmlThread::postMethodToMain(void (O::*Member)())
+{
+ struct I : public Message {
+ void (O::*Member)();
+ I(void (O::*Member)()) : Member(Member) {}
+ virtual void call(QQmlThread *thread) {
+ O *me = static_cast<O *>(thread);
+ (me->*Member)();
+ }
+ };
+ internalPostMethodToMain(new I(Member));
+}
+
+template<typename T, class V, class O>
+void QQmlThread::postMethodToMain(void (O::*Member)(V), const T &arg)
+{
+ struct I : public Message {
+ void (O::*Member)(V);
+ T arg;
+ I(void (O::*Member)(V), const T &arg) : Member(Member), arg(arg) {}
+ virtual void call(QQmlThread *thread) {
+ O *me = static_cast<O *>(thread);
+ (me->*Member)(arg);
+ }
+ };
+ internalPostMethodToMain(new I(Member, arg));
+}
+
+template<typename T, typename T2, class V, class V2, class O>
+void QQmlThread::postMethodToMain(void (O::*Member)(V, V2), const T &arg, const T2 &arg2)
+{
+ struct I : public Message {
+ void (O::*Member)(V, V2);
+ T arg;
+ T2 arg2;
+ I(void (O::*Member)(V, V2), const T &arg, const T2 &arg2) : Member(Member), arg(arg), arg2(arg2) {}
+ virtual void call(QQmlThread *thread) {
+ O *me = static_cast<O *>(thread);
+ (me->*Member)(arg, arg2);
+ }
+ };
+ internalPostMethodToMain(new I(Member, arg, arg2));
+}
+
+QT_END_NAMESPACE
+
+#endif // QQMLTHREAD_P_H
diff --git a/src/qml/qml/ftw/qqmltrace.cpp b/src/qml/qml/ftw/qqmltrace.cpp
new file mode 100644
index 0000000000..e044dc654f
--- /dev/null
+++ b/src/qml/qml/ftw/qqmltrace.cpp
@@ -0,0 +1,154 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qqmltrace_p.h"
+
+#ifdef QML_ENABLE_TRACE
+#include <stdio.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+#ifdef QML_ENABLE_TRACE
+
+QQmlTrace::Pool QQmlTrace::logPool;
+QQmlTrace::Entry *QQmlTrace::first = 0;
+QQmlTrace::Entry *QQmlTrace::last = 0;
+
+static qint64 toNsecs(QQmlTrace::TimeType time)
+{
+#ifdef Q_OS_MAC
+ static mach_timebase_info_data_t info = {0,0};
+ if (info.denom == 0)
+ mach_timebase_info(&info);
+ return time * info.numer / info.denom;
+#else
+ qint64 rv = time.tv_sec * 1000000000 + time.tv_nsec;
+ return rv;
+#endif
+}
+
+QQmlTrace::Pool::Pool()
+{
+ first = New<Entry>();
+ last = first;
+}
+
+QQmlTrace::Pool::~Pool()
+{
+ char buffer[128];
+ sprintf(buffer, "qml.%d.log", ::getpid());
+ FILE *out = fopen(buffer, "w");
+ if (!out) {
+ fprintf (stderr, "QML Log: Could not open %s\n", buffer);
+ return;
+ } else {
+ fprintf (stderr, "QML Log: Writing log to %s\n", buffer);
+ }
+
+ QQmlTrace::Entry *cur = QQmlTrace::first;
+ QByteArray indent;
+ int depth = -1;
+
+ qint64 firstTime = -1;
+
+ while (cur) {
+
+ switch (cur->type) {
+ case QQmlTrace::Entry::RangeStart: {
+ RangeStart *rs = static_cast<QQmlTrace::RangeStart *>(cur);
+
+ qint64 nsecs = toNsecs(rs->time);
+
+ if (firstTime == -1)
+ firstTime = nsecs;
+
+ nsecs -= firstTime;
+
+ depth++;
+ indent = QByteArray(depth * 4, ' ');
+ fprintf(out, "%s%s @%lld (%lld ns)\n", indent.constData(),
+ rs->description, nsecs, toNsecs(rs->end->time) - nsecs - firstTime);
+ } break;
+ case QQmlTrace::Entry::RangeEnd:
+ depth--;
+ indent = QByteArray(depth * 4, ' ');
+ break;
+ case QQmlTrace::Entry::Detail:
+ fprintf(out, "%s %s\n", indent.constData(),
+ static_cast<QQmlTrace::Detail *>(cur)->description);
+ break;
+ case QQmlTrace::Entry::IntDetail:
+ fprintf(out, "%s %s: %d\n", indent.constData(),
+ static_cast<QQmlTrace::Detail *>(cur)->description,
+ static_cast<QQmlTrace::IntDetail *>(cur)->value);
+ break;
+ case QQmlTrace::Entry::StringDetail: {
+ QByteArray vLatin1 = static_cast<QQmlTrace::StringDetail *>(cur)->value->toLatin1();
+ fprintf(out, "%s %s: %s\n", indent.constData(),
+ static_cast<QQmlTrace::Detail *>(cur)->description,
+ vLatin1.constData());
+ } break;
+ case QQmlTrace::Entry::UrlDetail: {
+ QByteArray vLatin1 = static_cast<QQmlTrace::UrlDetail *>(cur)->value->toString().toLatin1();
+ fprintf(out, "%s %s: %s\n", indent.constData(),
+ static_cast<QQmlTrace::Detail *>(cur)->description,
+ vLatin1.constData());
+ } break;
+ case QQmlTrace::Entry::Event: {
+ Event *ev = static_cast<QQmlTrace::Event *>(cur);
+ qint64 nsecs = toNsecs(ev->time) - firstTime;
+ fprintf(out, "%s + %s @%lld +%lld ns\n", indent.constData(),
+ ev->description, nsecs, nsecs - (toNsecs(ev->start->time) - firstTime));
+ } break;
+ case QQmlTrace::Entry::Null:
+ default:
+ break;
+ }
+ cur = cur->next;
+ }
+ fclose(out);
+}
+
+#endif
+
+QT_END_NAMESPACE
+
diff --git a/src/qml/qml/ftw/qqmltrace_p.h b/src/qml/qml/ftw/qqmltrace_p.h
new file mode 100644
index 0000000000..965baff3a3
--- /dev/null
+++ b/src/qml/qml/ftw/qqmltrace_p.h
@@ -0,0 +1,294 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLTRACE_P_H
+#define QQMLTRACE_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qglobal.h>
+#include <private/qqmlpool_p.h>
+
+// #define QML_ENABLE_TRACE
+
+#if defined(QML_ENABLE_TRACE) && defined(Q_OS_MAC)
+#include <mach/mach_time.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+class QUrl;
+class QQmlTrace
+{
+public:
+ inline QQmlTrace(const char *desc);
+ inline ~QQmlTrace();
+
+ inline void addDetail(const char *);
+ inline void addDetail(const char *, int);
+ inline void addDetail(const char *, const QString &);
+ inline void addDetail(const char *, const QUrl &);
+
+ inline void event(const char *desc);
+
+#ifdef QML_ENABLE_TRACE
+
+#ifdef Q_OS_MAC
+ typedef uint64_t TimeType;
+#else
+ typedef timespec TimeType;
+#endif
+
+ struct Entry : public QQmlPool::POD {
+ enum Type { Null, RangeStart, RangeEnd, Detail, IntDetail, StringDetail, UrlDetail, Event };
+ inline Entry();
+ inline Entry(Type);
+ Type type;
+ Entry *next;
+ };
+ struct RangeEnd : public Entry {
+ inline RangeEnd();
+ TimeType time;
+ };
+ struct RangeStart : public Entry {
+ inline RangeStart();
+ const char *description;
+ TimeType time;
+ QQmlTrace::RangeEnd *end;
+ };
+ struct Detail : public Entry {
+ inline Detail();
+ inline Detail(Type t);
+ const char *description;
+ };
+ struct IntDetail : public Detail {
+ inline IntDetail();
+ int value;
+ };
+ struct StringDetail : public Detail {
+ inline StringDetail();
+ QString *value;
+ };
+ struct UrlDetail : public Detail {
+ inline UrlDetail();
+ QUrl *value;
+ };
+ struct Event : public Entry {
+ inline Event();
+ const char *description;
+ TimeType time;
+ QQmlTrace::RangeStart *start;
+ };
+
+ struct Pool : public QQmlPool {
+ Pool();
+ ~Pool();
+ };
+
+ static Pool logPool;
+ static Entry *first;
+ static Entry *last;
+
+private:
+ RangeStart *start;
+
+ static TimeType gettime() {
+#ifdef Q_OS_MAC
+ return mach_absolute_time();
+#else
+ TimeType ts;
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+ return ts;
+#endif
+ }
+#endif
+};
+
+#ifdef QML_ENABLE_TRACE
+QQmlTrace::Entry::Entry()
+: type(Null), next(0)
+{
+}
+
+QQmlTrace::Entry::Entry(Type type)
+: type(type), next(0)
+{
+ QQmlTrace::last->next = this;
+ QQmlTrace::last = this;
+}
+
+QQmlTrace::RangeEnd::RangeEnd()
+: QQmlTrace::Entry(QQmlTrace::Entry::RangeEnd),
+ time(gettime())
+{
+}
+
+QQmlTrace::RangeStart::RangeStart()
+: QQmlTrace::Entry(QQmlTrace::Entry::RangeStart),
+ description(0), time(gettime())
+{
+}
+
+QQmlTrace::Detail::Detail()
+: QQmlTrace::Entry(QQmlTrace::Entry::Detail),
+ description(0)
+{
+}
+
+QQmlTrace::Detail::Detail(Type type)
+: QQmlTrace::Entry(type), description(0)
+{
+}
+
+QQmlTrace::IntDetail::IntDetail()
+: QQmlTrace::Detail(QQmlTrace::Entry::IntDetail),
+ value(0)
+{
+}
+
+QQmlTrace::StringDetail::StringDetail()
+: QQmlTrace::Detail(QQmlTrace::Entry::StringDetail),
+ value(0)
+{
+}
+
+QQmlTrace::UrlDetail::UrlDetail()
+: QQmlTrace::Detail(QQmlTrace::Entry::UrlDetail),
+ value(0)
+{
+}
+
+QQmlTrace::Event::Event()
+: QQmlTrace::Entry(QQmlTrace::Entry::Event),
+ description(0), time(gettime()), start(0)
+{
+}
+#endif
+
+QQmlTrace::QQmlTrace(const char *desc)
+{
+#ifdef QML_ENABLE_TRACE
+ RangeStart *e = logPool.New<RangeStart>();
+ e->description = desc;
+ e->end = 0;
+ start = e;
+#else
+ Q_UNUSED(desc);
+#endif
+}
+
+QQmlTrace::~QQmlTrace()
+{
+#ifdef QML_ENABLE_TRACE
+ RangeEnd *e = logPool.New<RangeEnd>();
+ start->end = e;
+#endif
+}
+
+void QQmlTrace::addDetail(const char *desc)
+{
+#ifdef QML_ENABLE_TRACE
+ Detail *e = logPool.New<Detail>();
+ e->description = desc;
+#else
+ Q_UNUSED(desc);
+#endif
+}
+
+void QQmlTrace::addDetail(const char *desc, int v)
+{
+#ifdef QML_ENABLE_TRACE
+ IntDetail *e = logPool.New<IntDetail>();
+ e->description = desc;
+ e->value = v;
+#else
+ Q_UNUSED(desc);
+ Q_UNUSED(v);
+#endif
+}
+
+void QQmlTrace::addDetail(const char *desc, const QString &v)
+{
+#ifdef QML_ENABLE_TRACE
+ StringDetail *e = logPool.New<StringDetail>();
+ e->description = desc;
+ e->value = logPool.NewString(v);
+#else
+ Q_UNUSED(desc);
+ Q_UNUSED(v);
+#endif
+}
+
+void QQmlTrace::addDetail(const char *desc, const QUrl &v)
+{
+#ifdef QML_ENABLE_TRACE
+ UrlDetail *e = logPool.New<UrlDetail>();
+ e->description = desc;
+ e->value = logPool.NewUrl(v);
+#else
+ Q_UNUSED(desc);
+ Q_UNUSED(v);
+#endif
+}
+
+void QQmlTrace::event(const char *desc)
+{
+#ifdef QML_ENABLE_TRACE
+ Event *e = logPool.New<Event>();
+ e->start = start;
+ e->description = desc;
+#else
+ Q_UNUSED(desc);
+#endif
+}
+
+QT_END_NAMESPACE
+
+#endif // QQMLTRACE_P_H
diff --git a/src/qml/qml/ftw/qrecursionwatcher_p.h b/src/qml/qml/ftw/qrecursionwatcher_p.h
new file mode 100644
index 0000000000..16886edf12
--- /dev/null
+++ b/src/qml/qml/ftw/qrecursionwatcher_p.h
@@ -0,0 +1,105 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QRECURSIONWATCHER_P_H
+#define QRECURSIONWATCHER_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qglobal.h>
+
+QT_BEGIN_NAMESPACE
+
+class QRecursionNode;
+class QRecursionNode {
+public:
+ inline QRecursionNode();
+ bool *_r;
+};
+
+template<class T, QRecursionNode T::*Node>
+class QRecursionWatcher {
+public:
+ inline QRecursionWatcher(T *);
+ inline ~QRecursionWatcher();
+ inline bool hasRecursed() const;
+private:
+ T *_t;
+ bool _r;
+};
+
+QRecursionNode::QRecursionNode()
+: _r(0)
+{
+}
+
+template<class T, QRecursionNode T::*Node>
+QRecursionWatcher<T, Node>::QRecursionWatcher(T *t)
+: _t(t), _r(false)
+{
+ if ((_t->*Node)._r) *(_t->*Node)._r = true;
+ (_t->*Node)._r = &_r;
+}
+
+template<class T, QRecursionNode T::*Node>
+QRecursionWatcher<T, Node>::~QRecursionWatcher()
+{
+ if ((_t->*Node)._r == &_r) (_t->*Node)._r = 0;
+}
+
+template<class T, QRecursionNode T::*Node>
+bool QRecursionWatcher<T, Node>::hasRecursed() const
+{
+ return _r;
+}
+
+QT_END_NAMESPACE
+
+#endif // QRECURSIONWATCHER_P_H
diff --git a/src/qml/qml/ftw/qrecyclepool_p.h b/src/qml/qml/ftw/qrecyclepool_p.h
new file mode 100644
index 0000000000..8d0f060ab3
--- /dev/null
+++ b/src/qml/qml/ftw/qrecyclepool_p.h
@@ -0,0 +1,220 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QRECYCLEPOOL_P_H
+#define QRECYCLEPOOL_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.
+//
+
+QT_BEGIN_NAMESPACE
+
+#define QRECYCLEPOOLCOOKIE 0x33218ADF
+
+template<typename T, int Step>
+class QRecyclePoolPrivate
+{
+public:
+ QRecyclePoolPrivate()
+ : recyclePoolHold(true), outstandingItems(0), cookie(QRECYCLEPOOLCOOKIE),
+ currentPage(0), nextAllocated(0)
+ {
+ }
+
+ bool recyclePoolHold;
+ int outstandingItems;
+ quint32 cookie;
+
+ struct PoolType : public T {
+ union {
+ QRecyclePoolPrivate<T, Step> *pool;
+ PoolType *nextAllocated;
+ };
+ };
+
+ struct Page {
+ Page *nextPage;
+ unsigned int free;
+ union {
+ char array[Step * sizeof(PoolType)];
+ qint64 q_for_alignment_1;
+ double q_for_alignment_2;
+ };
+ };
+
+ Page *currentPage;
+ PoolType *nextAllocated;
+
+ inline T *allocate();
+ static inline void dispose(T *);
+ inline void releaseIfPossible();
+};
+
+template<typename T, int Step = 1024>
+class QRecyclePool
+{
+public:
+ inline QRecyclePool();
+ inline ~QRecyclePool();
+
+ inline T *New();
+ template<typename T1>
+ inline T *New(const T1 &);
+ template<typename T1>
+ inline T *New(T1 &);
+
+ static inline void Delete(T *);
+
+private:
+ QRecyclePoolPrivate<T, Step> *d;
+};
+
+template<typename T, int Step>
+QRecyclePool<T, Step>::QRecyclePool()
+: d(new QRecyclePoolPrivate<T, Step>())
+{
+}
+
+template<typename T, int Step>
+QRecyclePool<T, Step>::~QRecyclePool()
+{
+ d->recyclePoolHold = false;
+ d->releaseIfPossible();
+}
+
+template<typename T, int Step>
+T *QRecyclePool<T, Step>::New()
+{
+ T *rv = d->allocate();
+ new (rv) T;
+ return rv;
+}
+
+template<typename T, int Step>
+template<typename T1>
+T *QRecyclePool<T, Step>::New(const T1 &a)
+{
+ T *rv = d->allocate();
+ new (rv) T(a);
+ return rv;
+}
+
+template<typename T, int Step>
+template<typename T1>
+T *QRecyclePool<T, Step>::New(T1 &a)
+{
+ T *rv = d->allocate();
+ new (rv) T(a);
+ return rv;
+}
+
+template<typename T, int Step>
+void QRecyclePool<T, Step>::Delete(T *t)
+{
+ t->~T();
+ QRecyclePoolPrivate<T, Step>::dispose(t);
+}
+
+template<typename T, int Step>
+void QRecyclePoolPrivate<T, Step>::releaseIfPossible()
+{
+ if (recyclePoolHold || outstandingItems)
+ return;
+
+ Page *p = currentPage;
+ while (p) {
+ Page *n = p->nextPage;
+ qFree(p);
+ p = n;
+ }
+
+ delete this;
+}
+
+template<typename T, int Step>
+T *QRecyclePoolPrivate<T, Step>::allocate()
+{
+ PoolType *rv = 0;
+ if (nextAllocated) {
+ rv = nextAllocated;
+ nextAllocated = rv->nextAllocated;
+ } else if (currentPage && currentPage->free) {
+ rv = (PoolType *)(currentPage->array + (Step - currentPage->free) * sizeof(PoolType));
+ currentPage->free--;
+ } else {
+ Page *p = (Page *)qMalloc(sizeof(Page));
+ p->nextPage = currentPage;
+ p->free = Step;
+ currentPage = p;
+
+ rv = (PoolType *)currentPage->array;
+ currentPage->free--;
+ }
+
+ rv->pool = this;
+ ++outstandingItems;
+ return rv;
+}
+
+template<typename T, int Step>
+void QRecyclePoolPrivate<T, Step>::dispose(T *t)
+{
+ PoolType *pt = static_cast<PoolType *>(t);
+ Q_ASSERT(pt->pool && pt->pool->cookie == QRECYCLEPOOLCOOKIE);
+
+ QRecyclePoolPrivate<T, Step> *This = pt->pool;
+ pt->nextAllocated = This->nextAllocated;
+ This->nextAllocated = pt;
+ --This->outstandingItems;
+ This->releaseIfPossible();
+}
+
+QT_END_NAMESPACE
+
+#endif // QRECYCLEPOOL_P_H
diff --git a/src/qml/qml/parser/parser.pri b/src/qml/qml/parser/parser.pri
new file mode 100644
index 0000000000..6be85ba85a
--- /dev/null
+++ b/src/qml/qml/parser/parser.pri
@@ -0,0 +1,19 @@
+HEADERS += \
+ $$PWD/qqmljsast_p.h \
+ $$PWD/qqmljsastfwd_p.h \
+ $$PWD/qqmljsastvisitor_p.h \
+ $$PWD/qqmljsengine_p.h \
+ $$PWD/qqmljsgrammar_p.h \
+ $$PWD/qqmljslexer_p.h \
+ $$PWD/qqmljsmemorypool_p.h \
+ $$PWD/qqmljsparser_p.h \
+ $$PWD/qqmljsglobal_p.h \
+ $$PWD/qqmljskeywords_p.h
+
+SOURCES += \
+ $$PWD/qqmljsast.cpp \
+ $$PWD/qqmljsastvisitor.cpp \
+ $$PWD/qqmljsengine_p.cpp \
+ $$PWD/qqmljsgrammar.cpp \
+ $$PWD/qqmljslexer.cpp \
+ $$PWD/qqmljsparser.cpp
diff --git a/src/qml/qml/parser/qqmljs.g b/src/qml/qml/parser/qqmljs.g
new file mode 100644
index 0000000000..746fcb24df
--- /dev/null
+++ b/src/qml/qml/parser/qqmljs.g
@@ -0,0 +1,3016 @@
+----------------------------------------------------------------------------
+--
+-- Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+-- Contact: http://www.qt-project.org/
+--
+-- This file is part of the QtQml module of the Qt Toolkit.
+--
+-- $QT_BEGIN_LICENSE:LGPL-ONLY$
+-- GNU Lesser General Public License Usage
+-- 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.
+--
+-- If you have questions regarding the use of this file, please contact
+-- us via http://www.qt-project.org/.
+--
+-- $QT_END_LICENSE$
+--
+----------------------------------------------------------------------------
+
+%parser QQmlJSGrammar
+%decl qqmljsparser_p.h
+%impl qdeclarativejsparser.cpp
+%expect 2
+%expect-rr 2
+
+%token T_AND "&" T_AND_AND "&&" T_AND_EQ "&="
+%token T_BREAK "break" T_CASE "case" T_CATCH "catch"
+%token T_COLON ":" T_COMMA "," T_CONTINUE "continue"
+%token T_DEFAULT "default" T_DELETE "delete" T_DIVIDE_ "/"
+%token T_DIVIDE_EQ "/=" T_DO "do" T_DOT "."
+%token T_ELSE "else" T_EQ "=" T_EQ_EQ "=="
+%token T_EQ_EQ_EQ "===" T_FINALLY "finally" T_FOR "for"
+%token T_FUNCTION "function" T_GE ">=" T_GT ">"
+%token T_GT_GT ">>" T_GT_GT_EQ ">>=" T_GT_GT_GT ">>>"
+%token T_GT_GT_GT_EQ ">>>=" T_IDENTIFIER "identifier" T_IF "if"
+%token T_IN "in" T_INSTANCEOF "instanceof" T_LBRACE "{"
+%token T_LBRACKET "[" T_LE "<=" T_LPAREN "("
+%token T_LT "<" T_LT_LT "<<" T_LT_LT_EQ "<<="
+%token T_MINUS "-" T_MINUS_EQ "-=" T_MINUS_MINUS "--"
+%token T_NEW "new" T_NOT "!" T_NOT_EQ "!="
+%token T_NOT_EQ_EQ "!==" T_NUMERIC_LITERAL "numeric literal" T_OR "|"
+%token T_OR_EQ "|=" T_OR_OR "||" T_PLUS "+"
+%token T_PLUS_EQ "+=" T_PLUS_PLUS "++" T_QUESTION "?"
+%token T_RBRACE "}" T_RBRACKET "]" T_REMAINDER "%"
+%token T_REMAINDER_EQ "%=" T_RETURN "return" T_RPAREN ")"
+%token T_SEMICOLON ";" T_AUTOMATIC_SEMICOLON T_STAR "*"
+%token T_STAR_EQ "*=" T_STRING_LITERAL "string literal"
+%token T_PROPERTY "property" T_SIGNAL "signal" T_READONLY "readonly"
+%token T_SWITCH "switch" T_THIS "this" T_THROW "throw"
+%token T_TILDE "~" T_TRY "try" T_TYPEOF "typeof"
+%token T_VAR "var" T_VOID "void" T_WHILE "while"
+%token T_WITH "with" T_XOR "^" T_XOR_EQ "^="
+%token T_NULL "null" T_TRUE "true" T_FALSE "false"
+%token T_CONST "const"
+%token T_DEBUGGER "debugger"
+%token T_RESERVED_WORD "reserved word"
+%token T_MULTILINE_STRING_LITERAL "multiline string literal"
+%token T_COMMENT "comment"
+
+--- context keywords.
+%token T_PUBLIC "public"
+%token T_IMPORT "import"
+%token T_AS "as"
+%token T_ON "on"
+
+%token T_ERROR
+
+--- feed tokens
+%token T_FEED_UI_PROGRAM
+%token T_FEED_UI_OBJECT_MEMBER
+%token T_FEED_JS_STATEMENT
+%token T_FEED_JS_EXPRESSION
+%token T_FEED_JS_SOURCE_ELEMENT
+%token T_FEED_JS_PROGRAM
+
+%nonassoc SHIFT_THERE
+%nonassoc T_IDENTIFIER T_COLON T_SIGNAL T_PROPERTY T_READONLY
+%nonassoc REDUCE_HERE
+
+%start TopLevel
+
+/./****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtCore/QtDebug>
+#include <QtCore/QCoreApplication>
+
+#include <string.h>
+
+#include "qqmljsengine_p.h"
+#include "qqmljslexer_p.h"
+#include "qqmljsast_p.h"
+#include "qqmljsmemorypool_p.h"
+
+./
+
+/:/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+//
+// 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.
+//
+
+//
+// This file is automatically generated from qmljs.g.
+// Changes will be lost.
+//
+
+#ifndef QDECLARATIVEJSPARSER_P_H
+#define QDECLARATIVEJSPARSER_P_H
+
+#include "qqmljsglobal_p.h"
+#include "qqmljsgrammar_p.h"
+#include "qqmljsast_p.h"
+#include "qqmljsengine_p.h"
+
+#include <QtCore/QList>
+#include <QtCore/QString>
+
+QT_QML_BEGIN_NAMESPACE
+
+namespace QQmlJS {
+
+class Engine;
+
+class QML_PARSER_EXPORT Parser: protected $table
+{
+public:
+ union Value {
+ int ival;
+ double dval;
+ AST::ArgumentList *ArgumentList;
+ AST::CaseBlock *CaseBlock;
+ AST::CaseClause *CaseClause;
+ AST::CaseClauses *CaseClauses;
+ AST::Catch *Catch;
+ AST::DefaultClause *DefaultClause;
+ AST::ElementList *ElementList;
+ AST::Elision *Elision;
+ AST::ExpressionNode *Expression;
+ AST::Finally *Finally;
+ AST::FormalParameterList *FormalParameterList;
+ AST::FunctionBody *FunctionBody;
+ AST::FunctionDeclaration *FunctionDeclaration;
+ AST::Node *Node;
+ AST::PropertyName *PropertyName;
+ AST::PropertyNameAndValueList *PropertyNameAndValueList;
+ AST::SourceElement *SourceElement;
+ AST::SourceElements *SourceElements;
+ AST::Statement *Statement;
+ AST::StatementList *StatementList;
+ AST::Block *Block;
+ AST::VariableDeclaration *VariableDeclaration;
+ AST::VariableDeclarationList *VariableDeclarationList;
+
+ AST::UiProgram *UiProgram;
+ AST::UiImportList *UiImportList;
+ AST::UiImport *UiImport;
+ AST::UiParameterList *UiParameterList;
+ AST::UiPublicMember *UiPublicMember;
+ AST::UiObjectDefinition *UiObjectDefinition;
+ AST::UiObjectInitializer *UiObjectInitializer;
+ AST::UiObjectBinding *UiObjectBinding;
+ AST::UiScriptBinding *UiScriptBinding;
+ AST::UiArrayBinding *UiArrayBinding;
+ AST::UiObjectMember *UiObjectMember;
+ AST::UiObjectMemberList *UiObjectMemberList;
+ AST::UiArrayMemberList *UiArrayMemberList;
+ AST::UiQualifiedId *UiQualifiedId;
+ };
+
+public:
+ Parser(Engine *engine);
+ ~Parser();
+
+ // parse a UI program
+ bool parse() { return parse(T_FEED_UI_PROGRAM); }
+ bool parseStatement() { return parse(T_FEED_JS_STATEMENT); }
+ bool parseExpression() { return parse(T_FEED_JS_EXPRESSION); }
+ bool parseSourceElement() { return parse(T_FEED_JS_SOURCE_ELEMENT); }
+ bool parseUiObjectMember() { return parse(T_FEED_UI_OBJECT_MEMBER); }
+ bool parseProgram() { return parse(T_FEED_JS_PROGRAM); }
+
+ AST::UiProgram *ast() const
+ { return AST::cast<AST::UiProgram *>(program); }
+
+ AST::Statement *statement() const
+ {
+ if (! program)
+ return 0;
+
+ return program->statementCast();
+ }
+
+ AST::ExpressionNode *expression() const
+ {
+ if (! program)
+ return 0;
+
+ return program->expressionCast();
+ }
+
+ AST::UiObjectMember *uiObjectMember() const
+ {
+ if (! program)
+ return 0;
+
+ return program->uiObjectMemberCast();
+ }
+
+ AST::Node *rootNode() const
+ { return program; }
+
+ QList<DiagnosticMessage> diagnosticMessages() const
+ { return diagnostic_messages; }
+
+ inline DiagnosticMessage diagnosticMessage() const
+ {
+ foreach (const DiagnosticMessage &d, diagnostic_messages) {
+ if (! d.kind == DiagnosticMessage::Warning)
+ return d;
+ }
+
+ return DiagnosticMessage();
+ }
+
+ inline QString errorMessage() const
+ { return diagnosticMessage().message; }
+
+ inline int errorLineNumber() const
+ { return diagnosticMessage().loc.startLine; }
+
+ inline int errorColumnNumber() const
+ { return diagnosticMessage().loc.startColumn; }
+
+protected:
+ bool parse(int startToken);
+
+ void reallocateStack();
+
+ inline Value &sym(int index)
+ { return sym_stack [tos + index - 1]; }
+
+ inline QStringRef &stringRef(int index)
+ { return string_stack [tos + index - 1]; }
+
+ inline AST::SourceLocation &loc(int index)
+ { return location_stack [tos + index - 1]; }
+
+ AST::UiQualifiedId *reparseAsQualifiedId(AST::ExpressionNode *expr);
+
+protected:
+ Engine *driver;
+ MemoryPool *pool;
+ int tos;
+ int stack_size;
+ Value *sym_stack;
+ int *state_stack;
+ AST::SourceLocation *location_stack;
+ QStringRef *string_stack;
+
+ AST::Node *program;
+
+ // error recovery
+ enum { TOKEN_BUFFER_SIZE = 3 };
+
+ struct SavedToken {
+ int token;
+ double dval;
+ AST::SourceLocation loc;
+ QStringRef spell;
+ };
+
+ double yylval;
+ QStringRef yytokenspell;
+ AST::SourceLocation yylloc;
+ AST::SourceLocation yyprevlloc;
+
+ SavedToken token_buffer[TOKEN_BUFFER_SIZE];
+ SavedToken *first_token;
+ SavedToken *last_token;
+
+ QList<DiagnosticMessage> diagnostic_messages;
+};
+
+} // end of namespace QQmlJS
+
+
+:/
+
+
+/.
+
+#include "qqmljsparser_p.h"
+#include <QVarLengthArray>
+
+//
+// This file is automatically generated from qmljs.g.
+// Changes will be lost.
+//
+
+using namespace QQmlJS;
+
+QT_QML_BEGIN_NAMESPACE
+
+void Parser::reallocateStack()
+{
+ if (! stack_size)
+ stack_size = 128;
+ else
+ stack_size <<= 1;
+
+ sym_stack = reinterpret_cast<Value*> (realloc(sym_stack, stack_size * sizeof(Value)));
+ state_stack = reinterpret_cast<int*> (realloc(state_stack, stack_size * sizeof(int)));
+ location_stack = reinterpret_cast<AST::SourceLocation*> (realloc(location_stack, stack_size * sizeof(AST::SourceLocation)));
+ string_stack = reinterpret_cast<QStringRef*> (realloc(string_stack, stack_size * sizeof(QStringRef)));
+}
+
+Parser::Parser(Engine *engine):
+ driver(engine),
+ pool(engine->pool()),
+ tos(0),
+ stack_size(0),
+ sym_stack(0),
+ state_stack(0),
+ location_stack(0),
+ string_stack(0),
+ first_token(0),
+ last_token(0)
+{
+}
+
+Parser::~Parser()
+{
+ if (stack_size) {
+ free(sym_stack);
+ free(state_stack);
+ free(location_stack);
+ free(string_stack);
+ }
+}
+
+static inline AST::SourceLocation location(Lexer *lexer)
+{
+ AST::SourceLocation loc;
+ loc.offset = lexer->tokenOffset();
+ loc.length = lexer->tokenLength();
+ loc.startLine = lexer->tokenStartLine();
+ loc.startColumn = lexer->tokenStartColumn();
+ return loc;
+}
+
+AST::UiQualifiedId *Parser::reparseAsQualifiedId(AST::ExpressionNode *expr)
+{
+ QVarLengthArray<QStringRef, 4> nameIds;
+ QVarLengthArray<AST::SourceLocation, 4> locations;
+
+ AST::ExpressionNode *it = expr;
+ while (AST::FieldMemberExpression *m = AST::cast<AST::FieldMemberExpression *>(it)) {
+ nameIds.append(m->name);
+ locations.append(m->identifierToken);
+ it = m->base;
+ }
+
+ if (AST::IdentifierExpression *idExpr = AST::cast<AST::IdentifierExpression *>(it)) {
+ AST::UiQualifiedId *q = new (pool) AST::UiQualifiedId(idExpr->name);
+ q->identifierToken = idExpr->identifierToken;
+
+ AST::UiQualifiedId *currentId = q;
+ for (int i = nameIds.size() - 1; i != -1; --i) {
+ currentId = new (pool) AST::UiQualifiedId(currentId, nameIds[i]);
+ currentId->identifierToken = locations[i];
+ }
+
+ return currentId->finish();
+ }
+
+ return 0;
+}
+
+bool Parser::parse(int startToken)
+{
+ Lexer *lexer = driver->lexer();
+ bool hadErrors = false;
+ int yytoken = -1;
+ int action = 0;
+
+ token_buffer[0].token = startToken;
+ first_token = &token_buffer[0];
+ last_token = &token_buffer[1];
+
+ tos = -1;
+ program = 0;
+
+ do {
+ if (++tos == stack_size)
+ reallocateStack();
+
+ state_stack[tos] = action;
+
+ _Lcheck_token:
+ if (yytoken == -1 && -TERMINAL_COUNT != action_index[action]) {
+ yyprevlloc = yylloc;
+
+ if (first_token == last_token) {
+ yytoken = lexer->lex();
+ yylval = lexer->tokenValue();
+ yytokenspell = lexer->tokenSpell();
+ yylloc = location(lexer);
+ } else {
+ yytoken = first_token->token;
+ yylval = first_token->dval;
+ yytokenspell = first_token->spell;
+ yylloc = first_token->loc;
+ ++first_token;
+ }
+ }
+
+ action = t_action(action, yytoken);
+ if (action > 0) {
+ if (action != ACCEPT_STATE) {
+ yytoken = -1;
+ sym(1).dval = yylval;
+ stringRef(1) = yytokenspell;
+ loc(1) = yylloc;
+ } else {
+ --tos;
+ return ! hadErrors;
+ }
+ } else if (action < 0) {
+ const int r = -action - 1;
+ tos -= rhs[r];
+
+ switch (r) {
+./
+
+--------------------------------------------------------------------------------------------------------
+-- Declarative UI
+--------------------------------------------------------------------------------------------------------
+
+TopLevel: T_FEED_UI_PROGRAM UiProgram ;
+/.
+case $rule_number: {
+ sym(1).Node = sym(2).Node;
+ program = sym(1).Node;
+} break;
+./
+
+TopLevel: T_FEED_JS_STATEMENT Statement ;
+/.
+case $rule_number: {
+ sym(1).Node = sym(2).Node;
+ program = sym(1).Node;
+} break;
+./
+
+TopLevel: T_FEED_JS_EXPRESSION Expression ;
+/.
+case $rule_number: {
+ sym(1).Node = sym(2).Node;
+ program = sym(1).Node;
+} break;
+./
+
+TopLevel: T_FEED_JS_SOURCE_ELEMENT SourceElement ;
+/.
+case $rule_number: {
+ sym(1).Node = sym(2).Node;
+ program = sym(1).Node;
+} break;
+./
+
+TopLevel: T_FEED_UI_OBJECT_MEMBER UiObjectMember ;
+/.
+case $rule_number: {
+ sym(1).Node = sym(2).Node;
+ program = sym(1).Node;
+} break;
+./
+
+TopLevel: T_FEED_JS_PROGRAM Program ;
+/.
+case $rule_number: {
+ sym(1).Node = sym(2).Node;
+ program = sym(1).Node;
+} break;
+./
+
+UiProgram: UiImportListOpt UiRootMember ;
+/.
+case $rule_number: {
+ sym(1).UiProgram = new (pool) AST::UiProgram(sym(1).UiImportList,
+ sym(2).UiObjectMemberList->finish());
+} break;
+./
+
+UiImportListOpt: Empty ;
+UiImportListOpt: UiImportList ;
+/.
+case $rule_number: {
+ sym(1).Node = sym(1).UiImportList->finish();
+} break;
+./
+
+UiImportList: UiImport ;
+/.
+case $rule_number: {
+ sym(1).Node = new (pool) AST::UiImportList(sym(1).UiImport);
+} break;
+./
+
+UiImportList: UiImportList UiImport ;
+/.
+case $rule_number: {
+ sym(1).Node = new (pool) AST::UiImportList(sym(1).UiImportList, sym(2).UiImport);
+} break;
+./
+
+ImportId: MemberExpression ;
+
+UiImport: UiImportHead T_AUTOMATIC_SEMICOLON ;
+UiImport: UiImportHead T_SEMICOLON ;
+/.
+case $rule_number: {
+ sym(1).UiImport->semicolonToken = loc(2);
+} break;
+./
+
+UiImport: UiImportHead T_NUMERIC_LITERAL T_AUTOMATIC_SEMICOLON ;
+UiImport: UiImportHead T_NUMERIC_LITERAL T_SEMICOLON ;
+/.
+case $rule_number: {
+ sym(1).UiImport->versionToken = loc(2);
+ sym(1).UiImport->semicolonToken = loc(3);
+} break;
+./
+
+UiImport: UiImportHead T_NUMERIC_LITERAL T_AS JsIdentifier T_AUTOMATIC_SEMICOLON ;
+UiImport: UiImportHead T_NUMERIC_LITERAL T_AS JsIdentifier T_SEMICOLON ;
+/.
+case $rule_number: {
+ sym(1).UiImport->versionToken = loc(2);
+ sym(1).UiImport->asToken = loc(3);
+ sym(1).UiImport->importIdToken = loc(4);
+ sym(1).UiImport->importId = stringRef(4);
+ sym(1).UiImport->semicolonToken = loc(5);
+} break;
+./
+
+UiImport: UiImportHead T_AS JsIdentifier T_AUTOMATIC_SEMICOLON ;
+UiImport: UiImportHead T_AS JsIdentifier T_SEMICOLON ;
+/.
+case $rule_number: {
+ sym(1).UiImport->asToken = loc(2);
+ sym(1).UiImport->importIdToken = loc(3);
+ sym(1).UiImport->importId = stringRef(3);
+ sym(1).UiImport->semicolonToken = loc(4);
+} break;
+./
+
+
+UiImportHead: T_IMPORT ImportId ;
+/.
+case $rule_number: {
+ AST::UiImport *node = 0;
+
+ if (AST::StringLiteral *importIdLiteral = AST::cast<AST::StringLiteral *>(sym(2).Expression)) {
+ node = new (pool) AST::UiImport(importIdLiteral->value);
+ node->fileNameToken = loc(2);
+ } else if (AST::UiQualifiedId *qualifiedId = reparseAsQualifiedId(sym(2).Expression)) {
+ node = new (pool) AST::UiImport(qualifiedId);
+ node->fileNameToken = loc(2);
+ }
+
+ sym(1).Node = node;
+
+ if (node) {
+ node->importToken = loc(1);
+ } else {
+ diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, loc(1),
+ QLatin1String("Expected a qualified name id or a string literal")));
+
+ return false; // ### remove me
+ }
+} break;
+./
+
+Empty: ;
+/.
+case $rule_number: {
+ sym(1).Node = 0;
+} break;
+./
+
+UiRootMember: UiObjectDefinition ;
+/.
+case $rule_number: {
+ sym(1).Node = new (pool) AST::UiObjectMemberList(sym(1).UiObjectMember);
+} break;
+./
+
+UiObjectMemberList: UiObjectMember ;
+/.
+case $rule_number: {
+ sym(1).Node = new (pool) AST::UiObjectMemberList(sym(1).UiObjectMember);
+} break;
+./
+
+UiObjectMemberList: UiObjectMemberList UiObjectMember ;
+/.
+case $rule_number: {
+ AST::UiObjectMemberList *node = new (pool) AST:: UiObjectMemberList(
+ sym(1).UiObjectMemberList, sym(2).UiObjectMember);
+ sym(1).Node = node;
+} break;
+./
+
+UiArrayMemberList: UiObjectDefinition ;
+/.
+case $rule_number: {
+ sym(1).Node = new (pool) AST::UiArrayMemberList(sym(1).UiObjectMember);
+} break;
+./
+
+UiArrayMemberList: UiArrayMemberList T_COMMA UiObjectDefinition ;
+/.
+case $rule_number: {
+ AST::UiArrayMemberList *node = new (pool) AST::UiArrayMemberList(
+ sym(1).UiArrayMemberList, sym(3).UiObjectMember);
+ node->commaToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+UiObjectInitializer: T_LBRACE T_RBRACE ;
+/.
+case $rule_number: {
+ AST::UiObjectInitializer *node = new (pool) AST::UiObjectInitializer((AST::UiObjectMemberList*)0);
+ node->lbraceToken = loc(1);
+ node->rbraceToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+UiObjectInitializer: T_LBRACE UiObjectMemberList T_RBRACE ;
+/.
+case $rule_number: {
+ AST::UiObjectInitializer *node = new (pool) AST::UiObjectInitializer(sym(2).UiObjectMemberList->finish());
+ node->lbraceToken = loc(1);
+ node->rbraceToken = loc(3);
+ sym(1).Node = node;
+} break;
+./
+
+UiObjectDefinition: UiQualifiedId UiObjectInitializer ;
+/.
+case $rule_number: {
+ AST::UiObjectDefinition *node = new (pool) AST::UiObjectDefinition(sym(1).UiQualifiedId,
+ sym(2).UiObjectInitializer);
+ sym(1).Node = node;
+} break;
+./
+
+UiObjectMember: UiObjectDefinition ;
+
+UiObjectMember: UiQualifiedId T_COLON T_LBRACKET UiArrayMemberList T_RBRACKET ;
+/.
+case $rule_number: {
+ AST::UiArrayBinding *node = new (pool) AST::UiArrayBinding(
+ sym(1).UiQualifiedId, sym(4).UiArrayMemberList->finish());
+ node->colonToken = loc(2);
+ node->lbracketToken = loc(3);
+ node->rbracketToken = loc(5);
+ sym(1).Node = node;
+} break;
+./
+
+UiObjectMember: UiQualifiedId T_COLON UiQualifiedId UiObjectInitializer ;
+/.
+case $rule_number: {
+ AST::UiObjectBinding *node = new (pool) AST::UiObjectBinding(
+ sym(1).UiQualifiedId, sym(3).UiQualifiedId, sym(4).UiObjectInitializer);
+ node->colonToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+UiObjectMember: UiQualifiedId T_ON UiQualifiedId UiObjectInitializer ;
+/.
+case $rule_number: {
+ AST::UiObjectBinding *node = new (pool) AST::UiObjectBinding(
+ sym(3).UiQualifiedId, sym(1).UiQualifiedId, sym(4).UiObjectInitializer);
+ node->colonToken = loc(2);
+ node->hasOnToken = true;
+ sym(1).Node = node;
+} break;
+./
+
+UiScriptStatement: Block ;
+UiScriptStatement: EmptyStatement ;
+UiScriptStatement: ExpressionStatement ;
+UiScriptStatement: IfStatement ;
+UiScriptStatement: WithStatement ;
+UiScriptStatement: SwitchStatement ;
+UiScriptStatement: TryStatement ;
+
+UiObjectMember: UiQualifiedId T_COLON UiScriptStatement ;
+/.
+case $rule_number:
+{
+ AST::UiScriptBinding *node = new (pool) AST::UiScriptBinding(
+ sym(1).UiQualifiedId, sym(3).Statement);
+ node->colonToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+UiPropertyType: T_VAR ;
+UiPropertyType: T_RESERVED_WORD ;
+UiPropertyType: T_IDENTIFIER ;
+
+UiParameterListOpt: ;
+/.
+case $rule_number: {
+ sym(1).Node = 0;
+} break;
+./
+
+UiParameterListOpt: UiParameterList ;
+/.
+case $rule_number: {
+ sym(1).Node = sym(1).UiParameterList->finish ();
+} break;
+./
+
+UiParameterList: UiPropertyType JsIdentifier ;
+/.
+case $rule_number: {
+ AST::UiParameterList *node = new (pool) AST::UiParameterList(stringRef(1), stringRef(2));
+ node->propertyTypeToken = loc(1);
+ node->identifierToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+UiParameterList: UiParameterList T_COMMA UiPropertyType JsIdentifier ;
+/.
+case $rule_number: {
+ AST::UiParameterList *node = new (pool) AST::UiParameterList(sym(1).UiParameterList, stringRef(3), stringRef(4));
+ node->commaToken = loc(2);
+ node->identifierToken = loc(4);
+ sym(1).Node = node;
+} break;
+./
+
+UiObjectMember: T_SIGNAL T_IDENTIFIER T_LPAREN UiParameterListOpt T_RPAREN T_AUTOMATIC_SEMICOLON ;
+UiObjectMember: T_SIGNAL T_IDENTIFIER T_LPAREN UiParameterListOpt T_RPAREN T_SEMICOLON ;
+/.
+case $rule_number: {
+ AST::UiPublicMember *node = new (pool) AST::UiPublicMember(QStringRef(), stringRef(2));
+ node->type = AST::UiPublicMember::Signal;
+ node->propertyToken = loc(1);
+ node->typeToken = loc(2);
+ node->identifierToken = loc(2);
+ node->parameters = sym(4).UiParameterList;
+ node->semicolonToken = loc(6);
+ sym(1).Node = node;
+} break;
+./
+
+UiObjectMember: T_SIGNAL T_IDENTIFIER T_AUTOMATIC_SEMICOLON ;
+UiObjectMember: T_SIGNAL T_IDENTIFIER T_SEMICOLON ;
+/.
+case $rule_number: {
+ AST::UiPublicMember *node = new (pool) AST::UiPublicMember(QStringRef(), stringRef(2));
+ node->type = AST::UiPublicMember::Signal;
+ node->propertyToken = loc(1);
+ node->typeToken = loc(2);
+ node->identifierToken = loc(2);
+ node->semicolonToken = loc(3);
+ sym(1).Node = node;
+} break;
+./
+
+UiObjectMember: T_PROPERTY T_IDENTIFIER T_LT UiPropertyType T_GT JsIdentifier T_AUTOMATIC_SEMICOLON ;
+UiObjectMember: T_PROPERTY T_IDENTIFIER T_LT UiPropertyType T_GT JsIdentifier T_SEMICOLON ;
+/.
+case $rule_number: {
+ AST::UiPublicMember *node = new (pool) AST::UiPublicMember(stringRef(4), stringRef(6));
+ node->typeModifier = stringRef(2);
+ node->propertyToken = loc(1);
+ node->typeModifierToken = loc(2);
+ node->typeToken = loc(4);
+ node->identifierToken = loc(6);
+ node->semicolonToken = loc(7);
+ sym(1).Node = node;
+} break;
+./
+
+UiObjectMember: T_PROPERTY UiPropertyType JsIdentifier T_AUTOMATIC_SEMICOLON ;
+UiObjectMember: T_PROPERTY UiPropertyType JsIdentifier T_SEMICOLON ;
+/.
+case $rule_number: {
+ AST::UiPublicMember *node = new (pool) AST::UiPublicMember(stringRef(2), stringRef(3));
+ node->propertyToken = loc(1);
+ node->typeToken = loc(2);
+ node->identifierToken = loc(3);
+ node->semicolonToken = loc(4);
+ sym(1).Node = node;
+} break;
+./
+
+UiObjectMember: T_DEFAULT T_PROPERTY UiPropertyType JsIdentifier T_AUTOMATIC_SEMICOLON ;
+UiObjectMember: T_DEFAULT T_PROPERTY UiPropertyType JsIdentifier T_SEMICOLON ;
+/.
+case $rule_number: {
+ AST::UiPublicMember *node = new (pool) AST::UiPublicMember(stringRef(3), stringRef(4));
+ node->isDefaultMember = true;
+ node->defaultToken = loc(1);
+ node->propertyToken = loc(2);
+ node->typeToken = loc(3);
+ node->identifierToken = loc(4);
+ node->semicolonToken = loc(5);
+ sym(1).Node = node;
+} break;
+./
+
+UiObjectMember: T_PROPERTY UiPropertyType JsIdentifier T_COLON UiScriptStatement ;
+/.
+case $rule_number: {
+ AST::UiPublicMember *node = new (pool) AST::UiPublicMember(stringRef(2), stringRef(3),
+ sym(5).Statement);
+ node->propertyToken = loc(1);
+ node->typeToken = loc(2);
+ node->identifierToken = loc(3);
+ node->colonToken = loc(4);
+ sym(1).Node = node;
+} break;
+./
+
+UiObjectMember: T_READONLY T_PROPERTY UiPropertyType JsIdentifier T_COLON UiScriptStatement ;
+/.
+case $rule_number: {
+ AST::UiPublicMember *node = new (pool) AST::UiPublicMember(stringRef(3), stringRef(4),
+ sym(6).Statement);
+ node->isReadonlyMember = true;
+ node->readonlyToken = loc(1);
+ node->propertyToken = loc(2);
+ node->typeToken = loc(3);
+ node->identifierToken = loc(4);
+ node->colonToken = loc(5);
+ sym(1).Node = node;
+} break;
+./
+
+UiObjectMember: T_DEFAULT T_PROPERTY UiPropertyType JsIdentifier T_COLON UiScriptStatement ;
+/.
+case $rule_number: {
+ AST::UiPublicMember *node = new (pool) AST::UiPublicMember(stringRef(3), stringRef(4),
+ sym(6).Statement);
+ node->isDefaultMember = true;
+ node->defaultToken = loc(1);
+ node->propertyToken = loc(2);
+ node->typeToken = loc(3);
+ node->identifierToken = loc(4);
+ node->colonToken = loc(5);
+ sym(1).Node = node;
+} break;
+./
+
+UiObjectMember: T_PROPERTY T_IDENTIFIER T_LT UiPropertyType T_GT JsIdentifier T_COLON T_LBRACKET UiArrayMemberList T_RBRACKET ;
+/.
+case $rule_number: {
+ AST::UiPublicMember *node = new (pool) AST::UiPublicMember(stringRef(4), stringRef(6));
+ node->typeModifier = stringRef(2);
+ node->propertyToken = loc(1);
+ node->typeModifierToken = loc(2);
+ node->typeToken = loc(4);
+ node->identifierToken = loc(6);
+ node->semicolonToken = loc(7); // insert a fake ';' before ':'
+
+ AST::UiQualifiedId *propertyName = new (pool) AST::UiQualifiedId(stringRef(6));
+ propertyName->identifierToken = loc(6);
+ propertyName->next = 0;
+
+ AST::UiArrayBinding *binding = new (pool) AST::UiArrayBinding(
+ propertyName, sym(9).UiArrayMemberList->finish());
+ binding->colonToken = loc(7);
+ binding->lbracketToken = loc(8);
+ binding->rbracketToken = loc(10);
+
+ node->binding = binding;
+
+ sym(1).Node = node;
+} break;
+./
+
+UiObjectMember: T_PROPERTY UiPropertyType JsIdentifier T_COLON UiQualifiedId UiObjectInitializer ;
+/.
+case $rule_number: {
+ AST::UiPublicMember *node = new (pool) AST::UiPublicMember(stringRef(2), stringRef(3));
+ node->propertyToken = loc(1);
+ node->typeToken = loc(2);
+ node->identifierToken = loc(3);
+ node->semicolonToken = loc(4); // insert a fake ';' before ':'
+
+ AST::UiQualifiedId *propertyName = new (pool) AST::UiQualifiedId(stringRef(3));
+ propertyName->identifierToken = loc(3);
+ propertyName->next = 0;
+
+ AST::UiObjectBinding *binding = new (pool) AST::UiObjectBinding(
+ propertyName, sym(5).UiQualifiedId, sym(6).UiObjectInitializer);
+ binding->colonToken = loc(4);
+
+ node->binding = binding;
+
+ sym(1).Node = node;
+} break;
+./
+
+UiObjectMember: FunctionDeclaration ;
+/.
+case $rule_number: {
+ sym(1).Node = new (pool) AST::UiSourceElement(sym(1).Node);
+} break;
+./
+
+UiObjectMember: VariableStatement ;
+/.
+case $rule_number: {
+ sym(1).Node = new (pool) AST::UiSourceElement(sym(1).Node);
+} break;
+./
+
+JsIdentifier: T_IDENTIFIER;
+
+JsIdentifier: T_PROPERTY ;
+JsIdentifier: T_SIGNAL ;
+JsIdentifier: T_READONLY ;
+JsIdentifier: T_ON ;
+
+--------------------------------------------------------------------------------------------------------
+-- Expressions
+--------------------------------------------------------------------------------------------------------
+
+PrimaryExpression: T_THIS ;
+/.
+case $rule_number: {
+ AST::ThisExpression *node = new (pool) AST::ThisExpression();
+ node->thisToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+PrimaryExpression: JsIdentifier ;
+/.
+case $rule_number: {
+ AST::IdentifierExpression *node = new (pool) AST::IdentifierExpression(stringRef(1));
+ node->identifierToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+PrimaryExpression: T_NULL ;
+/.
+case $rule_number: {
+ AST::NullExpression *node = new (pool) AST::NullExpression();
+ node->nullToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+PrimaryExpression: T_TRUE ;
+/.
+case $rule_number: {
+ AST::TrueLiteral *node = new (pool) AST::TrueLiteral();
+ node->trueToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+PrimaryExpression: T_FALSE ;
+/.
+case $rule_number: {
+ AST::FalseLiteral *node = new (pool) AST::FalseLiteral();
+ node->falseToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+PrimaryExpression: T_NUMERIC_LITERAL ;
+/.
+case $rule_number: {
+ AST::NumericLiteral *node = new (pool) AST::NumericLiteral(sym(1).dval);
+ node->literalToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+PrimaryExpression: T_MULTILINE_STRING_LITERAL ;
+/.case $rule_number:./
+
+PrimaryExpression: T_STRING_LITERAL ;
+/.
+case $rule_number: {
+ AST::StringLiteral *node = new (pool) AST::StringLiteral(stringRef(1));
+ node->literalToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+PrimaryExpression: T_DIVIDE_ ;
+/:
+#define J_SCRIPT_REGEXPLITERAL_RULE1 $rule_number
+:/
+/.
+case $rule_number: {
+ bool rx = lexer->scanRegExp(Lexer::NoPrefix);
+ if (!rx) {
+ diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, location(lexer), lexer->errorMessage()));
+ return false; // ### remove me
+ }
+
+ loc(1).length = lexer->tokenLength();
+ yylloc = loc(1); // adjust the location of the current token
+
+ AST::RegExpLiteral *node = new (pool) AST::RegExpLiteral(
+ driver->newStringRef(lexer->regExpPattern()), lexer->regExpFlags());
+ node->literalToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+PrimaryExpression: T_DIVIDE_EQ ;
+/:
+#define J_SCRIPT_REGEXPLITERAL_RULE2 $rule_number
+:/
+/.
+case $rule_number: {
+ bool rx = lexer->scanRegExp(Lexer::EqualPrefix);
+ if (!rx) {
+ diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, location(lexer), lexer->errorMessage()));
+ return false;
+ }
+
+ loc(1).length = lexer->tokenLength();
+ yylloc = loc(1); // adjust the location of the current token
+
+ AST::RegExpLiteral *node = new (pool) AST::RegExpLiteral(
+ driver->newStringRef(lexer->regExpPattern()), lexer->regExpFlags());
+ node->literalToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+PrimaryExpression: T_LBRACKET T_RBRACKET ;
+/.
+case $rule_number: {
+ AST::ArrayLiteral *node = new (pool) AST::ArrayLiteral((AST::Elision *) 0);
+ node->lbracketToken = loc(1);
+ node->rbracketToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+PrimaryExpression: T_LBRACKET Elision T_RBRACKET ;
+/.
+case $rule_number: {
+ AST::ArrayLiteral *node = new (pool) AST::ArrayLiteral(sym(2).Elision->finish());
+ node->lbracketToken = loc(1);
+ node->rbracketToken = loc(3);
+ sym(1).Node = node;
+} break;
+./
+
+PrimaryExpression: T_LBRACKET ElementList T_RBRACKET ;
+/.
+case $rule_number: {
+ AST::ArrayLiteral *node = new (pool) AST::ArrayLiteral(sym(2).ElementList->finish ());
+ node->lbracketToken = loc(1);
+ node->rbracketToken = loc(3);
+ sym(1).Node = node;
+} break;
+./
+
+PrimaryExpression: T_LBRACKET ElementList T_COMMA T_RBRACKET ;
+/.
+case $rule_number: {
+ AST::ArrayLiteral *node = new (pool) AST::ArrayLiteral(sym(2).ElementList->finish (),
+ (AST::Elision *) 0);
+ node->lbracketToken = loc(1);
+ node->commaToken = loc(3);
+ node->rbracketToken = loc(4);
+ sym(1).Node = node;
+} break;
+./
+
+PrimaryExpression: T_LBRACKET ElementList T_COMMA Elision T_RBRACKET ;
+/.
+case $rule_number: {
+ AST::ArrayLiteral *node = new (pool) AST::ArrayLiteral(sym(2).ElementList->finish (),
+ sym(4).Elision->finish());
+ node->lbracketToken = loc(1);
+ node->commaToken = loc(3);
+ node->rbracketToken = loc(5);
+ sym(1).Node = node;
+} break;
+./
+
+-- PrimaryExpression: T_LBRACE T_RBRACE ;
+-- /.
+-- case $rule_number: {
+-- sym(1).Node = new (pool) AST::ObjectLiteral();
+-- } break;
+-- ./
+
+PrimaryExpression: T_LBRACE PropertyNameAndValueListOpt T_RBRACE ;
+/.
+case $rule_number: {
+ AST::ObjectLiteral *node = 0;
+ if (sym(2).Node)
+ node = new (pool) AST::ObjectLiteral(
+ sym(2).PropertyNameAndValueList->finish ());
+ else
+ node = new (pool) AST::ObjectLiteral();
+ node->lbraceToken = loc(1);
+ node->rbraceToken = loc(3);
+ sym(1).Node = node;
+} break;
+./
+
+PrimaryExpression: T_LBRACE PropertyNameAndValueList T_COMMA T_RBRACE ;
+/.
+case $rule_number: {
+ AST::ObjectLiteral *node = new (pool) AST::ObjectLiteral(
+ sym(2).PropertyNameAndValueList->finish ());
+ node->lbraceToken = loc(1);
+ node->rbraceToken = loc(4);
+ sym(1).Node = node;
+} break;
+./
+
+PrimaryExpression: T_LPAREN Expression T_RPAREN ;
+/.
+case $rule_number: {
+ AST::NestedExpression *node = new (pool) AST::NestedExpression(sym(2).Expression);
+ node->lparenToken = loc(1);
+ node->rparenToken = loc(3);
+ sym(1).Node = node;
+} break;
+./
+
+UiQualifiedId: MemberExpression ;
+/.
+case $rule_number: {
+ if (AST::ArrayMemberExpression *mem = AST::cast<AST::ArrayMemberExpression *>(sym(1).Expression)) {
+ diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Warning, mem->lbracketToken,
+ QLatin1String("Ignored annotation")));
+
+ sym(1).Expression = mem->base;
+ }
+
+ if (AST::UiQualifiedId *qualifiedId = reparseAsQualifiedId(sym(1).Expression)) {
+ sym(1).UiQualifiedId = qualifiedId;
+ } else {
+ sym(1).UiQualifiedId = 0;
+
+ diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, loc(1),
+ QLatin1String("Expected a qualified name id")));
+
+ return false; // ### recover
+ }
+} break;
+./
+
+ElementList: AssignmentExpression ;
+/.
+case $rule_number: {
+ sym(1).Node = new (pool) AST::ElementList((AST::Elision *) 0, sym(1).Expression);
+} break;
+./
+
+ElementList: Elision AssignmentExpression ;
+/.
+case $rule_number: {
+ sym(1).Node = new (pool) AST::ElementList(sym(1).Elision->finish(), sym(2).Expression);
+} break;
+./
+
+ElementList: ElementList T_COMMA AssignmentExpression ;
+/.
+case $rule_number: {
+ AST::ElementList *node = new (pool) AST::ElementList(sym(1).ElementList,
+ (AST::Elision *) 0, sym(3).Expression);
+ node->commaToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+ElementList: ElementList T_COMMA Elision AssignmentExpression ;
+/.
+case $rule_number: {
+ AST::ElementList *node = new (pool) AST::ElementList(sym(1).ElementList, sym(3).Elision->finish(),
+ sym(4).Expression);
+ node->commaToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+Elision: T_COMMA ;
+/.
+case $rule_number: {
+ AST::Elision *node = new (pool) AST::Elision();
+ node->commaToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+Elision: Elision T_COMMA ;
+/.
+case $rule_number: {
+ AST::Elision *node = new (pool) AST::Elision(sym(1).Elision);
+ node->commaToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+PropertyNameAndValueList: PropertyName T_COLON AssignmentExpression ;
+/.
+case $rule_number: {
+ AST::PropertyNameAndValueList *node = new (pool) AST::PropertyNameAndValueList(
+ sym(1).PropertyName, sym(3).Expression);
+ node->colonToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+PropertyNameAndValueList: PropertyNameAndValueList T_COMMA PropertyName T_COLON AssignmentExpression ;
+/.
+case $rule_number: {
+ AST::PropertyNameAndValueList *node = new (pool) AST::PropertyNameAndValueList(
+ sym(1).PropertyNameAndValueList, sym(3).PropertyName, sym(5).Expression);
+ node->commaToken = loc(2);
+ node->colonToken = loc(4);
+ sym(1).Node = node;
+} break;
+./
+
+PropertyName: T_IDENTIFIER %prec SHIFT_THERE ;
+/.
+case $rule_number: {
+ AST::IdentifierPropertyName *node = new (pool) AST::IdentifierPropertyName(stringRef(1));
+ node->propertyNameToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+PropertyName: T_SIGNAL ;
+/.case $rule_number:./
+
+PropertyName: T_PROPERTY ;
+/.
+case $rule_number: {
+ AST::IdentifierPropertyName *node = new (pool) AST::IdentifierPropertyName(stringRef(1));
+ node->propertyNameToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+PropertyName: T_STRING_LITERAL ;
+/.
+case $rule_number: {
+ AST::StringLiteralPropertyName *node = new (pool) AST::StringLiteralPropertyName(stringRef(1));
+ node->propertyNameToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+PropertyName: T_NUMERIC_LITERAL ;
+/.
+case $rule_number: {
+ AST::NumericLiteralPropertyName *node = new (pool) AST::NumericLiteralPropertyName(sym(1).dval);
+ node->propertyNameToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+PropertyName: ReservedIdentifier ;
+/.
+case $rule_number: {
+ AST::IdentifierPropertyName *node = new (pool) AST::IdentifierPropertyName(stringRef(1));
+ node->propertyNameToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+ReservedIdentifier: T_BREAK ;
+ReservedIdentifier: T_CASE ;
+ReservedIdentifier: T_CATCH ;
+ReservedIdentifier: T_CONTINUE ;
+ReservedIdentifier: T_DEFAULT ;
+ReservedIdentifier: T_DELETE ;
+ReservedIdentifier: T_DO ;
+ReservedIdentifier: T_ELSE ;
+ReservedIdentifier: T_FALSE ;
+ReservedIdentifier: T_FINALLY ;
+ReservedIdentifier: T_FOR ;
+ReservedIdentifier: T_FUNCTION ;
+ReservedIdentifier: T_IF ;
+ReservedIdentifier: T_IN ;
+ReservedIdentifier: T_INSTANCEOF ;
+ReservedIdentifier: T_NEW ;
+ReservedIdentifier: T_NULL ;
+ReservedIdentifier: T_RETURN ;
+ReservedIdentifier: T_SWITCH ;
+ReservedIdentifier: T_THIS ;
+ReservedIdentifier: T_THROW ;
+ReservedIdentifier: T_TRUE ;
+ReservedIdentifier: T_TRY ;
+ReservedIdentifier: T_TYPEOF ;
+ReservedIdentifier: T_VAR ;
+ReservedIdentifier: T_VOID ;
+ReservedIdentifier: T_WHILE ;
+ReservedIdentifier: T_CONST ;
+ReservedIdentifier: T_DEBUGGER ;
+ReservedIdentifier: T_RESERVED_WORD ;
+ReservedIdentifier: T_WITH ;
+
+PropertyIdentifier: JsIdentifier ;
+PropertyIdentifier: ReservedIdentifier ;
+
+MemberExpression: PrimaryExpression ;
+MemberExpression: FunctionExpression ;
+
+MemberExpression: MemberExpression T_LBRACKET Expression T_RBRACKET ;
+/.
+case $rule_number: {
+ AST::ArrayMemberExpression *node = new (pool) AST::ArrayMemberExpression(sym(1).Expression, sym(3).Expression);
+ node->lbracketToken = loc(2);
+ node->rbracketToken = loc(4);
+ sym(1).Node = node;
+} break;
+./
+
+MemberExpression: MemberExpression T_DOT PropertyIdentifier ;
+/.
+case $rule_number: {
+ AST::FieldMemberExpression *node = new (pool) AST::FieldMemberExpression(sym(1).Expression, stringRef(3));
+ node->dotToken = loc(2);
+ node->identifierToken = loc(3);
+ sym(1).Node = node;
+} break;
+./
+
+MemberExpression: T_NEW MemberExpression T_LPAREN ArgumentListOpt T_RPAREN ;
+/.
+case $rule_number: {
+ AST::NewMemberExpression *node = new (pool) AST::NewMemberExpression(sym(2).Expression, sym(4).ArgumentList);
+ node->newToken = loc(1);
+ node->lparenToken = loc(3);
+ node->rparenToken = loc(5);
+ sym(1).Node = node;
+} break;
+./
+
+NewExpression: MemberExpression ;
+
+NewExpression: T_NEW NewExpression ;
+/.
+case $rule_number: {
+ AST::NewExpression *node = new (pool) AST::NewExpression(sym(2).Expression);
+ node->newToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+CallExpression: MemberExpression T_LPAREN ArgumentListOpt T_RPAREN ;
+/.
+case $rule_number: {
+ AST::CallExpression *node = new (pool) AST::CallExpression(sym(1).Expression, sym(3).ArgumentList);
+ node->lparenToken = loc(2);
+ node->rparenToken = loc(4);
+ sym(1).Node = node;
+} break;
+./
+
+CallExpression: CallExpression T_LPAREN ArgumentListOpt T_RPAREN ;
+/.
+case $rule_number: {
+ AST::CallExpression *node = new (pool) AST::CallExpression(sym(1).Expression, sym(3).ArgumentList);
+ node->lparenToken = loc(2);
+ node->rparenToken = loc(4);
+ sym(1).Node = node;
+} break;
+./
+
+CallExpression: CallExpression T_LBRACKET Expression T_RBRACKET ;
+/.
+case $rule_number: {
+ AST::ArrayMemberExpression *node = new (pool) AST::ArrayMemberExpression(sym(1).Expression, sym(3).Expression);
+ node->lbracketToken = loc(2);
+ node->rbracketToken = loc(4);
+ sym(1).Node = node;
+} break;
+./
+
+CallExpression: CallExpression T_DOT PropertyIdentifier ;
+/.
+case $rule_number: {
+ AST::FieldMemberExpression *node = new (pool) AST::FieldMemberExpression(sym(1).Expression, stringRef(3));
+ node->dotToken = loc(2);
+ node->identifierToken = loc(3);
+ sym(1).Node = node;
+} break;
+./
+
+ArgumentListOpt: ;
+/.
+case $rule_number: {
+ sym(1).Node = 0;
+} break;
+./
+
+ArgumentListOpt: ArgumentList ;
+/.
+case $rule_number: {
+ sym(1).Node = sym(1).ArgumentList->finish();
+} break;
+./
+
+ArgumentList: AssignmentExpression ;
+/.
+case $rule_number: {
+ sym(1).Node = new (pool) AST::ArgumentList(sym(1).Expression);
+} break;
+./
+
+ArgumentList: ArgumentList T_COMMA AssignmentExpression ;
+/.
+case $rule_number: {
+ AST::ArgumentList *node = new (pool) AST::ArgumentList(sym(1).ArgumentList, sym(3).Expression);
+ node->commaToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+LeftHandSideExpression: NewExpression ;
+LeftHandSideExpression: CallExpression ;
+PostfixExpression: LeftHandSideExpression ;
+
+PostfixExpression: LeftHandSideExpression T_PLUS_PLUS ;
+/.
+case $rule_number: {
+ AST::PostIncrementExpression *node = new (pool) AST::PostIncrementExpression(sym(1).Expression);
+ node->incrementToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+PostfixExpression: LeftHandSideExpression T_MINUS_MINUS ;
+/.
+case $rule_number: {
+ AST::PostDecrementExpression *node = new (pool) AST::PostDecrementExpression(sym(1).Expression);
+ node->decrementToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+UnaryExpression: PostfixExpression ;
+
+UnaryExpression: T_DELETE UnaryExpression ;
+/.
+case $rule_number: {
+ AST::DeleteExpression *node = new (pool) AST::DeleteExpression(sym(2).Expression);
+ node->deleteToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+UnaryExpression: T_VOID UnaryExpression ;
+/.
+case $rule_number: {
+ AST::VoidExpression *node = new (pool) AST::VoidExpression(sym(2).Expression);
+ node->voidToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+UnaryExpression: T_TYPEOF UnaryExpression ;
+/.
+case $rule_number: {
+ AST::TypeOfExpression *node = new (pool) AST::TypeOfExpression(sym(2).Expression);
+ node->typeofToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+UnaryExpression: T_PLUS_PLUS UnaryExpression ;
+/.
+case $rule_number: {
+ AST::PreIncrementExpression *node = new (pool) AST::PreIncrementExpression(sym(2).Expression);
+ node->incrementToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+UnaryExpression: T_MINUS_MINUS UnaryExpression ;
+/.
+case $rule_number: {
+ AST::PreDecrementExpression *node = new (pool) AST::PreDecrementExpression(sym(2).Expression);
+ node->decrementToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+UnaryExpression: T_PLUS UnaryExpression ;
+/.
+case $rule_number: {
+ AST::UnaryPlusExpression *node = new (pool) AST::UnaryPlusExpression(sym(2).Expression);
+ node->plusToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+UnaryExpression: T_MINUS UnaryExpression ;
+/.
+case $rule_number: {
+ AST::UnaryMinusExpression *node = new (pool) AST::UnaryMinusExpression(sym(2).Expression);
+ node->minusToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+UnaryExpression: T_TILDE UnaryExpression ;
+/.
+case $rule_number: {
+ AST::TildeExpression *node = new (pool) AST::TildeExpression(sym(2).Expression);
+ node->tildeToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+UnaryExpression: T_NOT UnaryExpression ;
+/.
+case $rule_number: {
+ AST::NotExpression *node = new (pool) AST::NotExpression(sym(2).Expression);
+ node->notToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+MultiplicativeExpression: UnaryExpression ;
+
+MultiplicativeExpression: MultiplicativeExpression T_STAR UnaryExpression ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::Mul, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+MultiplicativeExpression: MultiplicativeExpression T_DIVIDE_ UnaryExpression ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::Div, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+MultiplicativeExpression: MultiplicativeExpression T_REMAINDER UnaryExpression ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::Mod, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+AdditiveExpression: MultiplicativeExpression ;
+
+AdditiveExpression: AdditiveExpression T_PLUS MultiplicativeExpression ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::Add, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+AdditiveExpression: AdditiveExpression T_MINUS MultiplicativeExpression ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::Sub, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+ShiftExpression: AdditiveExpression ;
+
+ShiftExpression: ShiftExpression T_LT_LT AdditiveExpression ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::LShift, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+ShiftExpression: ShiftExpression T_GT_GT AdditiveExpression ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::RShift, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+ShiftExpression: ShiftExpression T_GT_GT_GT AdditiveExpression ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::URShift, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+RelationalExpression: ShiftExpression ;
+
+RelationalExpression: RelationalExpression T_LT ShiftExpression ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::Lt, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+RelationalExpression: RelationalExpression T_GT ShiftExpression ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::Gt, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+RelationalExpression: RelationalExpression T_LE ShiftExpression ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::Le, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+RelationalExpression: RelationalExpression T_GE ShiftExpression ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::Ge, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+RelationalExpression: RelationalExpression T_INSTANCEOF ShiftExpression ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::InstanceOf, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+RelationalExpression: RelationalExpression T_IN ShiftExpression ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::In, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+RelationalExpressionNotIn: ShiftExpression ;
+
+RelationalExpressionNotIn: RelationalExpressionNotIn T_LT ShiftExpression ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::Lt, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+RelationalExpressionNotIn: RelationalExpressionNotIn T_GT ShiftExpression ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::Gt, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+RelationalExpressionNotIn: RelationalExpressionNotIn T_LE ShiftExpression ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::Le, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+RelationalExpressionNotIn: RelationalExpressionNotIn T_GE ShiftExpression ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::Ge, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+RelationalExpressionNotIn: RelationalExpressionNotIn T_INSTANCEOF ShiftExpression ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::InstanceOf, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+EqualityExpression: RelationalExpression ;
+
+EqualityExpression: EqualityExpression T_EQ_EQ RelationalExpression ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::Equal, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+EqualityExpression: EqualityExpression T_NOT_EQ RelationalExpression ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::NotEqual, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+EqualityExpression: EqualityExpression T_EQ_EQ_EQ RelationalExpression ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::StrictEqual, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+EqualityExpression: EqualityExpression T_NOT_EQ_EQ RelationalExpression ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::StrictNotEqual, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+EqualityExpressionNotIn: RelationalExpressionNotIn ;
+
+EqualityExpressionNotIn: EqualityExpressionNotIn T_EQ_EQ RelationalExpressionNotIn ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::Equal, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+EqualityExpressionNotIn: EqualityExpressionNotIn T_NOT_EQ RelationalExpressionNotIn;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::NotEqual, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+EqualityExpressionNotIn: EqualityExpressionNotIn T_EQ_EQ_EQ RelationalExpressionNotIn ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::StrictEqual, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+EqualityExpressionNotIn: EqualityExpressionNotIn T_NOT_EQ_EQ RelationalExpressionNotIn ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::StrictNotEqual, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+BitwiseANDExpression: EqualityExpression ;
+
+BitwiseANDExpression: BitwiseANDExpression T_AND EqualityExpression ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::BitAnd, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+BitwiseANDExpressionNotIn: EqualityExpressionNotIn ;
+
+BitwiseANDExpressionNotIn: BitwiseANDExpressionNotIn T_AND EqualityExpressionNotIn ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::BitAnd, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+BitwiseXORExpression: BitwiseANDExpression ;
+
+BitwiseXORExpression: BitwiseXORExpression T_XOR BitwiseANDExpression ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::BitXor, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+BitwiseXORExpressionNotIn: BitwiseANDExpressionNotIn ;
+
+BitwiseXORExpressionNotIn: BitwiseXORExpressionNotIn T_XOR BitwiseANDExpressionNotIn ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::BitXor, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+BitwiseORExpression: BitwiseXORExpression ;
+
+BitwiseORExpression: BitwiseORExpression T_OR BitwiseXORExpression ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::BitOr, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+BitwiseORExpressionNotIn: BitwiseXORExpressionNotIn ;
+
+BitwiseORExpressionNotIn: BitwiseORExpressionNotIn T_OR BitwiseXORExpressionNotIn ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::BitOr, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+LogicalANDExpression: BitwiseORExpression ;
+
+LogicalANDExpression: LogicalANDExpression T_AND_AND BitwiseORExpression ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::And, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+LogicalANDExpressionNotIn: BitwiseORExpressionNotIn ;
+
+LogicalANDExpressionNotIn: LogicalANDExpressionNotIn T_AND_AND BitwiseORExpressionNotIn ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::And, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+LogicalORExpression: LogicalANDExpression ;
+
+LogicalORExpression: LogicalORExpression T_OR_OR LogicalANDExpression ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::Or, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+LogicalORExpressionNotIn: LogicalANDExpressionNotIn ;
+
+LogicalORExpressionNotIn: LogicalORExpressionNotIn T_OR_OR LogicalANDExpressionNotIn ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::Or, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+ConditionalExpression: LogicalORExpression ;
+
+ConditionalExpression: LogicalORExpression T_QUESTION AssignmentExpression T_COLON AssignmentExpression ;
+/.
+case $rule_number: {
+ AST::ConditionalExpression *node = new (pool) AST::ConditionalExpression(sym(1).Expression,
+ sym(3).Expression, sym(5).Expression);
+ node->questionToken = loc(2);
+ node->colonToken = loc(4);
+ sym(1).Node = node;
+} break;
+./
+
+ConditionalExpressionNotIn: LogicalORExpressionNotIn ;
+
+ConditionalExpressionNotIn: LogicalORExpressionNotIn T_QUESTION AssignmentExpressionNotIn T_COLON AssignmentExpressionNotIn ;
+/.
+case $rule_number: {
+ AST::ConditionalExpression *node = new (pool) AST::ConditionalExpression(sym(1).Expression,
+ sym(3).Expression, sym(5).Expression);
+ node->questionToken = loc(2);
+ node->colonToken = loc(4);
+ sym(1).Node = node;
+} break;
+./
+
+AssignmentExpression: ConditionalExpression ;
+
+AssignmentExpression: LeftHandSideExpression AssignmentOperator AssignmentExpression ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ sym(2).ival, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+AssignmentExpressionNotIn: ConditionalExpressionNotIn ;
+
+AssignmentExpressionNotIn: LeftHandSideExpression AssignmentOperator AssignmentExpressionNotIn ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ sym(2).ival, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+AssignmentOperator: T_EQ ;
+/.
+case $rule_number: {
+ sym(1).ival = QSOperator::Assign;
+} break;
+./
+
+AssignmentOperator: T_STAR_EQ ;
+/.
+case $rule_number: {
+ sym(1).ival = QSOperator::InplaceMul;
+} break;
+./
+
+AssignmentOperator: T_DIVIDE_EQ ;
+/.
+case $rule_number: {
+ sym(1).ival = QSOperator::InplaceDiv;
+} break;
+./
+
+AssignmentOperator: T_REMAINDER_EQ ;
+/.
+case $rule_number: {
+ sym(1).ival = QSOperator::InplaceMod;
+} break;
+./
+
+AssignmentOperator: T_PLUS_EQ ;
+/.
+case $rule_number: {
+ sym(1).ival = QSOperator::InplaceAdd;
+} break;
+./
+
+AssignmentOperator: T_MINUS_EQ ;
+/.
+case $rule_number: {
+ sym(1).ival = QSOperator::InplaceSub;
+} break;
+./
+
+AssignmentOperator: T_LT_LT_EQ ;
+/.
+case $rule_number: {
+ sym(1).ival = QSOperator::InplaceLeftShift;
+} break;
+./
+
+AssignmentOperator: T_GT_GT_EQ ;
+/.
+case $rule_number: {
+ sym(1).ival = QSOperator::InplaceRightShift;
+} break;
+./
+
+AssignmentOperator: T_GT_GT_GT_EQ ;
+/.
+case $rule_number: {
+ sym(1).ival = QSOperator::InplaceURightShift;
+} break;
+./
+
+AssignmentOperator: T_AND_EQ ;
+/.
+case $rule_number: {
+ sym(1).ival = QSOperator::InplaceAnd;
+} break;
+./
+
+AssignmentOperator: T_XOR_EQ ;
+/.
+case $rule_number: {
+ sym(1).ival = QSOperator::InplaceXor;
+} break;
+./
+
+AssignmentOperator: T_OR_EQ ;
+/.
+case $rule_number: {
+ sym(1).ival = QSOperator::InplaceOr;
+} break;
+./
+
+Expression: AssignmentExpression ;
+
+Expression: Expression T_COMMA AssignmentExpression ;
+/.
+case $rule_number: {
+ AST::Expression *node = new (pool) AST::Expression(sym(1).Expression, sym(3).Expression);
+ node->commaToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+ExpressionOpt: ;
+/.
+case $rule_number: {
+ sym(1).Node = 0;
+} break;
+./
+
+ExpressionOpt: Expression ;
+
+ExpressionNotIn: AssignmentExpressionNotIn ;
+
+ExpressionNotIn: ExpressionNotIn T_COMMA AssignmentExpressionNotIn ;
+/.
+case $rule_number: {
+ AST::Expression *node = new (pool) AST::Expression(sym(1).Expression, sym(3).Expression);
+ node->commaToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+ExpressionNotInOpt: ;
+/.
+case $rule_number: {
+ sym(1).Node = 0;
+} break;
+./
+
+ExpressionNotInOpt: ExpressionNotIn ;
+
+Statement: Block ;
+Statement: VariableStatement ;
+Statement: EmptyStatement ;
+Statement: ExpressionStatement ;
+Statement: IfStatement ;
+Statement: IterationStatement ;
+Statement: ContinueStatement ;
+Statement: BreakStatement ;
+Statement: ReturnStatement ;
+Statement: WithStatement ;
+Statement: LabelledStatement ;
+Statement: SwitchStatement ;
+Statement: ThrowStatement ;
+Statement: TryStatement ;
+Statement: DebuggerStatement ;
+
+
+Block: T_LBRACE StatementListOpt T_RBRACE ;
+/.
+case $rule_number: {
+ AST::Block *node = new (pool) AST::Block(sym(2).StatementList);
+ node->lbraceToken = loc(1);
+ node->rbraceToken = loc(3);
+ sym(1).Node = node;
+} break;
+./
+
+StatementList: Statement ;
+/.
+case $rule_number: {
+ sym(1).Node = new (pool) AST::StatementList(sym(1).Statement);
+} break;
+./
+
+StatementList: StatementList Statement ;
+/.
+case $rule_number: {
+ sym(1).Node = new (pool) AST::StatementList(sym(1).StatementList, sym(2).Statement);
+} break;
+./
+
+StatementListOpt: ;
+/.
+case $rule_number: {
+ sym(1).Node = 0;
+} break;
+./
+
+StatementListOpt: StatementList ;
+/.
+case $rule_number: {
+ sym(1).Node = sym(1).StatementList->finish ();
+} break;
+./
+
+VariableStatement: VariableDeclarationKind VariableDeclarationList T_AUTOMATIC_SEMICOLON ; -- automatic semicolon
+VariableStatement: VariableDeclarationKind VariableDeclarationList T_SEMICOLON ;
+/.
+case $rule_number: {
+ AST::VariableStatement *node = new (pool) AST::VariableStatement(
+ sym(2).VariableDeclarationList->finish (/*readOnly=*/sym(1).ival == T_CONST));
+ node->declarationKindToken = loc(1);
+ node->semicolonToken = loc(3);
+ sym(1).Node = node;
+} break;
+./
+
+VariableDeclarationKind: T_CONST ;
+/.
+case $rule_number: {
+ sym(1).ival = T_CONST;
+} break;
+./
+
+VariableDeclarationKind: T_VAR ;
+/.
+case $rule_number: {
+ sym(1).ival = T_VAR;
+} break;
+./
+
+VariableDeclarationList: VariableDeclaration ;
+/.
+case $rule_number: {
+ sym(1).Node = new (pool) AST::VariableDeclarationList(sym(1).VariableDeclaration);
+} break;
+./
+
+VariableDeclarationList: VariableDeclarationList T_COMMA VariableDeclaration ;
+/.
+case $rule_number: {
+ AST::VariableDeclarationList *node = new (pool) AST::VariableDeclarationList(
+ sym(1).VariableDeclarationList, sym(3).VariableDeclaration);
+ node->commaToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+VariableDeclarationListNotIn: VariableDeclarationNotIn ;
+/.
+case $rule_number: {
+ sym(1).Node = new (pool) AST::VariableDeclarationList(sym(1).VariableDeclaration);
+} break;
+./
+
+VariableDeclarationListNotIn: VariableDeclarationListNotIn T_COMMA VariableDeclarationNotIn ;
+/.
+case $rule_number: {
+ sym(1).Node = new (pool) AST::VariableDeclarationList(sym(1).VariableDeclarationList, sym(3).VariableDeclaration);
+} break;
+./
+
+VariableDeclaration: JsIdentifier InitialiserOpt ;
+/.
+case $rule_number: {
+ AST::VariableDeclaration *node = new (pool) AST::VariableDeclaration(stringRef(1), sym(2).Expression);
+ node->identifierToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+VariableDeclarationNotIn: JsIdentifier InitialiserNotInOpt ;
+/.
+case $rule_number: {
+ AST::VariableDeclaration *node = new (pool) AST::VariableDeclaration(stringRef(1), sym(2).Expression);
+ node->identifierToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+Initialiser: T_EQ AssignmentExpression ;
+/.
+case $rule_number: {
+ // ### TODO: AST for initializer
+ sym(1) = sym(2);
+} break;
+./
+
+InitialiserOpt: ;
+/.
+case $rule_number: {
+ sym(1).Node = 0;
+} break;
+./
+
+InitialiserOpt: Initialiser ;
+
+InitialiserNotIn: T_EQ AssignmentExpressionNotIn ;
+/.
+case $rule_number: {
+ // ### TODO: AST for initializer
+ sym(1) = sym(2);
+} break;
+./
+
+InitialiserNotInOpt: ;
+/.
+case $rule_number: {
+ sym(1).Node = 0;
+} break;
+./
+
+InitialiserNotInOpt: InitialiserNotIn ;
+
+EmptyStatement: T_SEMICOLON ;
+/.
+case $rule_number: {
+ AST::EmptyStatement *node = new (pool) AST::EmptyStatement();
+ node->semicolonToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+ExpressionStatement: Expression T_AUTOMATIC_SEMICOLON ; -- automatic semicolon
+ExpressionStatement: Expression T_SEMICOLON ;
+/.
+case $rule_number: {
+ AST::ExpressionStatement *node = new (pool) AST::ExpressionStatement(sym(1).Expression);
+ node->semicolonToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+IfStatement: T_IF T_LPAREN Expression T_RPAREN Statement T_ELSE Statement ;
+/.
+case $rule_number: {
+ AST::IfStatement *node = new (pool) AST::IfStatement(sym(3).Expression, sym(5).Statement, sym(7).Statement);
+ node->ifToken = loc(1);
+ node->lparenToken = loc(2);
+ node->rparenToken = loc(4);
+ node->elseToken = loc(6);
+ sym(1).Node = node;
+} break;
+./
+
+IfStatement: T_IF T_LPAREN Expression T_RPAREN Statement ;
+/.
+case $rule_number: {
+ AST::IfStatement *node = new (pool) AST::IfStatement(sym(3).Expression, sym(5).Statement);
+ node->ifToken = loc(1);
+ node->lparenToken = loc(2);
+ node->rparenToken = loc(4);
+ sym(1).Node = node;
+} break;
+./
+
+
+IterationStatement: T_DO Statement T_WHILE T_LPAREN Expression T_RPAREN T_AUTOMATIC_SEMICOLON ; -- automatic semicolon
+IterationStatement: T_DO Statement T_WHILE T_LPAREN Expression T_RPAREN T_SEMICOLON ;
+/.
+case $rule_number: {
+ AST::DoWhileStatement *node = new (pool) AST::DoWhileStatement(sym(2).Statement, sym(5).Expression);
+ node->doToken = loc(1);
+ node->whileToken = loc(3);
+ node->lparenToken = loc(4);
+ node->rparenToken = loc(6);
+ node->semicolonToken = loc(7);
+ sym(1).Node = node;
+} break;
+./
+
+IterationStatement: T_WHILE T_LPAREN Expression T_RPAREN Statement ;
+/.
+case $rule_number: {
+ AST::WhileStatement *node = new (pool) AST::WhileStatement(sym(3).Expression, sym(5).Statement);
+ node->whileToken = loc(1);
+ node->lparenToken = loc(2);
+ node->rparenToken = loc(4);
+ sym(1).Node = node;
+} break;
+./
+
+IterationStatement: T_FOR T_LPAREN ExpressionNotInOpt T_SEMICOLON ExpressionOpt T_SEMICOLON ExpressionOpt T_RPAREN Statement ;
+/.
+case $rule_number: {
+ AST::ForStatement *node = new (pool) AST::ForStatement(sym(3).Expression,
+ sym(5).Expression, sym(7).Expression, sym(9).Statement);
+ node->forToken = loc(1);
+ node->lparenToken = loc(2);
+ node->firstSemicolonToken = loc(4);
+ node->secondSemicolonToken = loc(6);
+ node->rparenToken = loc(8);
+ sym(1).Node = node;
+} break;
+./
+
+IterationStatement: T_FOR T_LPAREN T_VAR VariableDeclarationListNotIn T_SEMICOLON ExpressionOpt T_SEMICOLON ExpressionOpt T_RPAREN Statement ;
+/.
+case $rule_number: {
+ AST::LocalForStatement *node = new (pool) AST::LocalForStatement(
+ sym(4).VariableDeclarationList->finish (/*readOnly=*/false), sym(6).Expression,
+ sym(8).Expression, sym(10).Statement);
+ node->forToken = loc(1);
+ node->lparenToken = loc(2);
+ node->varToken = loc(3);
+ node->firstSemicolonToken = loc(5);
+ node->secondSemicolonToken = loc(7);
+ node->rparenToken = loc(9);
+ sym(1).Node = node;
+} break;
+./
+
+IterationStatement: T_FOR T_LPAREN LeftHandSideExpression T_IN Expression T_RPAREN Statement ;
+/.
+case $rule_number: {
+ AST:: ForEachStatement *node = new (pool) AST::ForEachStatement(sym(3).Expression,
+ sym(5).Expression, sym(7).Statement);
+ node->forToken = loc(1);
+ node->lparenToken = loc(2);
+ node->inToken = loc(4);
+ node->rparenToken = loc(6);
+ sym(1).Node = node;
+} break;
+./
+
+IterationStatement: T_FOR T_LPAREN T_VAR VariableDeclarationNotIn T_IN Expression T_RPAREN Statement ;
+/.
+case $rule_number: {
+ AST::LocalForEachStatement *node = new (pool) AST::LocalForEachStatement(
+ sym(4).VariableDeclaration, sym(6).Expression, sym(8).Statement);
+ node->forToken = loc(1);
+ node->lparenToken = loc(2);
+ node->varToken = loc(3);
+ node->inToken = loc(5);
+ node->rparenToken = loc(7);
+ sym(1).Node = node;
+} break;
+./
+
+ContinueStatement: T_CONTINUE T_AUTOMATIC_SEMICOLON ; -- automatic semicolon
+ContinueStatement: T_CONTINUE T_SEMICOLON ;
+/.
+case $rule_number: {
+ AST::ContinueStatement *node = new (pool) AST::ContinueStatement();
+ node->continueToken = loc(1);
+ node->semicolonToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+ContinueStatement: T_CONTINUE JsIdentifier T_AUTOMATIC_SEMICOLON ; -- automatic semicolon
+ContinueStatement: T_CONTINUE JsIdentifier T_SEMICOLON ;
+/.
+case $rule_number: {
+ AST::ContinueStatement *node = new (pool) AST::ContinueStatement(stringRef(2));
+ node->continueToken = loc(1);
+ node->identifierToken = loc(2);
+ node->semicolonToken = loc(3);
+ sym(1).Node = node;
+} break;
+./
+
+BreakStatement: T_BREAK T_AUTOMATIC_SEMICOLON ; -- automatic semicolon
+BreakStatement: T_BREAK T_SEMICOLON ;
+/.
+case $rule_number: {
+ AST::BreakStatement *node = new (pool) AST::BreakStatement(QStringRef());
+ node->breakToken = loc(1);
+ node->semicolonToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+BreakStatement: T_BREAK JsIdentifier T_AUTOMATIC_SEMICOLON ; -- automatic semicolon
+BreakStatement: T_BREAK JsIdentifier T_SEMICOLON ;
+/.
+case $rule_number: {
+ AST::BreakStatement *node = new (pool) AST::BreakStatement(stringRef(2));
+ node->breakToken = loc(1);
+ node->identifierToken = loc(2);
+ node->semicolonToken = loc(3);
+ sym(1).Node = node;
+} break;
+./
+
+ReturnStatement: T_RETURN ExpressionOpt T_AUTOMATIC_SEMICOLON ; -- automatic semicolon
+ReturnStatement: T_RETURN ExpressionOpt T_SEMICOLON ;
+/.
+case $rule_number: {
+ AST::ReturnStatement *node = new (pool) AST::ReturnStatement(sym(2).Expression);
+ node->returnToken = loc(1);
+ node->semicolonToken = loc(3);
+ sym(1).Node = node;
+} break;
+./
+
+WithStatement: T_WITH T_LPAREN Expression T_RPAREN Statement ;
+/.
+case $rule_number: {
+ AST::WithStatement *node = new (pool) AST::WithStatement(sym(3).Expression, sym(5).Statement);
+ node->withToken = loc(1);
+ node->lparenToken = loc(2);
+ node->rparenToken = loc(4);
+ sym(1).Node = node;
+} break;
+./
+
+SwitchStatement: T_SWITCH T_LPAREN Expression T_RPAREN CaseBlock ;
+/.
+case $rule_number: {
+ AST::SwitchStatement *node = new (pool) AST::SwitchStatement(sym(3).Expression, sym(5).CaseBlock);
+ node->switchToken = loc(1);
+ node->lparenToken = loc(2);
+ node->rparenToken = loc(4);
+ sym(1).Node = node;
+} break;
+./
+
+CaseBlock: T_LBRACE CaseClausesOpt T_RBRACE ;
+/.
+case $rule_number: {
+ AST::CaseBlock *node = new (pool) AST::CaseBlock(sym(2).CaseClauses);
+ node->lbraceToken = loc(1);
+ node->rbraceToken = loc(3);
+ sym(1).Node = node;
+} break;
+./
+
+CaseBlock: T_LBRACE CaseClausesOpt DefaultClause CaseClausesOpt T_RBRACE ;
+/.
+case $rule_number: {
+ AST::CaseBlock *node = new (pool) AST::CaseBlock(sym(2).CaseClauses, sym(3).DefaultClause, sym(4).CaseClauses);
+ node->lbraceToken = loc(1);
+ node->rbraceToken = loc(5);
+ sym(1).Node = node;
+} break;
+./
+
+CaseClauses: CaseClause ;
+/.
+case $rule_number: {
+ sym(1).Node = new (pool) AST::CaseClauses(sym(1).CaseClause);
+} break;
+./
+
+CaseClauses: CaseClauses CaseClause ;
+/.
+case $rule_number: {
+ sym(1).Node = new (pool) AST::CaseClauses(sym(1).CaseClauses, sym(2).CaseClause);
+} break;
+./
+
+CaseClausesOpt: ;
+/.
+case $rule_number: {
+ sym(1).Node = 0;
+} break;
+./
+
+CaseClausesOpt: CaseClauses ;
+/.
+case $rule_number: {
+ sym(1).Node = sym(1).CaseClauses->finish ();
+} break;
+./
+
+CaseClause: T_CASE Expression T_COLON StatementListOpt ;
+/.
+case $rule_number: {
+ AST::CaseClause *node = new (pool) AST::CaseClause(sym(2).Expression, sym(4).StatementList);
+ node->caseToken = loc(1);
+ node->colonToken = loc(3);
+ sym(1).Node = node;
+} break;
+./
+
+DefaultClause: T_DEFAULT T_COLON StatementListOpt ;
+/.
+case $rule_number: {
+ AST::DefaultClause *node = new (pool) AST::DefaultClause(sym(3).StatementList);
+ node->defaultToken = loc(1);
+ node->colonToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+LabelledStatement: T_SIGNAL T_COLON Statement ;
+/.case $rule_number:./
+
+LabelledStatement: T_PROPERTY T_COLON Statement ;
+/.
+case $rule_number: {
+ AST::LabelledStatement *node = new (pool) AST::LabelledStatement(stringRef(1), sym(3).Statement);
+ node->identifierToken = loc(1);
+ node->colonToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+LabelledStatement: T_IDENTIFIER T_COLON Statement ;
+/.
+case $rule_number: {
+ AST::LabelledStatement *node = new (pool) AST::LabelledStatement(stringRef(1), sym(3).Statement);
+ node->identifierToken = loc(1);
+ node->colonToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+ThrowStatement: T_THROW Expression T_AUTOMATIC_SEMICOLON ; -- automatic semicolon
+ThrowStatement: T_THROW Expression T_SEMICOLON ;
+/.
+case $rule_number: {
+ AST::ThrowStatement *node = new (pool) AST::ThrowStatement(sym(2).Expression);
+ node->throwToken = loc(1);
+ node->semicolonToken = loc(3);
+ sym(1).Node = node;
+} break;
+./
+
+TryStatement: T_TRY Block Catch ;
+/.
+case $rule_number: {
+ AST::TryStatement *node = new (pool) AST::TryStatement(sym(2).Statement, sym(3).Catch);
+ node->tryToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+TryStatement: T_TRY Block Finally ;
+/.
+case $rule_number: {
+ AST::TryStatement *node = new (pool) AST::TryStatement(sym(2).Statement, sym(3).Finally);
+ node->tryToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+TryStatement: T_TRY Block Catch Finally ;
+/.
+case $rule_number: {
+ AST::TryStatement *node = new (pool) AST::TryStatement(sym(2).Statement, sym(3).Catch, sym(4).Finally);
+ node->tryToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+Catch: T_CATCH T_LPAREN JsIdentifier T_RPAREN Block ;
+/.
+case $rule_number: {
+ AST::Catch *node = new (pool) AST::Catch(stringRef(3), sym(5).Block);
+ node->catchToken = loc(1);
+ node->lparenToken = loc(2);
+ node->identifierToken = loc(3);
+ node->rparenToken = loc(4);
+ sym(1).Node = node;
+} break;
+./
+
+Finally: T_FINALLY Block ;
+/.
+case $rule_number: {
+ AST::Finally *node = new (pool) AST::Finally(sym(2).Block);
+ node->finallyToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+DebuggerStatement: T_DEBUGGER T_AUTOMATIC_SEMICOLON ; -- automatic semicolon
+DebuggerStatement: T_DEBUGGER T_SEMICOLON ;
+/.
+case $rule_number: {
+ AST::DebuggerStatement *node = new (pool) AST::DebuggerStatement();
+ node->debuggerToken = loc(1);
+ node->semicolonToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+FunctionDeclaration: T_FUNCTION JsIdentifier T_LPAREN FormalParameterListOpt T_RPAREN T_LBRACE FunctionBodyOpt T_RBRACE ;
+/.
+case $rule_number: {
+ AST::FunctionDeclaration *node = new (pool) AST::FunctionDeclaration(stringRef(2), sym(4).FormalParameterList, sym(7).FunctionBody);
+ node->functionToken = loc(1);
+ node->identifierToken = loc(2);
+ node->lparenToken = loc(3);
+ node->rparenToken = loc(5);
+ node->lbraceToken = loc(6);
+ node->rbraceToken = loc(8);
+ sym(1).Node = node;
+} break;
+./
+
+FunctionExpression: T_FUNCTION IdentifierOpt T_LPAREN FormalParameterListOpt T_RPAREN T_LBRACE FunctionBodyOpt T_RBRACE ;
+/.
+case $rule_number: {
+ AST::FunctionExpression *node = new (pool) AST::FunctionExpression(stringRef(2), sym(4).FormalParameterList, sym(7).FunctionBody);
+ node->functionToken = loc(1);
+ if (! stringRef(2).isNull())
+ node->identifierToken = loc(2);
+ node->lparenToken = loc(3);
+ node->rparenToken = loc(5);
+ node->lbraceToken = loc(6);
+ node->rbraceToken = loc(8);
+ sym(1).Node = node;
+} break;
+./
+
+FormalParameterList: JsIdentifier ;
+/.
+case $rule_number: {
+ AST::FormalParameterList *node = new (pool) AST::FormalParameterList(stringRef(1));
+ node->identifierToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+FormalParameterList: FormalParameterList T_COMMA JsIdentifier ;
+/.
+case $rule_number: {
+ AST::FormalParameterList *node = new (pool) AST::FormalParameterList(sym(1).FormalParameterList, stringRef(3));
+ node->commaToken = loc(2);
+ node->identifierToken = loc(3);
+ sym(1).Node = node;
+} break;
+./
+
+FormalParameterListOpt: ;
+/.
+case $rule_number: {
+ sym(1).Node = 0;
+} break;
+./
+
+FormalParameterListOpt: FormalParameterList ;
+/.
+case $rule_number: {
+ sym(1).Node = sym(1).FormalParameterList->finish ();
+} break;
+./
+
+FunctionBodyOpt: ;
+/.
+case $rule_number: {
+ sym(1).Node = 0;
+} break;
+./
+
+FunctionBodyOpt: FunctionBody ;
+
+FunctionBody: SourceElements ;
+/.
+case $rule_number: {
+ sym(1).Node = new (pool) AST::FunctionBody(sym(1).SourceElements->finish ());
+} break;
+./
+
+Program: Empty ;
+
+Program: SourceElements ;
+/.
+case $rule_number: {
+ sym(1).Node = new (pool) AST::Program(sym(1).SourceElements->finish ());
+} break;
+./
+
+SourceElements: SourceElement ;
+/.
+case $rule_number: {
+ sym(1).Node = new (pool) AST::SourceElements(sym(1).SourceElement);
+} break;
+./
+
+SourceElements: SourceElements SourceElement ;
+/.
+case $rule_number: {
+ sym(1).Node = new (pool) AST::SourceElements(sym(1).SourceElements, sym(2).SourceElement);
+} break;
+./
+
+SourceElement: Statement ;
+/.
+case $rule_number: {
+ sym(1).Node = new (pool) AST::StatementSourceElement(sym(1).Statement);
+} break;
+./
+
+SourceElement: FunctionDeclaration ;
+/.
+case $rule_number: {
+ sym(1).Node = new (pool) AST::FunctionSourceElement(sym(1).FunctionDeclaration);
+} break;
+./
+
+IdentifierOpt: ;
+/.
+case $rule_number: {
+ stringRef(1) = QStringRef();
+} break;
+./
+
+IdentifierOpt: JsIdentifier ;
+
+PropertyNameAndValueListOpt: ;
+/.
+case $rule_number: {
+ sym(1).Node = 0;
+} break;
+./
+
+PropertyNameAndValueListOpt: PropertyNameAndValueList ;
+
+/.
+ } // switch
+ action = nt_action(state_stack[tos], lhs[r] - TERMINAL_COUNT);
+ } // if
+ } while (action != 0);
+
+ if (first_token == last_token) {
+ const int errorState = state_stack[tos];
+
+ // automatic insertion of `;'
+ if (yytoken != -1 && t_action(errorState, T_AUTOMATIC_SEMICOLON) && lexer->canInsertAutomaticSemicolon(yytoken)) {
+ SavedToken &tk = token_buffer[0];
+ tk.token = yytoken;
+ tk.dval = yylval;
+ tk.spell = yytokenspell;
+ tk.loc = yylloc;
+
+ yylloc = yyprevlloc;
+ yylloc.offset += yylloc.length;
+ yylloc.startColumn += yylloc.length;
+ yylloc.length = 0;
+
+ //const QString msg = qApp->translate("QQmlParser", "Missing `;'");
+ //diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Warning, yylloc, msg));
+
+ first_token = &token_buffer[0];
+ last_token = &token_buffer[1];
+
+ yytoken = T_SEMICOLON;
+ yylval = 0;
+
+ action = errorState;
+
+ goto _Lcheck_token;
+ }
+
+ hadErrors = true;
+
+ token_buffer[0].token = yytoken;
+ token_buffer[0].dval = yylval;
+ token_buffer[0].spell = yytokenspell;
+ token_buffer[0].loc = yylloc;
+
+ token_buffer[1].token = yytoken = lexer->lex();
+ token_buffer[1].dval = yylval = lexer->tokenValue();
+ token_buffer[1].spell = yytokenspell = lexer->tokenSpell();
+ token_buffer[1].loc = yylloc = location(lexer);
+
+ if (t_action(errorState, yytoken)) {
+ QString msg;
+ int token = token_buffer[0].token;
+ if (token < 0 || token >= TERMINAL_COUNT)
+ msg = qApp->translate("QQmlParser", "Syntax error");
+ else
+ msg = qApp->translate("QQmlParser", "Unexpected token `%1'").arg(QLatin1String(spell[token]));
+ diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, token_buffer[0].loc, msg));
+
+ action = errorState;
+ goto _Lcheck_token;
+ }
+
+ static int tokens[] = {
+ T_PLUS,
+ T_EQ,
+
+ T_COMMA,
+ T_COLON,
+ T_SEMICOLON,
+
+ T_RPAREN, T_RBRACKET, T_RBRACE,
+
+ T_NUMERIC_LITERAL,
+ T_IDENTIFIER,
+
+ T_LPAREN, T_LBRACKET, T_LBRACE,
+
+ EOF_SYMBOL
+ };
+
+ for (int *tk = tokens; *tk != EOF_SYMBOL; ++tk) {
+ int a = t_action(errorState, *tk);
+ if (a > 0 && t_action(a, yytoken)) {
+ const QString msg = qApp->translate("QQmlParser", "Expected token `%1'").arg(QLatin1String(spell[*tk]));
+ diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, token_buffer[0].loc, msg));
+
+ yytoken = *tk;
+ yylval = 0;
+ yylloc = token_buffer[0].loc;
+ yylloc.length = 0;
+
+ first_token = &token_buffer[0];
+ last_token = &token_buffer[2];
+
+ action = errorState;
+ goto _Lcheck_token;
+ }
+ }
+
+ for (int tk = 1; tk < TERMINAL_COUNT; ++tk) {
+ if (tk == T_AUTOMATIC_SEMICOLON || tk == T_FEED_UI_PROGRAM ||
+ tk == T_FEED_JS_STATEMENT || tk == T_FEED_JS_EXPRESSION ||
+ tk == T_FEED_JS_SOURCE_ELEMENT)
+ continue;
+
+ int a = t_action(errorState, tk);
+ if (a > 0 && t_action(a, yytoken)) {
+ const QString msg = qApp->translate("QQmlParser", "Expected token `%1'").arg(QLatin1String(spell[tk]));
+ diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, token_buffer[0].loc, msg));
+
+ yytoken = tk;
+ yylval = 0;
+ yylloc = token_buffer[0].loc;
+ yylloc.length = 0;
+
+ action = errorState;
+ goto _Lcheck_token;
+ }
+ }
+
+ const QString msg = qApp->translate("QQmlParser", "Syntax error");
+ diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, token_buffer[0].loc, msg));
+ }
+
+ return false;
+}
+
+QT_QML_END_NAMESPACE
+
+
+./
+/:
+QT_QML_END_NAMESPACE
+
+
+
+#endif // QDECLARATIVEJSPARSER_P_H
+:/
diff --git a/src/qml/qml/parser/qqmljsast.cpp b/src/qml/qml/parser/qqmljsast.cpp
new file mode 100644
index 0000000000..d0b984fc9e
--- /dev/null
+++ b/src/qml/qml/parser/qqmljsast.cpp
@@ -0,0 +1,931 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qqmljsast_p.h"
+
+#include "qqmljsastvisitor_p.h"
+
+QT_QML_BEGIN_NAMESPACE
+
+namespace QQmlJS { namespace AST {
+
+void Node::accept(Visitor *visitor)
+{
+ if (visitor->preVisit(this)) {
+ accept0(visitor);
+ }
+ visitor->postVisit(this);
+}
+
+void Node::accept(Node *node, Visitor *visitor)
+{
+ if (node)
+ node->accept(visitor);
+}
+
+ExpressionNode *Node::expressionCast()
+{
+ return 0;
+}
+
+BinaryExpression *Node::binaryExpressionCast()
+{
+ return 0;
+}
+
+Statement *Node::statementCast()
+{
+ return 0;
+}
+
+UiObjectMember *Node::uiObjectMemberCast()
+{
+ return 0;
+}
+
+ExpressionNode *ExpressionNode::expressionCast()
+{
+ return this;
+}
+
+BinaryExpression *BinaryExpression::binaryExpressionCast()
+{
+ return this;
+}
+
+Statement *Statement::statementCast()
+{
+ return this;
+}
+
+UiObjectMember *UiObjectMember::uiObjectMemberCast()
+{
+ return this;
+}
+
+void NestedExpression::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(expression, visitor);
+ }
+ visitor->endVisit(this);
+}
+
+void ThisExpression::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ }
+
+ visitor->endVisit(this);
+}
+
+void IdentifierExpression::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ }
+
+ visitor->endVisit(this);
+}
+
+void NullExpression::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ }
+
+ visitor->endVisit(this);
+}
+
+void TrueLiteral::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ }
+
+ visitor->endVisit(this);
+}
+
+void FalseLiteral::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ }
+
+ visitor->endVisit(this);
+}
+
+void StringLiteral::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ }
+
+ visitor->endVisit(this);
+}
+
+void NumericLiteral::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ }
+
+ visitor->endVisit(this);
+}
+
+void RegExpLiteral::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ }
+
+ visitor->endVisit(this);
+}
+
+void ArrayLiteral::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(elements, visitor);
+ accept(elision, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void ObjectLiteral::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(properties, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void ElementList::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ for (ElementList *it = this; it; it = it->next) {
+ accept(it->elision, visitor);
+ accept(it->expression, visitor);
+ }
+ }
+
+ visitor->endVisit(this);
+}
+
+void Elision::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ // ###
+ }
+
+ visitor->endVisit(this);
+}
+
+void PropertyNameAndValueList::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ for (PropertyNameAndValueList *it = this; it; it = it->next) {
+ accept(it->name, visitor);
+ accept(it->value, visitor);
+ }
+ }
+
+ visitor->endVisit(this);
+}
+
+void IdentifierPropertyName::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ }
+
+ visitor->endVisit(this);
+}
+
+void StringLiteralPropertyName::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ }
+
+ visitor->endVisit(this);
+}
+
+void NumericLiteralPropertyName::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ }
+
+ visitor->endVisit(this);
+}
+
+void ArrayMemberExpression::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(base, visitor);
+ accept(expression, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void FieldMemberExpression::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(base, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void NewMemberExpression::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(base, visitor);
+ accept(arguments, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void NewExpression::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(expression, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void CallExpression::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(base, visitor);
+ accept(arguments, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void ArgumentList::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ for (ArgumentList *it = this; it; it = it->next) {
+ accept(it->expression, visitor);
+ }
+ }
+
+ visitor->endVisit(this);
+}
+
+void PostIncrementExpression::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(base, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void PostDecrementExpression::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(base, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void DeleteExpression::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(expression, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void VoidExpression::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(expression, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void TypeOfExpression::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(expression, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void PreIncrementExpression::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(expression, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void PreDecrementExpression::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(expression, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void UnaryPlusExpression::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(expression, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void UnaryMinusExpression::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(expression, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void TildeExpression::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(expression, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void NotExpression::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(expression, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void BinaryExpression::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(left, visitor);
+ accept(right, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void ConditionalExpression::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(expression, visitor);
+ accept(ok, visitor);
+ accept(ko, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void Expression::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(left, visitor);
+ accept(right, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void Block::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(statements, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void StatementList::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ for (StatementList *it = this; it; it = it->next) {
+ accept(it->statement, visitor);
+ }
+ }
+
+ visitor->endVisit(this);
+}
+
+void VariableStatement::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(declarations, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void VariableDeclarationList::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ for (VariableDeclarationList *it = this; it; it = it->next) {
+ accept(it->declaration, visitor);
+ }
+ }
+
+ visitor->endVisit(this);
+}
+
+void VariableDeclaration::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(expression, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void EmptyStatement::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ }
+
+ visitor->endVisit(this);
+}
+
+void ExpressionStatement::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(expression, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void IfStatement::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(expression, visitor);
+ accept(ok, visitor);
+ accept(ko, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void DoWhileStatement::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(statement, visitor);
+ accept(expression, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void WhileStatement::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(expression, visitor);
+ accept(statement, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void ForStatement::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(initialiser, visitor);
+ accept(condition, visitor);
+ accept(expression, visitor);
+ accept(statement, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void LocalForStatement::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(declarations, visitor);
+ accept(condition, visitor);
+ accept(expression, visitor);
+ accept(statement, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void ForEachStatement::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(initialiser, visitor);
+ accept(expression, visitor);
+ accept(statement, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void LocalForEachStatement::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(declaration, visitor);
+ accept(expression, visitor);
+ accept(statement, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void ContinueStatement::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ }
+
+ visitor->endVisit(this);
+}
+
+void BreakStatement::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ }
+
+ visitor->endVisit(this);
+}
+
+void ReturnStatement::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(expression, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void WithStatement::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(expression, visitor);
+ accept(statement, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void SwitchStatement::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(expression, visitor);
+ accept(block, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void CaseBlock::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(clauses, visitor);
+ accept(defaultClause, visitor);
+ accept(moreClauses, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void CaseClauses::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ for (CaseClauses *it = this; it; it = it->next) {
+ accept(it->clause, visitor);
+ }
+ }
+
+ visitor->endVisit(this);
+}
+
+void CaseClause::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(expression, visitor);
+ accept(statements, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void DefaultClause::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(statements, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void LabelledStatement::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(statement, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void ThrowStatement::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(expression, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void TryStatement::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(statement, visitor);
+ accept(catchExpression, visitor);
+ accept(finallyExpression, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void Catch::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(statement, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void Finally::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(statement, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void FunctionDeclaration::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(formals, visitor);
+ accept(body, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void FunctionExpression::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(formals, visitor);
+ accept(body, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void FormalParameterList::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ // ###
+ }
+
+ visitor->endVisit(this);
+}
+
+void FunctionBody::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(elements, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void Program::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(elements, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void SourceElements::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ for (SourceElements *it = this; it; it = it->next) {
+ accept(it->element, visitor);
+ }
+ }
+
+ visitor->endVisit(this);
+}
+
+void FunctionSourceElement::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(declaration, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void StatementSourceElement::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(statement, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void DebuggerStatement::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ }
+
+ visitor->endVisit(this);
+}
+
+void UiProgram::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(imports, visitor);
+ accept(members, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void UiPublicMember::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(statement, visitor);
+ accept(binding, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void UiObjectDefinition::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(qualifiedTypeNameId, visitor);
+ accept(initializer, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void UiObjectInitializer::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(members, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void UiObjectBinding::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(qualifiedId, visitor);
+ accept(qualifiedTypeNameId, visitor);
+ accept(initializer, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void UiScriptBinding::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(qualifiedId, visitor);
+ accept(statement, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void UiArrayBinding::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(qualifiedId, visitor);
+ accept(members, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void UiObjectMemberList::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ for (UiObjectMemberList *it = this; it; it = it->next)
+ accept(it->member, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void UiArrayMemberList::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ for (UiArrayMemberList *it = this; it; it = it->next)
+ accept(it->member, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void UiQualifiedId::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ }
+
+ visitor->endVisit(this);
+}
+
+void UiImport::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(importUri, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void UiImportList::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(import, visitor);
+ accept(next, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void UiSourceElement::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(sourceElement, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+} } // namespace QQmlJS::AST
+
+QT_QML_END_NAMESPACE
+
+
diff --git a/src/qml/qml/parser/qqmljsast_p.h b/src/qml/qml/parser/qqmljsast_p.h
new file mode 100644
index 0000000000..f85eb4ca5f
--- /dev/null
+++ b/src/qml/qml/parser/qqmljsast_p.h
@@ -0,0 +1,2640 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLJSAST_P_H
+#define QQMLJSAST_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 "qqmljsastvisitor_p.h"
+#include "qqmljsglobal_p.h"
+#include "qqmljsmemorypool_p.h"
+
+#include <QtCore/QString>
+
+QT_QML_BEGIN_NAMESPACE
+
+#define QQMLJS_DECLARE_AST_NODE(name) \
+ enum { K = Kind_##name };
+
+namespace QSOperator // ### rename
+{
+
+enum Op {
+ Add,
+ And,
+ InplaceAnd,
+ Assign,
+ BitAnd,
+ BitOr,
+ BitXor,
+ InplaceSub,
+ Div,
+ InplaceDiv,
+ Equal,
+ Ge,
+ Gt,
+ In,
+ InplaceAdd,
+ InstanceOf,
+ Le,
+ LShift,
+ InplaceLeftShift,
+ Lt,
+ Mod,
+ InplaceMod,
+ Mul,
+ InplaceMul,
+ NotEqual,
+ Or,
+ InplaceOr,
+ RShift,
+ InplaceRightShift,
+ StrictEqual,
+ StrictNotEqual,
+ Sub,
+ URShift,
+ InplaceURightShift,
+ InplaceXor
+};
+
+} // namespace QSOperator
+
+namespace QQmlJS {
+
+namespace AST {
+
+template <typename _T1, typename _T2>
+_T1 cast(_T2 *ast)
+{
+ if (ast && ast->kind == static_cast<_T1>(0)->K)
+ return static_cast<_T1>(ast);
+
+ return 0;
+}
+
+class QML_PARSER_EXPORT Node: public Managed
+{
+public:
+ enum Kind {
+ Kind_Undefined,
+
+ Kind_ArgumentList,
+ Kind_ArrayLiteral,
+ Kind_ArrayMemberExpression,
+ Kind_BinaryExpression,
+ Kind_Block,
+ Kind_BreakStatement,
+ Kind_CallExpression,
+ Kind_CaseBlock,
+ Kind_CaseClause,
+ Kind_CaseClauses,
+ Kind_Catch,
+ Kind_ConditionalExpression,
+ Kind_ContinueStatement,
+ Kind_DebuggerStatement,
+ Kind_DefaultClause,
+ Kind_DeleteExpression,
+ Kind_DoWhileStatement,
+ Kind_ElementList,
+ Kind_Elision,
+ Kind_EmptyStatement,
+ Kind_Expression,
+ Kind_ExpressionStatement,
+ Kind_FalseLiteral,
+ Kind_FieldMemberExpression,
+ Kind_Finally,
+ Kind_ForEachStatement,
+ Kind_ForStatement,
+ Kind_FormalParameterList,
+ Kind_FunctionBody,
+ Kind_FunctionDeclaration,
+ Kind_FunctionExpression,
+ Kind_FunctionSourceElement,
+ Kind_IdentifierExpression,
+ Kind_IdentifierPropertyName,
+ Kind_IfStatement,
+ Kind_LabelledStatement,
+ Kind_LocalForEachStatement,
+ Kind_LocalForStatement,
+ Kind_NewExpression,
+ Kind_NewMemberExpression,
+ Kind_NotExpression,
+ Kind_NullExpression,
+ Kind_NumericLiteral,
+ Kind_NumericLiteralPropertyName,
+ Kind_ObjectLiteral,
+ Kind_PostDecrementExpression,
+ Kind_PostIncrementExpression,
+ Kind_PreDecrementExpression,
+ Kind_PreIncrementExpression,
+ Kind_Program,
+ Kind_PropertyName,
+ Kind_PropertyNameAndValueList,
+ Kind_RegExpLiteral,
+ Kind_ReturnStatement,
+ Kind_SourceElement,
+ Kind_SourceElements,
+ Kind_StatementList,
+ Kind_StatementSourceElement,
+ Kind_StringLiteral,
+ Kind_StringLiteralPropertyName,
+ Kind_SwitchStatement,
+ Kind_ThisExpression,
+ Kind_ThrowStatement,
+ Kind_TildeExpression,
+ Kind_TrueLiteral,
+ Kind_TryStatement,
+ Kind_TypeOfExpression,
+ Kind_UnaryMinusExpression,
+ Kind_UnaryPlusExpression,
+ Kind_VariableDeclaration,
+ Kind_VariableDeclarationList,
+ Kind_VariableStatement,
+ Kind_VoidExpression,
+ Kind_WhileStatement,
+ Kind_WithStatement,
+ Kind_NestedExpression,
+
+ Kind_UiArrayBinding,
+ Kind_UiImport,
+ Kind_UiImportList,
+ Kind_UiObjectBinding,
+ Kind_UiObjectDefinition,
+ Kind_UiObjectInitializer,
+ Kind_UiObjectMemberList,
+ Kind_UiArrayMemberList,
+ Kind_UiProgram,
+ Kind_UiParameterList,
+ Kind_UiPublicMember,
+ Kind_UiQualifiedId,
+ Kind_UiScriptBinding,
+ Kind_UiSourceElement
+ };
+
+ inline Node()
+ : kind(Kind_Undefined) {}
+
+ // NOTE: node destructors are never called,
+ // instead we block free the memory
+ // (see the NodePool class)
+ virtual ~Node() {}
+
+ virtual ExpressionNode *expressionCast();
+ virtual BinaryExpression *binaryExpressionCast();
+ virtual Statement *statementCast();
+ virtual UiObjectMember *uiObjectMemberCast();
+
+ void accept(Visitor *visitor);
+ static void accept(Node *node, Visitor *visitor);
+
+ inline static void acceptChild(Node *node, Visitor *visitor)
+ { return accept(node, visitor); } // ### remove
+
+ virtual void accept0(Visitor *visitor) = 0;
+ virtual SourceLocation firstSourceLocation() const = 0;
+ virtual SourceLocation lastSourceLocation() const = 0;
+
+// attributes
+ int kind;
+};
+
+class QML_PARSER_EXPORT ExpressionNode: public Node
+{
+public:
+ ExpressionNode() {}
+
+ virtual ExpressionNode *expressionCast();
+};
+
+class QML_PARSER_EXPORT Statement: public Node
+{
+public:
+ Statement() {}
+
+ virtual Statement *statementCast();
+};
+
+class QML_PARSER_EXPORT NestedExpression: public ExpressionNode
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(NestedExpression)
+
+ NestedExpression(ExpressionNode *expression)
+ : expression(expression)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return lparenToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return rparenToken; }
+
+// attributes
+ ExpressionNode *expression;
+ SourceLocation lparenToken;
+ SourceLocation rparenToken;
+};
+
+class QML_PARSER_EXPORT ThisExpression: public ExpressionNode
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(ThisExpression)
+
+ ThisExpression() { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return thisToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return thisToken; }
+
+// attributes
+ SourceLocation thisToken;
+};
+
+class QML_PARSER_EXPORT IdentifierExpression: public ExpressionNode
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(IdentifierExpression)
+
+ IdentifierExpression(const QStringRef &n):
+ name (n) { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return identifierToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return identifierToken; }
+
+// attributes
+ QStringRef name;
+ SourceLocation identifierToken;
+};
+
+class QML_PARSER_EXPORT NullExpression: public ExpressionNode
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(NullExpression)
+
+ NullExpression() { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return nullToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return nullToken; }
+
+// attributes
+ SourceLocation nullToken;
+};
+
+class QML_PARSER_EXPORT TrueLiteral: public ExpressionNode
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(TrueLiteral)
+
+ TrueLiteral() { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return trueToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return trueToken; }
+
+// attributes
+ SourceLocation trueToken;
+};
+
+class QML_PARSER_EXPORT FalseLiteral: public ExpressionNode
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(FalseLiteral)
+
+ FalseLiteral() { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return falseToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return falseToken; }
+
+// attributes
+ SourceLocation falseToken;
+};
+
+class QML_PARSER_EXPORT NumericLiteral: public ExpressionNode
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(NumericLiteral)
+
+ NumericLiteral(double v):
+ value(v) { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return literalToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return literalToken; }
+
+// attributes:
+ double value;
+ SourceLocation literalToken;
+};
+
+class QML_PARSER_EXPORT StringLiteral: public ExpressionNode
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(StringLiteral)
+
+ StringLiteral(const QStringRef &v):
+ value (v) { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return literalToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return literalToken; }
+
+// attributes:
+ QStringRef value;
+ SourceLocation literalToken;
+};
+
+class QML_PARSER_EXPORT RegExpLiteral: public ExpressionNode
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(RegExpLiteral)
+
+ RegExpLiteral(const QStringRef &p, int f):
+ pattern (p), flags (f) { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return literalToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return literalToken; }
+
+// attributes:
+ QStringRef pattern;
+ int flags;
+ SourceLocation literalToken;
+};
+
+class QML_PARSER_EXPORT ArrayLiteral: public ExpressionNode
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(ArrayLiteral)
+
+ ArrayLiteral(Elision *e):
+ elements (0), elision (e)
+ { kind = K; }
+
+ ArrayLiteral(ElementList *elts):
+ elements (elts), elision (0)
+ { kind = K; }
+
+ ArrayLiteral(ElementList *elts, Elision *e):
+ elements (elts), elision (e)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return lbracketToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return rbracketToken; }
+
+// attributes
+ ElementList *elements;
+ Elision *elision;
+ SourceLocation lbracketToken;
+ SourceLocation commaToken;
+ SourceLocation rbracketToken;
+};
+
+class QML_PARSER_EXPORT ObjectLiteral: public ExpressionNode
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(ObjectLiteral)
+
+ ObjectLiteral():
+ properties (0) { kind = K; }
+
+ ObjectLiteral(PropertyNameAndValueList *plist):
+ properties (plist) { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return lbraceToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return rbraceToken; }
+
+// attributes
+ PropertyNameAndValueList *properties;
+ SourceLocation lbraceToken;
+ SourceLocation rbraceToken;
+};
+
+class QML_PARSER_EXPORT Elision: public Node
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(Elision)
+
+ Elision():
+ next (this) { kind = K; }
+
+ Elision(Elision *previous)
+ {
+ kind = K;
+ next = previous->next;
+ previous->next = this;
+ }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return commaToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return next ? next->lastSourceLocation() : commaToken; }
+
+ inline Elision *finish ()
+ {
+ Elision *front = next;
+ next = 0;
+ return front;
+ }
+
+// attributes
+ Elision *next;
+ SourceLocation commaToken;
+};
+
+class QML_PARSER_EXPORT ElementList: public Node
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(ElementList)
+
+ ElementList(Elision *e, ExpressionNode *expr):
+ elision (e), expression (expr), next (this)
+ { kind = K; }
+
+ ElementList(ElementList *previous, Elision *e, ExpressionNode *expr):
+ elision (e), expression (expr)
+ {
+ kind = K;
+ next = previous->next;
+ previous->next = this;
+ }
+
+ inline ElementList *finish ()
+ {
+ ElementList *front = next;
+ next = 0;
+ return front;
+ }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ {
+ if (elision)
+ return elision->firstSourceLocation();
+ return expression->firstSourceLocation();
+ }
+
+ virtual SourceLocation lastSourceLocation() const
+ {
+ if (next)
+ return next->lastSourceLocation();
+ return expression->lastSourceLocation();
+ }
+
+// attributes
+ Elision *elision;
+ ExpressionNode *expression;
+ ElementList *next;
+ SourceLocation commaToken;
+};
+
+class QML_PARSER_EXPORT PropertyName: public Node
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(PropertyName)
+
+ PropertyName() { kind = K; }
+
+ virtual SourceLocation firstSourceLocation() const
+ { return propertyNameToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return propertyNameToken; }
+
+// attributes
+ SourceLocation propertyNameToken;
+};
+
+class QML_PARSER_EXPORT PropertyNameAndValueList: public Node
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(PropertyNameAndValueList)
+
+ PropertyNameAndValueList(PropertyName *n, ExpressionNode *v):
+ name (n), value (v), next (this)
+ { kind = K; }
+
+ PropertyNameAndValueList(PropertyNameAndValueList *previous, PropertyName *n, ExpressionNode *v):
+ name (n), value (v)
+ {
+ kind = K;
+ next = previous->next;
+ previous->next = this;
+ }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return name->firstSourceLocation(); }
+
+ virtual SourceLocation lastSourceLocation() const
+ {
+ if (next)
+ return next->lastSourceLocation();
+ return value->lastSourceLocation();
+ }
+
+ inline PropertyNameAndValueList *finish ()
+ {
+ PropertyNameAndValueList *front = next;
+ next = 0;
+ return front;
+ }
+
+// attributes
+ PropertyName *name;
+ ExpressionNode *value;
+ PropertyNameAndValueList *next;
+ SourceLocation colonToken;
+ SourceLocation commaToken;
+};
+
+class QML_PARSER_EXPORT IdentifierPropertyName: public PropertyName
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(IdentifierPropertyName)
+
+ IdentifierPropertyName(const QStringRef &n):
+ id (n) { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+// attributes
+ QStringRef id;
+};
+
+class QML_PARSER_EXPORT StringLiteralPropertyName: public PropertyName
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(StringLiteralPropertyName)
+
+ StringLiteralPropertyName(const QStringRef &n):
+ id (n) { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+// attributes
+ QStringRef id;
+};
+
+class QML_PARSER_EXPORT NumericLiteralPropertyName: public PropertyName
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(NumericLiteralPropertyName)
+
+ NumericLiteralPropertyName(double n):
+ id (n) { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+// attributes
+ double id;
+};
+
+class QML_PARSER_EXPORT ArrayMemberExpression: public ExpressionNode
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(ArrayMemberExpression)
+
+ ArrayMemberExpression(ExpressionNode *b, ExpressionNode *e):
+ base (b), expression (e)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return base->firstSourceLocation(); }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return rbracketToken; }
+
+// attributes
+ ExpressionNode *base;
+ ExpressionNode *expression;
+ SourceLocation lbracketToken;
+ SourceLocation rbracketToken;
+};
+
+class QML_PARSER_EXPORT FieldMemberExpression: public ExpressionNode
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(FieldMemberExpression)
+
+ FieldMemberExpression(ExpressionNode *b, const QStringRef &n):
+ base (b), name (n)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return base->firstSourceLocation(); }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return identifierToken; }
+
+ // attributes
+ ExpressionNode *base;
+ QStringRef name;
+ SourceLocation dotToken;
+ SourceLocation identifierToken;
+};
+
+class QML_PARSER_EXPORT NewMemberExpression: public ExpressionNode
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(NewMemberExpression)
+
+ NewMemberExpression(ExpressionNode *b, ArgumentList *a):
+ base (b), arguments (a)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return newToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return rparenToken; }
+
+ // attributes
+ ExpressionNode *base;
+ ArgumentList *arguments;
+ SourceLocation newToken;
+ SourceLocation lparenToken;
+ SourceLocation rparenToken;
+};
+
+class QML_PARSER_EXPORT NewExpression: public ExpressionNode
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(NewExpression)
+
+ NewExpression(ExpressionNode *e):
+ expression (e) { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return newToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return expression->lastSourceLocation(); }
+
+// attributes
+ ExpressionNode *expression;
+ SourceLocation newToken;
+};
+
+class QML_PARSER_EXPORT CallExpression: public ExpressionNode
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(CallExpression)
+
+ CallExpression(ExpressionNode *b, ArgumentList *a):
+ base (b), arguments (a)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return base->firstSourceLocation(); }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return rparenToken; }
+
+// attributes
+ ExpressionNode *base;
+ ArgumentList *arguments;
+ SourceLocation lparenToken;
+ SourceLocation rparenToken;
+};
+
+class QML_PARSER_EXPORT ArgumentList: public Node
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(ArgumentList)
+
+ ArgumentList(ExpressionNode *e):
+ expression (e), next (this)
+ { kind = K; }
+
+ ArgumentList(ArgumentList *previous, ExpressionNode *e):
+ expression (e)
+ {
+ kind = K;
+ next = previous->next;
+ previous->next = this;
+ }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return expression->firstSourceLocation(); }
+
+ virtual SourceLocation lastSourceLocation() const
+ {
+ if (next)
+ return next->lastSourceLocation();
+ return expression->lastSourceLocation();
+ }
+
+ inline ArgumentList *finish ()
+ {
+ ArgumentList *front = next;
+ next = 0;
+ return front;
+ }
+
+// attributes
+ ExpressionNode *expression;
+ ArgumentList *next;
+ SourceLocation commaToken;
+};
+
+class QML_PARSER_EXPORT PostIncrementExpression: public ExpressionNode
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(PostIncrementExpression)
+
+ PostIncrementExpression(ExpressionNode *b):
+ base (b) { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return base->firstSourceLocation(); }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return incrementToken; }
+
+// attributes
+ ExpressionNode *base;
+ SourceLocation incrementToken;
+};
+
+class QML_PARSER_EXPORT PostDecrementExpression: public ExpressionNode
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(PostDecrementExpression)
+
+ PostDecrementExpression(ExpressionNode *b):
+ base (b) { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return base->firstSourceLocation(); }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return decrementToken; }
+
+// attributes
+ ExpressionNode *base;
+ SourceLocation decrementToken;
+};
+
+class QML_PARSER_EXPORT DeleteExpression: public ExpressionNode
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(DeleteExpression)
+
+ DeleteExpression(ExpressionNode *e):
+ expression (e) { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return deleteToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return expression->lastSourceLocation(); }
+
+// attributes
+ ExpressionNode *expression;
+ SourceLocation deleteToken;
+};
+
+class QML_PARSER_EXPORT VoidExpression: public ExpressionNode
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(VoidExpression)
+
+ VoidExpression(ExpressionNode *e):
+ expression (e) { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return voidToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return expression->lastSourceLocation(); }
+
+// attributes
+ ExpressionNode *expression;
+ SourceLocation voidToken;
+};
+
+class QML_PARSER_EXPORT TypeOfExpression: public ExpressionNode
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(TypeOfExpression)
+
+ TypeOfExpression(ExpressionNode *e):
+ expression (e) { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return typeofToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return expression->lastSourceLocation(); }
+
+// attributes
+ ExpressionNode *expression;
+ SourceLocation typeofToken;
+};
+
+class QML_PARSER_EXPORT PreIncrementExpression: public ExpressionNode
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(PreIncrementExpression)
+
+ PreIncrementExpression(ExpressionNode *e):
+ expression (e) { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return incrementToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return expression->lastSourceLocation(); }
+
+// attributes
+ ExpressionNode *expression;
+ SourceLocation incrementToken;
+};
+
+class QML_PARSER_EXPORT PreDecrementExpression: public ExpressionNode
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(PreDecrementExpression)
+
+ PreDecrementExpression(ExpressionNode *e):
+ expression (e) { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return decrementToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return expression->lastSourceLocation(); }
+
+// attributes
+ ExpressionNode *expression;
+ SourceLocation decrementToken;
+};
+
+class QML_PARSER_EXPORT UnaryPlusExpression: public ExpressionNode
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(UnaryPlusExpression)
+
+ UnaryPlusExpression(ExpressionNode *e):
+ expression (e) { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return plusToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return expression->lastSourceLocation(); }
+
+// attributes
+ ExpressionNode *expression;
+ SourceLocation plusToken;
+};
+
+class QML_PARSER_EXPORT UnaryMinusExpression: public ExpressionNode
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(UnaryMinusExpression)
+
+ UnaryMinusExpression(ExpressionNode *e):
+ expression (e) { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return minusToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return expression->lastSourceLocation(); }
+
+// attributes
+ ExpressionNode *expression;
+ SourceLocation minusToken;
+};
+
+class QML_PARSER_EXPORT TildeExpression: public ExpressionNode
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(TildeExpression)
+
+ TildeExpression(ExpressionNode *e):
+ expression (e) { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return tildeToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return expression->lastSourceLocation(); }
+
+// attributes
+ ExpressionNode *expression;
+ SourceLocation tildeToken;
+};
+
+class QML_PARSER_EXPORT NotExpression: public ExpressionNode
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(NotExpression)
+
+ NotExpression(ExpressionNode *e):
+ expression (e) { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return notToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return expression->lastSourceLocation(); }
+
+// attributes
+ ExpressionNode *expression;
+ SourceLocation notToken;
+};
+
+class QML_PARSER_EXPORT BinaryExpression: public ExpressionNode
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(BinaryExpression)
+
+ BinaryExpression(ExpressionNode *l, int o, ExpressionNode *r):
+ left (l), op (o), right (r)
+ { kind = K; }
+
+ virtual BinaryExpression *binaryExpressionCast();
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return left->firstSourceLocation(); }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return right->lastSourceLocation(); }
+
+// attributes
+ ExpressionNode *left;
+ int op;
+ ExpressionNode *right;
+ SourceLocation operatorToken;
+};
+
+class QML_PARSER_EXPORT ConditionalExpression: public ExpressionNode
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(ConditionalExpression)
+
+ ConditionalExpression(ExpressionNode *e, ExpressionNode *t, ExpressionNode *f):
+ expression (e), ok (t), ko (f)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return expression->firstSourceLocation(); }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return ko->lastSourceLocation(); }
+
+// attributes
+ ExpressionNode *expression;
+ ExpressionNode *ok;
+ ExpressionNode *ko;
+ SourceLocation questionToken;
+ SourceLocation colonToken;
+};
+
+class QML_PARSER_EXPORT Expression: public ExpressionNode // ### rename
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(Expression)
+
+ Expression(ExpressionNode *l, ExpressionNode *r):
+ left (l), right (r) { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return left->firstSourceLocation(); }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return right->lastSourceLocation(); }
+
+// attributes
+ ExpressionNode *left;
+ ExpressionNode *right;
+ SourceLocation commaToken;
+};
+
+class QML_PARSER_EXPORT Block: public Statement
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(Block)
+
+ Block(StatementList *slist):
+ statements (slist) { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return lbraceToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return rbraceToken; }
+
+ // attributes
+ StatementList *statements;
+ SourceLocation lbraceToken;
+ SourceLocation rbraceToken;
+};
+
+class QML_PARSER_EXPORT StatementList: public Node
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(StatementList)
+
+ StatementList(Statement *stmt):
+ statement (stmt), next (this)
+ { kind = K; }
+
+ StatementList(StatementList *previous, Statement *stmt):
+ statement (stmt)
+ {
+ kind = K;
+ next = previous->next;
+ previous->next = this;
+ }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return statement->firstSourceLocation(); }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return next ? next->lastSourceLocation() : statement->lastSourceLocation(); }
+
+ inline StatementList *finish ()
+ {
+ StatementList *front = next;
+ next = 0;
+ return front;
+ }
+
+// attributes
+ Statement *statement;
+ StatementList *next;
+};
+
+class QML_PARSER_EXPORT VariableStatement: public Statement
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(VariableStatement)
+
+ VariableStatement(VariableDeclarationList *vlist):
+ declarations (vlist)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return declarationKindToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return semicolonToken; }
+
+// attributes
+ VariableDeclarationList *declarations;
+ SourceLocation declarationKindToken;
+ SourceLocation semicolonToken;
+};
+
+class QML_PARSER_EXPORT VariableDeclaration: public Node
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(VariableDeclaration)
+
+ VariableDeclaration(const QStringRef &n, ExpressionNode *e):
+ name (n), expression (e), readOnly(false)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return identifierToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return expression ? expression->lastSourceLocation() : identifierToken; }
+
+// attributes
+ QStringRef name;
+ ExpressionNode *expression;
+ bool readOnly;
+ SourceLocation identifierToken;
+};
+
+class QML_PARSER_EXPORT VariableDeclarationList: public Node
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(VariableDeclarationList)
+
+ VariableDeclarationList(VariableDeclaration *decl):
+ declaration (decl), next (this)
+ { kind = K; }
+
+ VariableDeclarationList(VariableDeclarationList *previous, VariableDeclaration *decl):
+ declaration (decl)
+ {
+ kind = K;
+ next = previous->next;
+ previous->next = this;
+ }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return declaration->firstSourceLocation(); }
+
+ virtual SourceLocation lastSourceLocation() const
+ {
+ if (next)
+ return next->lastSourceLocation();
+ return declaration->lastSourceLocation();
+ }
+
+ inline VariableDeclarationList *finish (bool readOnly)
+ {
+ VariableDeclarationList *front = next;
+ next = 0;
+ if (readOnly) {
+ VariableDeclarationList *vdl;
+ for (vdl = front; vdl != 0; vdl = vdl->next)
+ vdl->declaration->readOnly = true;
+ }
+ return front;
+ }
+
+// attributes
+ VariableDeclaration *declaration;
+ VariableDeclarationList *next;
+ SourceLocation commaToken;
+};
+
+class QML_PARSER_EXPORT EmptyStatement: public Statement
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(EmptyStatement)
+
+ EmptyStatement() { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return semicolonToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return semicolonToken; }
+
+// attributes
+ SourceLocation semicolonToken;
+};
+
+class QML_PARSER_EXPORT ExpressionStatement: public Statement
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(ExpressionStatement)
+
+ ExpressionStatement(ExpressionNode *e):
+ expression (e) { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return expression->firstSourceLocation(); }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return semicolonToken; }
+
+// attributes
+ ExpressionNode *expression;
+ SourceLocation semicolonToken;
+};
+
+class QML_PARSER_EXPORT IfStatement: public Statement
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(IfStatement)
+
+ IfStatement(ExpressionNode *e, Statement *t, Statement *f = 0):
+ expression (e), ok (t), ko (f)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return ifToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ {
+ if (ko)
+ return ko->lastSourceLocation();
+
+ return ok->lastSourceLocation();
+ }
+
+// attributes
+ ExpressionNode *expression;
+ Statement *ok;
+ Statement *ko;
+ SourceLocation ifToken;
+ SourceLocation lparenToken;
+ SourceLocation rparenToken;
+ SourceLocation elseToken;
+};
+
+class QML_PARSER_EXPORT DoWhileStatement: public Statement
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(DoWhileStatement)
+
+ DoWhileStatement(Statement *stmt, ExpressionNode *e):
+ statement (stmt), expression (e)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return doToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return semicolonToken; }
+
+// attributes
+ Statement *statement;
+ ExpressionNode *expression;
+ SourceLocation doToken;
+ SourceLocation whileToken;
+ SourceLocation lparenToken;
+ SourceLocation rparenToken;
+ SourceLocation semicolonToken;
+};
+
+class QML_PARSER_EXPORT WhileStatement: public Statement
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(WhileStatement)
+
+ WhileStatement(ExpressionNode *e, Statement *stmt):
+ expression (e), statement (stmt)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return whileToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return statement->lastSourceLocation(); }
+
+// attributes
+ ExpressionNode *expression;
+ Statement *statement;
+ SourceLocation whileToken;
+ SourceLocation lparenToken;
+ SourceLocation rparenToken;
+};
+
+class QML_PARSER_EXPORT ForStatement: public Statement
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(ForStatement)
+
+ ForStatement(ExpressionNode *i, ExpressionNode *c, ExpressionNode *e, Statement *stmt):
+ initialiser (i), condition (c), expression (e), statement (stmt)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return forToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return statement->lastSourceLocation(); }
+
+// attributes
+ ExpressionNode *initialiser;
+ ExpressionNode *condition;
+ ExpressionNode *expression;
+ Statement *statement;
+ SourceLocation forToken;
+ SourceLocation lparenToken;
+ SourceLocation firstSemicolonToken;
+ SourceLocation secondSemicolonToken;
+ SourceLocation rparenToken;
+};
+
+class QML_PARSER_EXPORT LocalForStatement: public Statement
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(LocalForStatement)
+
+ LocalForStatement(VariableDeclarationList *vlist, ExpressionNode *c, ExpressionNode *e, Statement *stmt):
+ declarations (vlist), condition (c), expression (e), statement (stmt)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return forToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return statement->lastSourceLocation(); }
+
+// attributes
+ VariableDeclarationList *declarations;
+ ExpressionNode *condition;
+ ExpressionNode *expression;
+ Statement *statement;
+ SourceLocation forToken;
+ SourceLocation lparenToken;
+ SourceLocation varToken;
+ SourceLocation firstSemicolonToken;
+ SourceLocation secondSemicolonToken;
+ SourceLocation rparenToken;
+};
+
+class QML_PARSER_EXPORT ForEachStatement: public Statement
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(ForEachStatement)
+
+ ForEachStatement(ExpressionNode *i, ExpressionNode *e, Statement *stmt):
+ initialiser (i), expression (e), statement (stmt)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return forToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return statement->lastSourceLocation(); }
+
+// attributes
+ ExpressionNode *initialiser;
+ ExpressionNode *expression;
+ Statement *statement;
+ SourceLocation forToken;
+ SourceLocation lparenToken;
+ SourceLocation inToken;
+ SourceLocation rparenToken;
+};
+
+class QML_PARSER_EXPORT LocalForEachStatement: public Statement
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(LocalForEachStatement)
+
+ LocalForEachStatement(VariableDeclaration *v, ExpressionNode *e, Statement *stmt):
+ declaration (v), expression (e), statement (stmt)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return forToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return statement->lastSourceLocation(); }
+
+// attributes
+ VariableDeclaration *declaration;
+ ExpressionNode *expression;
+ Statement *statement;
+ SourceLocation forToken;
+ SourceLocation lparenToken;
+ SourceLocation varToken;
+ SourceLocation inToken;
+ SourceLocation rparenToken;
+};
+
+class QML_PARSER_EXPORT ContinueStatement: public Statement
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(ContinueStatement)
+
+ ContinueStatement(const QStringRef &l = QStringRef()):
+ label (l) { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return continueToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return semicolonToken; }
+
+// attributes
+ QStringRef label;
+ SourceLocation continueToken;
+ SourceLocation identifierToken;
+ SourceLocation semicolonToken;
+};
+
+class QML_PARSER_EXPORT BreakStatement: public Statement
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(BreakStatement)
+
+ BreakStatement(const QStringRef &l):
+ label (l) { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return breakToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return semicolonToken; }
+
+ // attributes
+ QStringRef label;
+ SourceLocation breakToken;
+ SourceLocation identifierToken;
+ SourceLocation semicolonToken;
+};
+
+class QML_PARSER_EXPORT ReturnStatement: public Statement
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(ReturnStatement)
+
+ ReturnStatement(ExpressionNode *e):
+ expression (e) { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return returnToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return semicolonToken; }
+
+// attributes
+ ExpressionNode *expression;
+ SourceLocation returnToken;
+ SourceLocation semicolonToken;
+};
+
+class QML_PARSER_EXPORT WithStatement: public Statement
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(WithStatement)
+
+ WithStatement(ExpressionNode *e, Statement *stmt):
+ expression (e), statement (stmt)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return withToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return statement->lastSourceLocation(); }
+
+// attributes
+ ExpressionNode *expression;
+ Statement *statement;
+ SourceLocation withToken;
+ SourceLocation lparenToken;
+ SourceLocation rparenToken;
+};
+
+class QML_PARSER_EXPORT CaseBlock: public Node
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(CaseBlock)
+
+ CaseBlock(CaseClauses *c, DefaultClause *d = 0, CaseClauses *r = 0):
+ clauses (c), defaultClause (d), moreClauses (r)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return lbraceToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return rbraceToken; }
+
+// attributes
+ CaseClauses *clauses;
+ DefaultClause *defaultClause;
+ CaseClauses *moreClauses;
+ SourceLocation lbraceToken;
+ SourceLocation rbraceToken;
+};
+
+class QML_PARSER_EXPORT SwitchStatement: public Statement
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(SwitchStatement)
+
+ SwitchStatement(ExpressionNode *e, CaseBlock *b):
+ expression (e), block (b)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return switchToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return block->rbraceToken; }
+
+// attributes
+ ExpressionNode *expression;
+ CaseBlock *block;
+ SourceLocation switchToken;
+ SourceLocation lparenToken;
+ SourceLocation rparenToken;
+};
+
+class QML_PARSER_EXPORT CaseClause: public Node
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(CaseClause)
+
+ CaseClause(ExpressionNode *e, StatementList *slist):
+ expression (e), statements (slist)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return caseToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return statements ? statements->lastSourceLocation() : colonToken; }
+
+// attributes
+ ExpressionNode *expression;
+ StatementList *statements;
+ SourceLocation caseToken;
+ SourceLocation colonToken;
+};
+
+class QML_PARSER_EXPORT CaseClauses: public Node
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(CaseClauses)
+
+ CaseClauses(CaseClause *c):
+ clause (c), next (this)
+ { kind = K; }
+
+ CaseClauses(CaseClauses *previous, CaseClause *c):
+ clause (c)
+ {
+ kind = K;
+ next = previous->next;
+ previous->next = this;
+ }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return clause->firstSourceLocation(); }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return next ? next->lastSourceLocation() : clause->lastSourceLocation(); }
+
+ inline CaseClauses *finish ()
+ {
+ CaseClauses *front = next;
+ next = 0;
+ return front;
+ }
+
+//attributes
+ CaseClause *clause;
+ CaseClauses *next;
+};
+
+class QML_PARSER_EXPORT DefaultClause: public Node
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(DefaultClause)
+
+ DefaultClause(StatementList *slist):
+ statements (slist)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return defaultToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return statements ? statements->lastSourceLocation() : colonToken; }
+
+// attributes
+ StatementList *statements;
+ SourceLocation defaultToken;
+ SourceLocation colonToken;
+};
+
+class QML_PARSER_EXPORT LabelledStatement: public Statement
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(LabelledStatement)
+
+ LabelledStatement(const QStringRef &l, Statement *stmt):
+ label (l), statement (stmt)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return identifierToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return statement->lastSourceLocation(); }
+
+// attributes
+ QStringRef label;
+ Statement *statement;
+ SourceLocation identifierToken;
+ SourceLocation colonToken;
+};
+
+class QML_PARSER_EXPORT ThrowStatement: public Statement
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(ThrowStatement)
+
+ ThrowStatement(ExpressionNode *e):
+ expression (e) { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return throwToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return semicolonToken; }
+
+ // attributes
+ ExpressionNode *expression;
+ SourceLocation throwToken;
+ SourceLocation semicolonToken;
+};
+
+class QML_PARSER_EXPORT Catch: public Node
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(Catch)
+
+ Catch(const QStringRef &n, Block *stmt):
+ name (n), statement (stmt)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return catchToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return statement->lastSourceLocation(); }
+
+// attributes
+ QStringRef name;
+ Block *statement;
+ SourceLocation catchToken;
+ SourceLocation lparenToken;
+ SourceLocation identifierToken;
+ SourceLocation rparenToken;
+};
+
+class QML_PARSER_EXPORT Finally: public Node
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(Finally)
+
+ Finally(Block *stmt):
+ statement (stmt)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return finallyToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return statement ? statement->lastSourceLocation() : finallyToken; }
+
+// attributes
+ Block *statement;
+ SourceLocation finallyToken;
+};
+
+class QML_PARSER_EXPORT TryStatement: public Statement
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(TryStatement)
+
+ TryStatement(Statement *stmt, Catch *c, Finally *f):
+ statement (stmt), catchExpression (c), finallyExpression (f)
+ { kind = K; }
+
+ TryStatement(Statement *stmt, Finally *f):
+ statement (stmt), catchExpression (0), finallyExpression (f)
+ { kind = K; }
+
+ TryStatement(Statement *stmt, Catch *c):
+ statement (stmt), catchExpression (c), finallyExpression (0)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return tryToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ {
+ if (finallyExpression)
+ return finallyExpression->statement->rbraceToken;
+ else if (catchExpression)
+ return catchExpression->statement->rbraceToken;
+
+ return statement->lastSourceLocation();
+ }
+
+// attributes
+ Statement *statement;
+ Catch *catchExpression;
+ Finally *finallyExpression;
+ SourceLocation tryToken;
+};
+
+class QML_PARSER_EXPORT FunctionExpression: public ExpressionNode
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(FunctionExpression)
+
+ FunctionExpression(const QStringRef &n, FormalParameterList *f, FunctionBody *b):
+ name (n), formals (f), body (b)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return functionToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return rbraceToken; }
+
+// attributes
+ QStringRef name;
+ FormalParameterList *formals;
+ FunctionBody *body;
+ SourceLocation functionToken;
+ SourceLocation identifierToken;
+ SourceLocation lparenToken;
+ SourceLocation rparenToken;
+ SourceLocation lbraceToken;
+ SourceLocation rbraceToken;
+};
+
+class QML_PARSER_EXPORT FunctionDeclaration: public FunctionExpression
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(FunctionDeclaration)
+
+ FunctionDeclaration(const QStringRef &n, FormalParameterList *f, FunctionBody *b):
+ FunctionExpression(n, f, b)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+};
+
+class QML_PARSER_EXPORT FormalParameterList: public Node
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(FormalParameterList)
+
+ FormalParameterList(const QStringRef &n):
+ name (n), next (this)
+ { kind = K; }
+
+ FormalParameterList(FormalParameterList *previous, const QStringRef &n):
+ name (n)
+ {
+ kind = K;
+ next = previous->next;
+ previous->next = this;
+ }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return identifierToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return next ? next->lastSourceLocation() : identifierToken; }
+
+ inline FormalParameterList *finish ()
+ {
+ FormalParameterList *front = next;
+ next = 0;
+ return front;
+ }
+
+// attributes
+ QStringRef name;
+ FormalParameterList *next;
+ SourceLocation commaToken;
+ SourceLocation identifierToken;
+};
+
+class QML_PARSER_EXPORT SourceElement: public Node
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(SourceElement)
+
+ inline SourceElement()
+ { kind = K; }
+};
+
+class QML_PARSER_EXPORT SourceElements: public Node
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(SourceElements)
+
+ SourceElements(SourceElement *elt):
+ element (elt), next (this)
+ { kind = K; }
+
+ SourceElements(SourceElements *previous, SourceElement *elt):
+ element (elt)
+ {
+ kind = K;
+ next = previous->next;
+ previous->next = this;
+ }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return element->firstSourceLocation(); }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return next ? next->lastSourceLocation() : element->lastSourceLocation(); }
+
+ inline SourceElements *finish ()
+ {
+ SourceElements *front = next;
+ next = 0;
+ return front;
+ }
+
+// attributes
+ SourceElement *element;
+ SourceElements *next;
+};
+
+class QML_PARSER_EXPORT FunctionBody: public Node
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(FunctionBody)
+
+ FunctionBody(SourceElements *elts):
+ elements (elts)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return elements ? elements->firstSourceLocation() : SourceLocation(); }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return elements ? elements->lastSourceLocation() : SourceLocation(); }
+
+// attributes
+ SourceElements *elements;
+};
+
+class QML_PARSER_EXPORT Program: public Node
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(Program)
+
+ Program(SourceElements *elts):
+ elements (elts)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return elements ? elements->firstSourceLocation() : SourceLocation(); }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return elements ? elements->lastSourceLocation() : SourceLocation(); }
+
+// attributes
+ SourceElements *elements;
+};
+
+class QML_PARSER_EXPORT FunctionSourceElement: public SourceElement
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(FunctionSourceElement)
+
+ FunctionSourceElement(FunctionDeclaration *f):
+ declaration (f)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return declaration->firstSourceLocation(); }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return declaration->lastSourceLocation(); }
+
+// attributes
+ FunctionDeclaration *declaration;
+};
+
+class QML_PARSER_EXPORT StatementSourceElement: public SourceElement
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(StatementSourceElement)
+
+ StatementSourceElement(Statement *stmt):
+ statement (stmt)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return statement->firstSourceLocation(); }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return statement->lastSourceLocation(); }
+
+// attributes
+ Statement *statement;
+};
+
+class QML_PARSER_EXPORT DebuggerStatement: public Statement
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(DebuggerStatement)
+
+ DebuggerStatement()
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return debuggerToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return semicolonToken; }
+
+// attributes
+ SourceLocation debuggerToken;
+ SourceLocation semicolonToken;
+};
+
+class QML_PARSER_EXPORT UiQualifiedId: public Node
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(UiQualifiedId)
+
+ UiQualifiedId(const QStringRef &name)
+ : next(this), name(name)
+ { kind = K; }
+
+ UiQualifiedId(UiQualifiedId *previous, const QStringRef &name)
+ : name(name)
+ {
+ kind = K;
+ next = previous->next;
+ previous->next = this;
+ }
+
+ UiQualifiedId *finish()
+ {
+ UiQualifiedId *head = next;
+ next = 0;
+ return head;
+ }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return identifierToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return next ? next->lastSourceLocation() : identifierToken; }
+
+// attributes
+ UiQualifiedId *next;
+ QStringRef name;
+ SourceLocation identifierToken;
+};
+
+class QML_PARSER_EXPORT UiImport: public Node
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(UiImport)
+
+ UiImport(const QStringRef &fileName)
+ : fileName(fileName), importUri(0)
+ { kind = K; }
+
+ UiImport(UiQualifiedId *uri)
+ : importUri(uri)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return importToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return semicolonToken; }
+
+// attributes
+ QStringRef fileName;
+ UiQualifiedId *importUri;
+ QStringRef importId;
+ SourceLocation importToken;
+ SourceLocation fileNameToken;
+ SourceLocation versionToken;
+ SourceLocation asToken;
+ SourceLocation importIdToken;
+ SourceLocation semicolonToken;
+};
+
+class QML_PARSER_EXPORT UiImportList: public Node
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(UiImportList)
+
+ UiImportList(UiImport *import)
+ : import(import),
+ next(this)
+ { kind = K; }
+
+ UiImportList(UiImportList *previous, UiImport *import)
+ : import(import)
+ {
+ kind = K;
+ next = previous->next;
+ previous->next = this;
+ }
+
+ UiImportList *finish()
+ {
+ UiImportList *head = next;
+ next = 0;
+ return head;
+ }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return import->firstSourceLocation(); }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return next ? next->lastSourceLocation() : import->lastSourceLocation(); }
+
+// attributes
+ UiImport *import;
+ UiImportList *next;
+};
+
+class QML_PARSER_EXPORT UiObjectMember: public Node
+{
+public:
+ virtual SourceLocation firstSourceLocation() const = 0;
+ virtual SourceLocation lastSourceLocation() const = 0;
+
+ virtual UiObjectMember *uiObjectMemberCast();
+};
+
+class QML_PARSER_EXPORT UiObjectMemberList: public Node
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(UiObjectMemberList)
+
+ UiObjectMemberList(UiObjectMember *member)
+ : next(this), member(member)
+ { kind = K; }
+
+ UiObjectMemberList(UiObjectMemberList *previous, UiObjectMember *member)
+ : member(member)
+ {
+ kind = K;
+ next = previous->next;
+ previous->next = this;
+ }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return member->firstSourceLocation(); }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return next ? next->lastSourceLocation() : member->lastSourceLocation(); }
+
+ UiObjectMemberList *finish()
+ {
+ UiObjectMemberList *head = next;
+ next = 0;
+ return head;
+ }
+
+// attributes
+ UiObjectMemberList *next;
+ UiObjectMember *member;
+};
+
+class QML_PARSER_EXPORT UiProgram: public Node
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(UiProgram)
+
+ UiProgram(UiImportList *imports, UiObjectMemberList *members)
+ : imports(imports), members(members)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ {
+ if (imports)
+ return imports->firstSourceLocation();
+ else if (members)
+ return members->firstSourceLocation();
+ return SourceLocation();
+ }
+
+ virtual SourceLocation lastSourceLocation() const
+ {
+ if (members)
+ return members->lastSourceLocation();
+ else if (imports)
+ return imports->lastSourceLocation();
+ return SourceLocation();
+ }
+
+// attributes
+ UiImportList *imports;
+ UiObjectMemberList *members;
+};
+
+class QML_PARSER_EXPORT UiArrayMemberList: public Node
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(UiArrayMemberList)
+
+ UiArrayMemberList(UiObjectMember *member)
+ : next(this), member(member)
+ { kind = K; }
+
+ UiArrayMemberList(UiArrayMemberList *previous, UiObjectMember *member)
+ : member(member)
+ {
+ kind = K;
+ next = previous->next;
+ previous->next = this;
+ }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return member->firstSourceLocation(); }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return next ? next->lastSourceLocation() : member->lastSourceLocation(); }
+
+ UiArrayMemberList *finish()
+ {
+ UiArrayMemberList *head = next;
+ next = 0;
+ return head;
+ }
+
+// attributes
+ UiArrayMemberList *next;
+ UiObjectMember *member;
+ SourceLocation commaToken;
+};
+
+class QML_PARSER_EXPORT UiObjectInitializer: public Node
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(UiObjectInitializer)
+
+ UiObjectInitializer(UiObjectMemberList *members)
+ : members(members)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return lbraceToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return rbraceToken; }
+
+// attributes
+ SourceLocation lbraceToken;
+ UiObjectMemberList *members;
+ SourceLocation rbraceToken;
+};
+
+class QML_PARSER_EXPORT UiParameterList: public Node
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(UiParameterList)
+
+ UiParameterList(const QStringRef &t, const QStringRef &n):
+ type (t), name (n), next (this)
+ { kind = K; }
+
+ UiParameterList(UiParameterList *previous, const QStringRef &t, const QStringRef &n):
+ type (t), name (n)
+ {
+ kind = K;
+ next = previous->next;
+ previous->next = this;
+ }
+
+ virtual void accept0(Visitor *) {}
+
+ virtual SourceLocation firstSourceLocation() const
+ { return propertyTypeToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return next ? next->lastSourceLocation() : identifierToken; }
+
+ inline UiParameterList *finish ()
+ {
+ UiParameterList *front = next;
+ next = 0;
+ return front;
+ }
+
+// attributes
+ QStringRef type;
+ QStringRef name;
+ UiParameterList *next;
+ SourceLocation commaToken;
+ SourceLocation propertyTypeToken;
+ SourceLocation identifierToken;
+};
+
+class QML_PARSER_EXPORT UiPublicMember: public UiObjectMember
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(UiPublicMember)
+
+ UiPublicMember(const QStringRef &memberType,
+ const QStringRef &name)
+ : type(Property), memberType(memberType), name(name), statement(0), binding(0), isDefaultMember(false), isReadonlyMember(false), parameters(0)
+ { kind = K; }
+
+ UiPublicMember(const QStringRef &memberType,
+ const QStringRef &name,
+ Statement *statement)
+ : type(Property), memberType(memberType), name(name), statement(statement), binding(0), isDefaultMember(false), isReadonlyMember(false), parameters(0)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ {
+ if (defaultToken.isValid())
+ return defaultToken;
+ else if (readonlyToken.isValid())
+ return readonlyToken;
+
+ return propertyToken;
+ }
+
+ virtual SourceLocation lastSourceLocation() const
+ {
+ if (binding)
+ return binding->lastSourceLocation();
+ if (statement)
+ return statement->lastSourceLocation();
+
+ return semicolonToken;
+ }
+
+// attributes
+ enum { Signal, Property } type;
+ QStringRef typeModifier;
+ QStringRef memberType;
+ QStringRef name;
+ Statement *statement; // initialized with a JS expression
+ UiObjectMember *binding; // initialized with a QML object or array.
+ bool isDefaultMember;
+ bool isReadonlyMember;
+ UiParameterList *parameters;
+ SourceLocation defaultToken;
+ SourceLocation readonlyToken;
+ SourceLocation propertyToken;
+ SourceLocation typeModifierToken;
+ SourceLocation typeToken;
+ SourceLocation identifierToken;
+ SourceLocation colonToken;
+ SourceLocation semicolonToken;
+};
+
+class QML_PARSER_EXPORT UiObjectDefinition: public UiObjectMember
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(UiObjectDefinition)
+
+ UiObjectDefinition(UiQualifiedId *qualifiedTypeNameId,
+ UiObjectInitializer *initializer)
+ : qualifiedTypeNameId(qualifiedTypeNameId), initializer(initializer)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return qualifiedTypeNameId->identifierToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return initializer->rbraceToken; }
+
+// attributes
+ UiQualifiedId *qualifiedTypeNameId;
+ UiObjectInitializer *initializer;
+};
+
+class QML_PARSER_EXPORT UiSourceElement: public UiObjectMember
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(UiSourceElement)
+
+ UiSourceElement(Node *sourceElement)
+ : sourceElement(sourceElement)
+ { kind = K; }
+
+ virtual SourceLocation firstSourceLocation() const
+ {
+ if (FunctionDeclaration *funDecl = cast<FunctionDeclaration *>(sourceElement))
+ return funDecl->firstSourceLocation();
+ else if (VariableStatement *varStmt = cast<VariableStatement *>(sourceElement))
+ return varStmt->firstSourceLocation();
+
+ return SourceLocation();
+ }
+
+ virtual SourceLocation lastSourceLocation() const
+ {
+ if (FunctionDeclaration *funDecl = cast<FunctionDeclaration *>(sourceElement))
+ return funDecl->lastSourceLocation();
+ else if (VariableStatement *varStmt = cast<VariableStatement *>(sourceElement))
+ return varStmt->lastSourceLocation();
+
+ return SourceLocation();
+ }
+
+ virtual void accept0(Visitor *visitor);
+
+
+// attributes
+ Node *sourceElement;
+};
+
+class QML_PARSER_EXPORT UiObjectBinding: public UiObjectMember
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(UiObjectBinding)
+
+ UiObjectBinding(UiQualifiedId *qualifiedId,
+ UiQualifiedId *qualifiedTypeNameId,
+ UiObjectInitializer *initializer)
+ : qualifiedId(qualifiedId),
+ qualifiedTypeNameId(qualifiedTypeNameId),
+ initializer(initializer),
+ hasOnToken(false)
+ { kind = K; }
+
+ virtual SourceLocation firstSourceLocation() const
+ {
+ if (hasOnToken && qualifiedTypeNameId)
+ return qualifiedTypeNameId->identifierToken;
+
+ return qualifiedId->identifierToken;
+ }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return initializer->rbraceToken; }
+
+ virtual void accept0(Visitor *visitor);
+
+
+// attributes
+ UiQualifiedId *qualifiedId;
+ UiQualifiedId *qualifiedTypeNameId;
+ UiObjectInitializer *initializer;
+ SourceLocation colonToken;
+ bool hasOnToken;
+};
+
+class QML_PARSER_EXPORT UiScriptBinding: public UiObjectMember
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(UiScriptBinding)
+
+ UiScriptBinding(UiQualifiedId *qualifiedId,
+ Statement *statement)
+ : qualifiedId(qualifiedId),
+ statement(statement)
+ { kind = K; }
+
+ virtual SourceLocation firstSourceLocation() const
+ { return qualifiedId->identifierToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return statement->lastSourceLocation(); }
+
+ virtual void accept0(Visitor *visitor);
+
+// attributes
+ UiQualifiedId *qualifiedId;
+ Statement *statement;
+ SourceLocation colonToken;
+};
+
+class QML_PARSER_EXPORT UiArrayBinding: public UiObjectMember
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(UiArrayBinding)
+
+ UiArrayBinding(UiQualifiedId *qualifiedId,
+ UiArrayMemberList *members)
+ : qualifiedId(qualifiedId),
+ members(members)
+ { kind = K; }
+
+ virtual SourceLocation firstSourceLocation() const
+ { return qualifiedId->identifierToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return rbracketToken; }
+
+ virtual void accept0(Visitor *visitor);
+
+// attributes
+ UiQualifiedId *qualifiedId;
+ UiArrayMemberList *members;
+ SourceLocation colonToken;
+ SourceLocation lbracketToken;
+ SourceLocation rbracketToken;
+};
+
+} } // namespace AST
+
+
+
+QT_QML_END_NAMESPACE
+
+#endif
diff --git a/src/qml/qml/parser/qqmljsastfwd_p.h b/src/qml/qml/parser/qqmljsastfwd_p.h
new file mode 100644
index 0000000000..dec1cbc599
--- /dev/null
+++ b/src/qml/qml/parser/qqmljsastfwd_p.h
@@ -0,0 +1,186 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLJSAST_FWD_P_H
+#define QQMLJSAST_FWD_P_H
+
+#include "qqmljsglobal_p.h"
+
+#include <QtCore/qglobal.h>
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+QT_QML_BEGIN_NAMESPACE
+
+namespace QQmlJS { namespace AST {
+
+class SourceLocation
+{
+public:
+ SourceLocation(quint32 offset = 0, quint32 length = 0, quint32 line = 0, quint32 column = 0)
+ : offset(offset), length(length),
+ startLine(line), startColumn(column)
+ { }
+
+ bool isValid() const { return length != 0; }
+
+ quint32 begin() const { return offset; }
+ quint32 end() const { return offset + length; }
+
+// attributes
+ // ### encode
+ quint32 offset;
+ quint32 length;
+ quint32 startLine;
+ quint32 startColumn;
+};
+
+class Visitor;
+class Node;
+class ExpressionNode;
+class Statement;
+class ThisExpression;
+class IdentifierExpression;
+class NullExpression;
+class TrueLiteral;
+class FalseLiteral;
+class NumericLiteral;
+class StringLiteral;
+class RegExpLiteral;
+class ArrayLiteral;
+class ObjectLiteral;
+class ElementList;
+class Elision;
+class PropertyNameAndValueList;
+class PropertyName;
+class IdentifierPropertyName;
+class StringLiteralPropertyName;
+class NumericLiteralPropertyName;
+class ArrayMemberExpression;
+class FieldMemberExpression;
+class NewMemberExpression;
+class NewExpression;
+class CallExpression;
+class ArgumentList;
+class PostIncrementExpression;
+class PostDecrementExpression;
+class DeleteExpression;
+class VoidExpression;
+class TypeOfExpression;
+class PreIncrementExpression;
+class PreDecrementExpression;
+class UnaryPlusExpression;
+class UnaryMinusExpression;
+class TildeExpression;
+class NotExpression;
+class BinaryExpression;
+class ConditionalExpression;
+class Expression; // ### rename
+class Block;
+class StatementList;
+class VariableStatement;
+class VariableDeclarationList;
+class VariableDeclaration;
+class EmptyStatement;
+class ExpressionStatement;
+class IfStatement;
+class DoWhileStatement;
+class WhileStatement;
+class ForStatement;
+class LocalForStatement;
+class ForEachStatement;
+class LocalForEachStatement;
+class ContinueStatement;
+class BreakStatement;
+class ReturnStatement;
+class WithStatement;
+class SwitchStatement;
+class CaseBlock;
+class CaseClauses;
+class CaseClause;
+class DefaultClause;
+class LabelledStatement;
+class ThrowStatement;
+class TryStatement;
+class Catch;
+class Finally;
+class FunctionDeclaration;
+class FunctionExpression;
+class FormalParameterList;
+class FunctionBody;
+class Program;
+class SourceElements;
+class SourceElement;
+class FunctionSourceElement;
+class StatementSourceElement;
+class DebuggerStatement;
+class NestedExpression;
+
+// ui elements
+class UiProgram;
+class UiImportList;
+class UiImport;
+class UiPublicMember;
+class UiObjectDefinition;
+class UiObjectInitializer;
+class UiObjectBinding;
+class UiScriptBinding;
+class UiSourceElement;
+class UiArrayBinding;
+class UiObjectMember;
+class UiObjectMemberList;
+class UiArrayMemberList;
+class UiQualifiedId;
+
+} } // namespace AST
+
+QT_QML_END_NAMESPACE
+
+#endif
diff --git a/src/qml/qml/parser/qqmljsastvisitor.cpp b/src/qml/qml/parser/qqmljsastvisitor.cpp
new file mode 100644
index 0000000000..2d854dc735
--- /dev/null
+++ b/src/qml/qml/parser/qqmljsastvisitor.cpp
@@ -0,0 +1,58 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qqmljsastvisitor_p.h"
+
+QT_QML_BEGIN_NAMESPACE
+
+namespace QQmlJS { namespace AST {
+
+Visitor::Visitor()
+{
+}
+
+Visitor::~Visitor()
+{
+}
+
+} } // namespace QQmlJS::AST
+
+QT_QML_END_NAMESPACE
diff --git a/src/qml/qml/parser/qqmljsastvisitor_p.h b/src/qml/qml/parser/qqmljsastvisitor_p.h
new file mode 100644
index 0000000000..991580309d
--- /dev/null
+++ b/src/qml/qml/parser/qqmljsastvisitor_p.h
@@ -0,0 +1,329 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLJSASTVISITOR_P_H
+#define QQMLJSASTVISITOR_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 "qqmljsastfwd_p.h"
+#include "qqmljsglobal_p.h"
+
+QT_QML_BEGIN_NAMESPACE
+
+namespace QQmlJS { namespace AST {
+
+class QML_PARSER_EXPORT Visitor
+{
+public:
+ Visitor();
+ virtual ~Visitor();
+
+ virtual bool preVisit(Node *) { return true; }
+ virtual void postVisit(Node *) {}
+
+ // Ui
+ virtual bool visit(UiProgram *) { return true; }
+ virtual bool visit(UiImportList *) { return true; }
+ virtual bool visit(UiImport *) { return true; }
+ virtual bool visit(UiPublicMember *) { return true; }
+ virtual bool visit(UiSourceElement *) { return true; }
+ virtual bool visit(UiObjectDefinition *) { return true; }
+ virtual bool visit(UiObjectInitializer *) { return true; }
+ virtual bool visit(UiObjectBinding *) { return true; }
+ virtual bool visit(UiScriptBinding *) { return true; }
+ virtual bool visit(UiArrayBinding *) { return true; }
+ virtual bool visit(UiObjectMemberList *) { return true; }
+ virtual bool visit(UiArrayMemberList *) { return true; }
+ virtual bool visit(UiQualifiedId *) { return true; }
+
+ virtual void endVisit(UiProgram *) {}
+ virtual void endVisit(UiImportList *) {}
+ virtual void endVisit(UiImport *) {}
+ virtual void endVisit(UiPublicMember *) {}
+ virtual void endVisit(UiSourceElement *) {}
+ virtual void endVisit(UiObjectDefinition *) {}
+ virtual void endVisit(UiObjectInitializer *) {}
+ virtual void endVisit(UiObjectBinding *) {}
+ virtual void endVisit(UiScriptBinding *) {}
+ virtual void endVisit(UiArrayBinding *) {}
+ virtual void endVisit(UiObjectMemberList *) {}
+ virtual void endVisit(UiArrayMemberList *) {}
+ virtual void endVisit(UiQualifiedId *) {}
+
+ // QQmlJS
+ virtual bool visit(ThisExpression *) { return true; }
+ virtual void endVisit(ThisExpression *) {}
+
+ virtual bool visit(IdentifierExpression *) { return true; }
+ virtual void endVisit(IdentifierExpression *) {}
+
+ virtual bool visit(NullExpression *) { return true; }
+ virtual void endVisit(NullExpression *) {}
+
+ virtual bool visit(TrueLiteral *) { return true; }
+ virtual void endVisit(TrueLiteral *) {}
+
+ virtual bool visit(FalseLiteral *) { return true; }
+ virtual void endVisit(FalseLiteral *) {}
+
+ virtual bool visit(StringLiteral *) { return true; }
+ virtual void endVisit(StringLiteral *) {}
+
+ virtual bool visit(NumericLiteral *) { return true; }
+ virtual void endVisit(NumericLiteral *) {}
+
+ virtual bool visit(RegExpLiteral *) { return true; }
+ virtual void endVisit(RegExpLiteral *) {}
+
+ virtual bool visit(ArrayLiteral *) { return true; }
+ virtual void endVisit(ArrayLiteral *) {}
+
+ virtual bool visit(ObjectLiteral *) { return true; }
+ virtual void endVisit(ObjectLiteral *) {}
+
+ virtual bool visit(ElementList *) { return true; }
+ virtual void endVisit(ElementList *) {}
+
+ virtual bool visit(Elision *) { return true; }
+ virtual void endVisit(Elision *) {}
+
+ virtual bool visit(PropertyNameAndValueList *) { return true; }
+ virtual void endVisit(PropertyNameAndValueList *) {}
+
+ virtual bool visit(NestedExpression *) { return true; }
+ virtual void endVisit(NestedExpression *) {}
+
+ virtual bool visit(IdentifierPropertyName *) { return true; }
+ virtual void endVisit(IdentifierPropertyName *) {}
+
+ virtual bool visit(StringLiteralPropertyName *) { return true; }
+ virtual void endVisit(StringLiteralPropertyName *) {}
+
+ virtual bool visit(NumericLiteralPropertyName *) { return true; }
+ virtual void endVisit(NumericLiteralPropertyName *) {}
+
+ virtual bool visit(ArrayMemberExpression *) { return true; }
+ virtual void endVisit(ArrayMemberExpression *) {}
+
+ virtual bool visit(FieldMemberExpression *) { return true; }
+ virtual void endVisit(FieldMemberExpression *) {}
+
+ virtual bool visit(NewMemberExpression *) { return true; }
+ virtual void endVisit(NewMemberExpression *) {}
+
+ virtual bool visit(NewExpression *) { return true; }
+ virtual void endVisit(NewExpression *) {}
+
+ virtual bool visit(CallExpression *) { return true; }
+ virtual void endVisit(CallExpression *) {}
+
+ virtual bool visit(ArgumentList *) { return true; }
+ virtual void endVisit(ArgumentList *) {}
+
+ virtual bool visit(PostIncrementExpression *) { return true; }
+ virtual void endVisit(PostIncrementExpression *) {}
+
+ virtual bool visit(PostDecrementExpression *) { return true; }
+ virtual void endVisit(PostDecrementExpression *) {}
+
+ virtual bool visit(DeleteExpression *) { return true; }
+ virtual void endVisit(DeleteExpression *) {}
+
+ virtual bool visit(VoidExpression *) { return true; }
+ virtual void endVisit(VoidExpression *) {}
+
+ virtual bool visit(TypeOfExpression *) { return true; }
+ virtual void endVisit(TypeOfExpression *) {}
+
+ virtual bool visit(PreIncrementExpression *) { return true; }
+ virtual void endVisit(PreIncrementExpression *) {}
+
+ virtual bool visit(PreDecrementExpression *) { return true; }
+ virtual void endVisit(PreDecrementExpression *) {}
+
+ virtual bool visit(UnaryPlusExpression *) { return true; }
+ virtual void endVisit(UnaryPlusExpression *) {}
+
+ virtual bool visit(UnaryMinusExpression *) { return true; }
+ virtual void endVisit(UnaryMinusExpression *) {}
+
+ virtual bool visit(TildeExpression *) { return true; }
+ virtual void endVisit(TildeExpression *) {}
+
+ virtual bool visit(NotExpression *) { return true; }
+ virtual void endVisit(NotExpression *) {}
+
+ virtual bool visit(BinaryExpression *) { return true; }
+ virtual void endVisit(BinaryExpression *) {}
+
+ virtual bool visit(ConditionalExpression *) { return true; }
+ virtual void endVisit(ConditionalExpression *) {}
+
+ virtual bool visit(Expression *) { return true; }
+ virtual void endVisit(Expression *) {}
+
+ virtual bool visit(Block *) { return true; }
+ virtual void endVisit(Block *) {}
+
+ virtual bool visit(StatementList *) { return true; }
+ virtual void endVisit(StatementList *) {}
+
+ virtual bool visit(VariableStatement *) { return true; }
+ virtual void endVisit(VariableStatement *) {}
+
+ virtual bool visit(VariableDeclarationList *) { return true; }
+ virtual void endVisit(VariableDeclarationList *) {}
+
+ virtual bool visit(VariableDeclaration *) { return true; }
+ virtual void endVisit(VariableDeclaration *) {}
+
+ virtual bool visit(EmptyStatement *) { return true; }
+ virtual void endVisit(EmptyStatement *) {}
+
+ virtual bool visit(ExpressionStatement *) { return true; }
+ virtual void endVisit(ExpressionStatement *) {}
+
+ virtual bool visit(IfStatement *) { return true; }
+ virtual void endVisit(IfStatement *) {}
+
+ virtual bool visit(DoWhileStatement *) { return true; }
+ virtual void endVisit(DoWhileStatement *) {}
+
+ virtual bool visit(WhileStatement *) { return true; }
+ virtual void endVisit(WhileStatement *) {}
+
+ virtual bool visit(ForStatement *) { return true; }
+ virtual void endVisit(ForStatement *) {}
+
+ virtual bool visit(LocalForStatement *) { return true; }
+ virtual void endVisit(LocalForStatement *) {}
+
+ virtual bool visit(ForEachStatement *) { return true; }
+ virtual void endVisit(ForEachStatement *) {}
+
+ virtual bool visit(LocalForEachStatement *) { return true; }
+ virtual void endVisit(LocalForEachStatement *) {}
+
+ virtual bool visit(ContinueStatement *) { return true; }
+ virtual void endVisit(ContinueStatement *) {}
+
+ virtual bool visit(BreakStatement *) { return true; }
+ virtual void endVisit(BreakStatement *) {}
+
+ virtual bool visit(ReturnStatement *) { return true; }
+ virtual void endVisit(ReturnStatement *) {}
+
+ virtual bool visit(WithStatement *) { return true; }
+ virtual void endVisit(WithStatement *) {}
+
+ virtual bool visit(SwitchStatement *) { return true; }
+ virtual void endVisit(SwitchStatement *) {}
+
+ virtual bool visit(CaseBlock *) { return true; }
+ virtual void endVisit(CaseBlock *) {}
+
+ virtual bool visit(CaseClauses *) { return true; }
+ virtual void endVisit(CaseClauses *) {}
+
+ virtual bool visit(CaseClause *) { return true; }
+ virtual void endVisit(CaseClause *) {}
+
+ virtual bool visit(DefaultClause *) { return true; }
+ virtual void endVisit(DefaultClause *) {}
+
+ virtual bool visit(LabelledStatement *) { return true; }
+ virtual void endVisit(LabelledStatement *) {}
+
+ virtual bool visit(ThrowStatement *) { return true; }
+ virtual void endVisit(ThrowStatement *) {}
+
+ virtual bool visit(TryStatement *) { return true; }
+ virtual void endVisit(TryStatement *) {}
+
+ virtual bool visit(Catch *) { return true; }
+ virtual void endVisit(Catch *) {}
+
+ virtual bool visit(Finally *) { return true; }
+ virtual void endVisit(Finally *) {}
+
+ virtual bool visit(FunctionDeclaration *) { return true; }
+ virtual void endVisit(FunctionDeclaration *) {}
+
+ virtual bool visit(FunctionExpression *) { return true; }
+ virtual void endVisit(FunctionExpression *) {}
+
+ virtual bool visit(FormalParameterList *) { return true; }
+ virtual void endVisit(FormalParameterList *) {}
+
+ virtual bool visit(FunctionBody *) { return true; }
+ virtual void endVisit(FunctionBody *) {}
+
+ virtual bool visit(Program *) { return true; }
+ virtual void endVisit(Program *) {}
+
+ virtual bool visit(SourceElements *) { return true; }
+ virtual void endVisit(SourceElements *) {}
+
+ virtual bool visit(FunctionSourceElement *) { return true; }
+ virtual void endVisit(FunctionSourceElement *) {}
+
+ virtual bool visit(StatementSourceElement *) { return true; }
+ virtual void endVisit(StatementSourceElement *) {}
+
+ virtual bool visit(DebuggerStatement *) { return true; }
+ virtual void endVisit(DebuggerStatement *) {}
+};
+
+} } // namespace AST
+
+QT_QML_END_NAMESPACE
+
+#endif // QQMLJSASTVISITOR_P_H
diff --git a/src/qml/qml/parser/qqmljsengine_p.cpp b/src/qml/qml/parser/qqmljsengine_p.cpp
new file mode 100644
index 0000000000..459ba8d7dc
--- /dev/null
+++ b/src/qml/qml/parser/qqmljsengine_p.cpp
@@ -0,0 +1,161 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qqmljsengine_p.h"
+#include "qqmljsglobal_p.h"
+
+#include <qnumeric.h>
+#include <QHash>
+#include <QDebug>
+
+QT_QML_BEGIN_NAMESPACE
+
+namespace QQmlJS {
+
+static int toDigit(char c)
+{
+ if ((c >= '0') && (c <= '9'))
+ return c - '0';
+ else if ((c >= 'a') && (c <= 'z'))
+ return 10 + c - 'a';
+ else if ((c >= 'A') && (c <= 'Z'))
+ return 10 + c - 'A';
+ return -1;
+}
+
+double integerFromString(const char *buf, int size, int radix)
+{
+ if (size == 0)
+ return qSNaN();
+
+ double sign = 1.0;
+ int i = 0;
+ if (buf[0] == '+') {
+ ++i;
+ } else if (buf[0] == '-') {
+ sign = -1.0;
+ ++i;
+ }
+
+ if (((size-i) >= 2) && (buf[i] == '0')) {
+ if (((buf[i+1] == 'x') || (buf[i+1] == 'X'))
+ && (radix < 34)) {
+ if ((radix != 0) && (radix != 16))
+ return 0;
+ radix = 16;
+ i += 2;
+ } else {
+ if (radix == 0) {
+ radix = 8;
+ ++i;
+ }
+ }
+ } else if (radix == 0) {
+ radix = 10;
+ }
+
+ int j = i;
+ for ( ; i < size; ++i) {
+ int d = toDigit(buf[i]);
+ if ((d == -1) || (d >= radix))
+ break;
+ }
+ double result;
+ if (j == i) {
+ if (!qstrcmp(buf, "Infinity"))
+ result = qInf();
+ else
+ result = qSNaN();
+ } else {
+ result = 0;
+ double multiplier = 1;
+ for (--i ; i >= j; --i, multiplier *= radix)
+ result += toDigit(buf[i]) * multiplier;
+ }
+ result *= sign;
+ return result;
+}
+
+double integerFromString(const QString &str, int radix)
+{
+ QByteArray ba = str.trimmed().toLatin1();
+ return integerFromString(ba.constData(), ba.size(), radix);
+}
+
+
+Engine::Engine()
+ : _lexer(0)
+{ }
+
+Engine::~Engine()
+{ }
+
+void Engine::setCode(const QString &code)
+{ _code = code; }
+
+void Engine::addComment(int pos, int len, int line, int col)
+{ if (len > 0) _comments.append(QQmlJS::AST::SourceLocation(pos, len, line, col)); }
+
+QList<QQmlJS::AST::SourceLocation> Engine::comments() const
+{ return _comments; }
+
+Lexer *Engine::lexer() const
+{ return _lexer; }
+
+void Engine::setLexer(Lexer *lexer)
+{ _lexer = lexer; }
+
+MemoryPool *Engine::pool()
+{ return &_pool; }
+
+QStringRef Engine::newStringRef(const QString &text)
+{
+ const int pos = _extraCode.length();
+ _extraCode += text;
+ return _extraCode.midRef(pos, text.length());
+}
+
+QStringRef Engine::newStringRef(const QChar *chars, int size)
+{ return newStringRef(QString(chars, size)); }
+
+} // end of namespace QQmlJS
+
+QT_QML_END_NAMESPACE
diff --git a/src/qml/qml/parser/qqmljsengine_p.h b/src/qml/qml/parser/qqmljsengine_p.h
new file mode 100644
index 0000000000..3cb78de4eb
--- /dev/null
+++ b/src/qml/qml/parser/qqmljsengine_p.h
@@ -0,0 +1,126 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLJSENGINE_P_H
+#define QQMLJSENGINE_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 "qqmljsglobal_p.h"
+#include "qqmljsastfwd_p.h"
+#include "qqmljsmemorypool_p.h"
+
+#include <QString>
+#include <QSet>
+
+QT_QML_BEGIN_NAMESPACE
+
+namespace QQmlJS {
+
+class Lexer;
+class MemoryPool;
+
+class QML_PARSER_EXPORT DiagnosticMessage
+{
+public:
+ enum Kind { Warning, Error };
+
+ DiagnosticMessage()
+ : kind(Error) {}
+
+ DiagnosticMessage(Kind kind, const AST::SourceLocation &loc, const QString &message)
+ : kind(kind), loc(loc), message(message) {}
+
+ bool isWarning() const
+ { return kind == Warning; }
+
+ bool isError() const
+ { return kind == Error; }
+
+ Kind kind;
+ AST::SourceLocation loc;
+ QString message;
+};
+
+class QML_PARSER_EXPORT Engine
+{
+ Lexer *_lexer;
+ MemoryPool _pool;
+ QList<AST::SourceLocation> _comments;
+ QString _extraCode;
+ QString _code;
+
+public:
+ Engine();
+ ~Engine();
+
+ void setCode(const QString &code);
+
+ void addComment(int pos, int len, int line, int col);
+ QList<AST::SourceLocation> comments() const;
+
+ Lexer *lexer() const;
+ void setLexer(Lexer *lexer);
+
+ MemoryPool *pool();
+
+ inline QStringRef midRef(int position, int size) { return _code.midRef(position, size); }
+
+ QStringRef newStringRef(const QString &s);
+ QStringRef newStringRef(const QChar *chars, int size);
+};
+
+double integerFromString(const char *buf, int size, int radix);
+
+} // end of namespace QQmlJS
+
+QT_QML_END_NAMESPACE
+
+#endif // QQMLJSENGINE_P_H
diff --git a/src/qml/qml/parser/qqmljsglobal_p.h b/src/qml/qml/parser/qqmljsglobal_p.h
new file mode 100644
index 0000000000..81c90310ad
--- /dev/null
+++ b/src/qml/qml/parser/qqmljsglobal_p.h
@@ -0,0 +1,69 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef QQMLJSGLOBAL_P_H
+#define QQMLJSGLOBAL_P_H
+
+#include <QtCore/qglobal.h>
+
+#ifdef QT_CREATOR
+# define QT_QML_BEGIN_NAMESPACE
+# define QT_QML_END_NAMESPACE
+
+# ifdef QDECLARATIVEJS_BUILD_DIR
+# define QML_PARSER_EXPORT Q_DECL_EXPORT
+# elif QML_BUILD_STATIC_LIB
+# define QML_PARSER_EXPORT
+# else
+# define QML_PARSER_EXPORT Q_DECL_IMPORT
+# endif // QQMLJS_BUILD_DIR
+
+#else // !QT_CREATOR
+# define QT_QML_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
+# define QT_QML_END_NAMESPACE QT_END_NAMESPACE
+# if defined(QT_BUILD_QMLDEVTOOLS_LIB) || defined(QT_QMLDEVTOOLS_LIB)
+ // QmlDevTools is a static library
+# define QML_PARSER_EXPORT
+# else
+# define QML_PARSER_EXPORT Q_AUTOTEST_EXPORT
+# endif
+#endif // QT_CREATOR
+
+#endif // QQMLJSGLOBAL_P_H
diff --git a/src/qml/qml/parser/qqmljsgrammar.cpp b/src/qml/qml/parser/qqmljsgrammar.cpp
new file mode 100644
index 0000000000..f69f809ee3
--- /dev/null
+++ b/src/qml/qml/parser/qqmljsgrammar.cpp
@@ -0,0 +1,1013 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// This file was generated by qlalr - DO NOT EDIT!
+#include "qqmljsgrammar_p.h"
+
+QT_BEGIN_NAMESPACE
+
+const char *const QQmlJSGrammar::spell [] = {
+ "end of file", "&", "&&", "&=", "break", "case", "catch", ":", ",", "continue",
+ "default", "delete", "/", "/=", "do", ".", "else", "=", "==", "===",
+ "finally", "for", "function", ">=", ">", ">>", ">>=", ">>>", ">>>=", "identifier",
+ "if", "in", "instanceof", "{", "[", "<=", "(", "<", "<<", "<<=",
+ "-", "-=", "--", "new", "!", "!=", "!==", "numeric literal", "|", "|=",
+ "||", "+", "+=", "++", "?", "}", "]", "%", "%=", "return",
+ ")", ";", 0, "*", "*=", "string literal", "property", "signal", "readonly", "switch",
+ "this", "throw", "~", "try", "typeof", "var", "void", "while", "with", "^",
+ "^=", "null", "true", "false", "const", "debugger", "reserved word", "multiline string literal", "comment", "public",
+ "import", "as", "on", 0, 0, 0, 0, 0, 0, 0,
+ 0, 0};
+
+const short QQmlJSGrammar::lhs [] = {
+ 102, 102, 102, 102, 102, 102, 103, 109, 109, 112,
+ 112, 114, 113, 113, 113, 113, 113, 113, 113, 113,
+ 116, 111, 110, 119, 119, 120, 120, 121, 121, 118,
+ 107, 107, 107, 107, 123, 123, 123, 123, 123, 123,
+ 123, 107, 131, 131, 131, 132, 132, 133, 133, 107,
+ 107, 107, 107, 107, 107, 107, 107, 107, 107, 107,
+ 107, 107, 107, 107, 107, 107, 117, 117, 117, 117,
+ 117, 136, 136, 136, 136, 136, 136, 136, 136, 136,
+ 136, 136, 136, 136, 136, 136, 136, 136, 136, 122,
+ 138, 138, 138, 138, 137, 137, 140, 140, 142, 142,
+ 142, 142, 142, 142, 143, 143, 143, 143, 143, 143,
+ 143, 143, 143, 143, 143, 143, 143, 143, 143, 143,
+ 143, 143, 143, 143, 143, 143, 143, 143, 143, 143,
+ 143, 143, 143, 143, 143, 144, 144, 115, 115, 115,
+ 115, 115, 147, 147, 148, 148, 148, 148, 146, 146,
+ 149, 149, 150, 150, 151, 151, 151, 152, 152, 152,
+ 152, 152, 152, 152, 152, 152, 152, 153, 153, 153,
+ 153, 154, 154, 154, 155, 155, 155, 155, 156, 156,
+ 156, 156, 156, 156, 156, 157, 157, 157, 157, 157,
+ 157, 158, 158, 158, 158, 158, 159, 159, 159, 159,
+ 159, 160, 160, 161, 161, 162, 162, 163, 163, 164,
+ 164, 165, 165, 166, 166, 167, 167, 168, 168, 169,
+ 169, 170, 170, 171, 171, 141, 141, 172, 172, 173,
+ 173, 173, 173, 173, 173, 173, 173, 173, 173, 173,
+ 173, 105, 105, 174, 174, 175, 175, 176, 176, 104,
+ 104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
+ 104, 104, 104, 104, 124, 185, 185, 184, 184, 135,
+ 135, 186, 186, 187, 187, 189, 189, 188, 190, 193,
+ 191, 191, 194, 192, 192, 125, 126, 126, 127, 127,
+ 177, 177, 177, 177, 177, 177, 177, 178, 178, 178,
+ 178, 179, 179, 179, 179, 180, 180, 128, 129, 195,
+ 195, 198, 198, 196, 196, 199, 197, 181, 181, 181,
+ 182, 182, 130, 130, 130, 200, 201, 183, 183, 134,
+ 145, 205, 205, 202, 202, 203, 203, 206, 108, 108,
+ 207, 207, 106, 106, 204, 204, 139, 139, 208};
+
+const short QQmlJSGrammar::rhs [] = {
+ 2, 2, 2, 2, 2, 2, 2, 1, 1, 1,
+ 2, 1, 2, 2, 3, 3, 5, 5, 4, 4,
+ 2, 0, 1, 1, 2, 1, 3, 2, 3, 2,
+ 1, 5, 4, 4, 1, 1, 1, 1, 1, 1,
+ 1, 3, 1, 1, 1, 0, 1, 2, 4, 6,
+ 6, 3, 3, 7, 7, 4, 4, 5, 5, 5,
+ 6, 6, 10, 6, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 3, 3, 4, 5, 3, 4, 3, 1,
+ 1, 2, 3, 4, 1, 2, 3, 5, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 4,
+ 3, 5, 1, 2, 4, 4, 4, 3, 0, 1,
+ 1, 3, 1, 1, 1, 2, 2, 1, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 1, 3, 3,
+ 3, 1, 3, 3, 1, 3, 3, 3, 1, 3,
+ 3, 3, 3, 3, 3, 1, 3, 3, 3, 3,
+ 3, 1, 3, 3, 3, 3, 1, 3, 3, 3,
+ 3, 1, 3, 1, 3, 1, 3, 1, 3, 1,
+ 3, 1, 3, 1, 3, 1, 3, 1, 3, 1,
+ 3, 1, 5, 1, 5, 1, 3, 1, 3, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 3, 0, 1, 1, 3, 0, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 3, 1, 2, 0, 1, 3,
+ 3, 1, 1, 1, 3, 1, 3, 2, 2, 2,
+ 0, 1, 2, 0, 1, 1, 2, 2, 7, 5,
+ 7, 7, 5, 9, 10, 7, 8, 2, 2, 3,
+ 3, 2, 2, 3, 3, 3, 3, 5, 5, 3,
+ 5, 1, 2, 0, 1, 4, 3, 3, 3, 3,
+ 3, 3, 3, 3, 4, 5, 2, 2, 2, 8,
+ 8, 1, 3, 0, 1, 0, 1, 1, 1, 1,
+ 1, 2, 1, 1, 0, 1, 0, 1, 2};
+
+const short QQmlJSGrammar::action_default [] = {
+ 0, 0, 22, 0, 0, 0, 22, 0, 175, 242,
+ 206, 214, 210, 154, 226, 202, 3, 139, 73, 155,
+ 218, 222, 143, 172, 153, 158, 138, 192, 179, 0,
+ 80, 81, 76, 345, 67, 347, 0, 0, 0, 0,
+ 78, 0, 0, 74, 77, 71, 0, 0, 68, 70,
+ 69, 79, 72, 0, 75, 0, 0, 168, 0, 0,
+ 155, 174, 157, 156, 0, 0, 0, 170, 171, 169,
+ 173, 0, 203, 0, 0, 0, 0, 193, 0, 0,
+ 0, 0, 0, 0, 183, 0, 0, 0, 177, 178,
+ 176, 181, 185, 184, 182, 180, 195, 194, 196, 0,
+ 211, 0, 207, 0, 0, 149, 136, 148, 137, 105,
+ 106, 107, 132, 108, 133, 109, 110, 111, 112, 113,
+ 114, 115, 116, 117, 118, 119, 120, 121, 134, 122,
+ 123, 124, 125, 126, 127, 128, 129, 130, 131, 135,
+ 0, 0, 147, 243, 150, 0, 151, 0, 152, 146,
+ 0, 239, 232, 230, 237, 238, 236, 235, 241, 234,
+ 233, 231, 240, 227, 0, 215, 0, 0, 219, 0,
+ 0, 223, 0, 0, 149, 141, 0, 140, 0, 145,
+ 159, 0, 346, 334, 335, 0, 332, 0, 333, 0,
+ 336, 250, 257, 256, 264, 252, 0, 253, 337, 0,
+ 344, 254, 255, 260, 258, 341, 338, 343, 261, 0,
+ 272, 0, 0, 0, 0, 345, 67, 0, 347, 68,
+ 244, 286, 69, 0, 0, 0, 273, 0, 0, 262,
+ 263, 0, 251, 259, 287, 288, 331, 342, 0, 302,
+ 303, 304, 305, 0, 298, 299, 300, 301, 328, 329,
+ 0, 0, 0, 0, 0, 291, 292, 248, 246, 208,
+ 216, 212, 228, 204, 249, 0, 155, 220, 224, 197,
+ 186, 0, 0, 205, 0, 0, 0, 0, 198, 0,
+ 0, 0, 0, 0, 190, 188, 191, 189, 187, 200,
+ 199, 201, 0, 213, 0, 209, 0, 247, 155, 0,
+ 229, 244, 245, 0, 244, 0, 0, 294, 0, 0,
+ 0, 296, 0, 217, 0, 0, 221, 0, 0, 225,
+ 284, 0, 276, 285, 279, 0, 283, 0, 244, 277,
+ 0, 244, 0, 0, 295, 0, 0, 0, 297, 346,
+ 334, 0, 0, 336, 0, 330, 0, 320, 0, 0,
+ 0, 290, 0, 289, 0, 348, 0, 104, 266, 269,
+ 0, 105, 272, 108, 133, 110, 111, 76, 115, 116,
+ 67, 117, 120, 74, 77, 68, 244, 69, 79, 123,
+ 72, 125, 75, 127, 128, 273, 130, 131, 135, 0,
+ 97, 0, 0, 99, 103, 101, 88, 100, 102, 0,
+ 98, 87, 267, 265, 143, 144, 149, 0, 142, 0,
+ 319, 0, 306, 307, 0, 318, 0, 0, 0, 309,
+ 314, 312, 315, 0, 0, 313, 314, 0, 310, 0,
+ 311, 268, 317, 0, 268, 316, 0, 321, 322, 0,
+ 268, 323, 324, 0, 0, 325, 0, 0, 0, 326,
+ 327, 161, 160, 0, 0, 0, 293, 0, 0, 0,
+ 308, 281, 274, 0, 282, 278, 0, 280, 270, 0,
+ 271, 275, 91, 0, 0, 95, 82, 0, 84, 93,
+ 0, 85, 94, 96, 86, 92, 83, 0, 89, 165,
+ 163, 167, 164, 162, 166, 339, 6, 340, 4, 2,
+ 65, 90, 0, 0, 68, 70, 69, 31, 5, 0,
+ 66, 0, 45, 44, 43, 0, 0, 58, 0, 59,
+ 35, 36, 37, 38, 40, 41, 62, 39, 0, 45,
+ 0, 0, 0, 0, 0, 54, 0, 55, 0, 0,
+ 26, 0, 0, 63, 27, 0, 30, 28, 24, 0,
+ 29, 25, 0, 56, 0, 57, 143, 0, 60, 64,
+ 0, 0, 0, 0, 61, 0, 52, 46, 53, 47,
+ 0, 0, 0, 0, 49, 0, 50, 51, 48, 0,
+ 0, 143, 268, 0, 0, 42, 105, 272, 108, 133,
+ 110, 111, 76, 115, 116, 67, 117, 120, 74, 77,
+ 68, 244, 69, 79, 123, 72, 125, 75, 127, 128,
+ 273, 130, 131, 135, 0, 32, 33, 0, 34, 8,
+ 0, 10, 0, 9, 0, 1, 21, 12, 0, 13,
+ 0, 14, 0, 19, 20, 0, 15, 16, 0, 17,
+ 18, 11, 23, 7, 349};
+
+const short QQmlJSGrammar::goto_default [] = {
+ 7, 625, 207, 196, 205, 508, 496, 624, 643, 495,
+ 623, 621, 626, 22, 622, 18, 507, 549, 539, 546,
+ 541, 526, 191, 195, 197, 201, 233, 208, 230, 530,
+ 570, 569, 200, 232, 26, 474, 473, 356, 355, 9,
+ 354, 357, 107, 17, 145, 24, 13, 144, 19, 25,
+ 57, 23, 8, 28, 27, 269, 15, 263, 10, 259,
+ 12, 261, 11, 260, 20, 267, 21, 268, 14, 262,
+ 258, 299, 411, 264, 265, 202, 193, 192, 204, 203,
+ 229, 194, 360, 359, 231, 463, 462, 321, 322, 465,
+ 324, 464, 323, 419, 423, 426, 422, 421, 441, 442,
+ 185, 199, 181, 184, 198, 206, 0};
+
+const short QQmlJSGrammar::action_index [] = {
+ 404, 1275, 2411, 2411, 2509, 1000, 68, 92, 90, -102,
+ 88, 62, 60, 256, -102, 298, 86, -102, -102, 638,
+ 83, 134, 172, 219, -102, -102, -102, 454, 194, 1275,
+ -102, -102, -102, 381, -102, 2215, 1555, 1275, 1275, 1275,
+ -102, 790, 1275, -102, -102, -102, 1275, 1275, -102, -102,
+ -102, -102, -102, 1275, -102, 1275, 1275, -102, 1275, 1275,
+ 102, 217, -102, -102, 1275, 1275, 1275, -102, -102, -102,
+ 204, 1275, 304, 1275, 1275, 1275, 1275, 539, 1275, 1275,
+ 1275, 1275, 1275, 1275, 308, 1275, 1275, 1275, 103, 131,
+ 135, 308, 210, 225, 216, 308, 444, 390, 434, 1275,
+ 82, 1275, 100, 2117, 1275, 1275, -102, -102, -102, -102,
+ -102, -102, -102, -102, -102, -102, -102, -102, -102, -102,
+ -102, -102, -102, -102, -102, -102, -102, -102, -102, -102,
+ -102, -102, -102, -102, -102, -102, -102, -102, -102, -102,
+ 139, 1275, -102, -102, 91, 10, -102, 1275, -102, -102,
+ 1275, -102, -102, -102, -102, -102, -102, -102, -102, -102,
+ -102, -102, -102, -102, 1275, 26, 1275, 1275, 69, 66,
+ 1275, -102, 2117, 1275, 1275, -102, 97, -102, 44, -102,
+ -102, 67, -102, 297, 78, 24, -102, 291, -102, 36,
+ 2411, -102, -102, -102, -102, -102, 234, -102, -102, 12,
+ -102, -102, -102, -102, -102, -102, 2411, -102, -102, 464,
+ -102, 461, 115, 2509, 42, 381, 58, 46, 2705, 70,
+ 1275, -102, 74, 57, 1275, 65, -102, 59, 61, -102,
+ -102, 367, -102, -102, -102, -102, -102, -102, 106, -102,
+ -102, -102, -102, 87, -102, -102, -102, -102, -102, -102,
+ 56, 55, 1275, 99, 84, -102, -102, 1461, -102, 75,
+ 48, 52, -102, 306, 72, 53, 579, 77, 110, 370,
+ 230, 381, 1275, 286, 1275, 1275, 1275, 1275, 380, 1275,
+ 1275, 1275, 1275, 1275, 184, 169, 166, 190, 198, 460,
+ 363, 353, 1275, 50, 1275, 63, 1275, -102, 638, 1275,
+ -102, 1275, 64, 39, 1275, 30, 2509, -102, 1275, 173,
+ 2509, -102, 1275, 79, 1275, 1275, 81, 80, 1275, -102,
+ 71, 149, 32, -102, -102, 1275, -102, 381, 1275, -102,
+ 73, 1275, 76, 2509, -102, 1275, 142, 2509, -102, -16,
+ 381, -42, -12, 2411, -39, -102, 2509, -102, 1275, 154,
+ 2509, 14, 2509, -102, 20, 16, -32, -102, -102, 2509,
+ -51, 519, -4, 511, 136, 1275, 2509, -2, -35, 395,
+ -1, -27, 908, 4, 6, -102, 1370, -102, 0, -36,
+ 27, 1275, 47, 22, 1275, 45, 1275, 21, 17, 1275,
+ -102, 2313, 144, -102, -102, -102, -102, -102, -102, 1275,
+ -102, -102, -102, -102, 274, -102, 1275, -21, -102, 2509,
+ -102, 138, -102, -102, 2509, -102, 1275, 132, 5, -102,
+ 40, -102, 41, 101, 1275, -102, 38, 34, -102, -38,
+ -102, 2509, -102, 105, 2509, -102, 245, -102, -102, 96,
+ 2509, 11, -102, -7, -11, -102, 352, 8, 18, -102,
+ -102, -102, -102, 1275, 129, 2509, -102, 1275, 130, 2509,
+ -102, 49, -102, 226, -102, -102, 1275, -102, -102, 362,
+ -102, -102, -102, 107, 1837, -102, -102, 1649, -102, -102,
+ 1743, -102, -102, -102, -102, -102, -102, 114, -102, -102,
+ -102, -102, -102, -102, -102, -102, -102, 2411, -102, -102,
+ -102, 94, 9, 818, 189, -10, 31, -102, -102, 223,
+ -102, 191, -102, -102, -102, 300, 178, -102, 1928, -102,
+ -102, -102, -102, -102, -102, -102, -102, -102, 257, -25,
+ 381, 195, -22, 305, 240, -102, -6, -102, 818, 127,
+ -102, -18, 818, -102, -102, 1184, -102, -102, -102, 1092,
+ -102, -102, 237, -102, 1928, -102, 294, -8, -102, -102,
+ 176, 381, 19, 1928, -102, 165, -102, 174, -102, 2,
+ -52, 381, 183, 381, -102, 117, -102, -102, -102, 2019,
+ 880, 285, 2607, 1555, 3, -102, 522, 35, 453, 108,
+ 1275, 2509, 51, 23, 475, 54, -17, 700, 7, 43,
+ -102, 1370, -102, 28, -3, 33, 1275, 37, 15, 1275,
+ 25, 1275, 1, 13, 124, -102, -102, 29, -102, -102,
+ 728, -102, 250, -43, 627, -102, -102, 231, 372, -102,
+ 222, -102, 111, -102, -102, 381, -102, -102, 104, -102,
+ -102, -102, -102, -102, -102,
+
+ -107, 9, -103, 2, 5, 266, 1, -107, -107, -107,
+ -107, -107, -107, -107, -107, -107, -107, -107, -107, -39,
+ -107, -107, -107, -107, -107, -107, -107, -107, -107, 86,
+ -107, -107, -107, 8, -107, -107, -22, 19, 71, 174,
+ -107, 186, 171, -107, -107, -107, 184, 178, -107, -107,
+ -107, -107, -107, 144, -107, 124, 150, -107, 165, 161,
+ -107, -107, -107, -107, 156, 160, 157, -107, -107, -107,
+ -107, 147, -107, 142, 135, 179, 166, -107, 177, 170,
+ 117, 72, 134, 92, -107, 75, 94, 66, -107, -107,
+ -107, -107, -107, -107, -107, -107, -107, -107, -107, 181,
+ -107, 106, -107, 143, 78, 55, -107, -107, -107, -107,
+ -107, -107, -107, -107, -107, -107, -107, -107, -107, -107,
+ -107, -107, -107, -107, -107, -107, -107, -107, -107, -107,
+ -107, -107, -107, -107, -107, -107, -107, -107, -107, -107,
+ -107, -5, -107, -107, -107, -107, -107, 54, -107, -107,
+ 51, -107, -107, -107, -107, -107, -107, -107, -107, -107,
+ -107, -107, -107, -107, 114, -107, 113, 38, -107, -107,
+ 41, -107, 231, 63, 112, -107, -107, -107, -107, -107,
+ -107, -107, -107, 30, -107, -107, -107, 52, -107, -107,
+ -107, -107, -107, -107, -107, -107, -107, -107, -107, -107,
+ -107, -107, -107, -107, -107, -107, 36, -107, -107, 45,
+ -107, 42, -107, 40, -107, 80, -107, -107, 77, -107,
+ 88, -107, -107, -107, 83, 74, -107, -107, -107, -107,
+ -107, -10, -107, -107, -107, -107, -107, -107, -107, -107,
+ -107, -107, -107, -107, -107, -107, -107, -107, -107, -107,
+ -107, -107, 23, -107, -107, -107, -107, 100, -107, -107,
+ -107, -107, -107, -107, -107, -107, -107, -107, -107, -107,
+ -107, 4, 223, -107, 230, 236, 222, 205, -107, 127,
+ 125, 115, 96, 102, -107, -107, -107, -107, -107, -107,
+ -107, -107, 234, -107, 215, -107, 199, -107, -107, 197,
+ -107, 190, -107, -107, 163, -107, 90, -107, 0, -107,
+ -1, -107, 203, -107, 189, 211, -107, -107, 195, -107,
+ -107, -107, -107, -107, -107, 191, -107, 98, 119, -107,
+ -107, 95, -107, 81, -107, 79, -107, 82, -107, -107,
+ 101, -107, -107, -16, -107, -107, 53, -107, 46, -107,
+ 57, -107, 59, -107, -107, -107, -107, -107, -107, 35,
+ -107, 33, -107, 39, -107, 89, 67, -107, -107, 58,
+ -107, -107, 84, -107, -107, -107, 73, -107, -107, -107,
+ -107, 65, -107, 43, 93, -107, 109, -107, -107, 49,
+ -107, 47, -107, -107, -107, -107, -107, -107, -107, 50,
+ -107, -107, -107, -107, -107, -107, 108, -107, -107, 61,
+ -107, -107, -107, -107, 62, -107, 68, -107, -107, -107,
+ -107, -107, -23, -107, 69, -107, -19, -107, -107, -107,
+ -107, 97, -107, -107, 99, -107, -107, -107, -107, -107,
+ 60, -61, -107, -107, 34, -107, 37, -107, 29, -107,
+ -107, -107, -107, 32, -107, 76, -107, 44, -107, 56,
+ -107, -107, -107, -107, -107, -107, 31, -107, -107, 116,
+ -107, -107, -107, -107, -6, -107, -107, 70, -107, -107,
+ 64, -107, -107, -107, -107, -107, -107, -107, -107, -107,
+ -107, -107, -107, -107, -107, -107, -107, 193, -107, -107,
+ -107, -107, -107, 7, -107, -107, -107, -107, -107, -107,
+ -107, -20, -107, -107, -107, -7, -107, -107, 290, -107,
+ -107, -107, -107, -107, -107, -107, -107, -107, -107, -107,
+ -2, -25, -107, -15, -107, -107, -107, -107, 172, -107,
+ -107, -107, 287, -107, -107, 288, -107, -107, -107, 291,
+ -107, -107, -107, -107, 336, -107, -107, 20, -107, -107,
+ 15, 3, -107, 304, -107, -107, -107, 24, -107, -107,
+ -107, 28, 21, 26, -107, -107, -107, -107, -107, 320,
+ 104, -107, 13, 381, -3, -107, 6, -107, 10, -107,
+ 167, 22, -107, -107, 12, -107, -107, 87, -107, -107,
+ -107, 25, -107, -107, -107, -107, 11, -107, 14, 85,
+ -107, 121, -107, -107, -107, -107, -107, 27, -107, -107,
+ 17, -107, -107, 18, 91, -107, -107, -107, 16, -107,
+ -107, -107, -107, -107, -107, -4, -107, -107, -107, -107,
+ -107, -107, -107, -107, -107};
+
+const short QQmlJSGrammar::action_info [] = {
+ 416, 257, 533, -132, 403, -113, 346, -102, 575, 348,
+ 572, -121, 531, -103, -121, 545, 345, 430, 342, 348,
+ 340, 343, 440, 401, 391, 545, 563, 389, 538, 446,
+ 352, 444, -129, 416, -124, -102, 545, 453, 420, 408,
+ -124, 431, -132, 424, -126, 424, 424, 620, 440, 457,
+ -103, 440, -129, 457, -126, 440, 560, 453, -113, 257,
+ 565, 346, 545, 335, 272, 346, 466, 236, 448, 190,
+ 149, 164, 141, 170, 99, 511, 272, 409, 257, 312,
+ 296, 414, 348, 312, 189, 164, 187, 318, 325, 71,
+ 306, 252, 644, 416, 141, 453, 292, 457, 440, 147,
+ 304, 71, 443, 183, 179, 141, 0, 141, 0, 172,
+ 99, 427, 434, 141, 301, 477, 444, 0, 0, 0,
+ 0, 0, 141, 0, 0, 0, 0, 292, 173, 294,
+ 58, 294, 542, 251, 331, 542, 333, 141, 141, 101,
+ 141, 59, 0, 58, 62, 256, 255, 141, 247, 246,
+ 141, 399, 0, 177, 59, 63, 428, 327, 620, 254,
+ 314, 101, 141, 478, 315, 640, 639, 242, 241, 249,
+ 248, 58, 634, 633, 488, 58, 249, 248, 577, 576,
+ 615, 141, 59, 543, 166, 518, 59, 172, 167, 455,
+ 459, 85, 418, 86, 85, 142, 86, 249, 248, 413,
+ 412, 567, 337, 512, 87, 512, 173, 87, 174, 85,
+ 328, 86, 512, 0, 350, 85, 64, 86, 529, 85,
+ 512, 86, 87, 85, 512, 86, 568, 566, 87, 64,
+ 579, 64, 87, 310, 469, 85, 87, 86, 0, 519,
+ 517, 85, 141, 86, 554, 0, 172, 536, 87, 514,
+ 85, 514, 86, 141, 87, 85, 545, 86, 514, 0,
+ 513, 65, 513, 87, 514, 173, 514, 66, 87, 513,
+ 514, 103, 172, 0, 65, 513, 65, 513, 0, 0,
+ 66, 513, 66, 637, 636, 0, 0, 470, 468, 172,
+ 104, 173, 105, 406, 0, 235, 234, 630, 555, 553,
+ 172, 537, 535, 0, 274, 275, 438, 437, 173, 172,
+ 406, 631, 629, 635, 0, 580, 73, 74, -90, 173,
+ 34, 174, 73, 74, 274, 275, 34, -90, 173, 34,
+ 174, 276, 277, 85, 34, 86, 0, 0, 0, 0,
+ 0, 628, 0, 75, 76, 0, 87, 0, 0, 75,
+ 76, 276, 277, 0, 0, 0, 0, 48, 50, 49,
+ 0, 0, 0, 48, 50, 49, 48, 50, 49, 0,
+ 0, 48, 50, 49, 0, 0, 279, 280, 0, 0,
+ 0, 34, 0, 45, 0, 281, 279, 280, 282, 45,
+ 283, 34, 45, 279, 280, 281, 34, 45, 282, 0,
+ 283, 34, 281, 279, 280, 282, 0, 283, 0, 0,
+ 34, 0, 281, 78, 79, 282, 0, 283, 48, 50,
+ 49, 80, 81, 0, 34, 82, 0, 83, 48, 50,
+ 49, -345, 0, 48, 50, 49, 0, 0, 48, 50,
+ 49, 0, 0, 0, 45, 0, 0, 48, 50, 49,
+ 0, 0, 0, 0, 45, 0, 0, 78, 79, 45,
+ 0, 48, 50, 49, 45, 80, 81, 78, 79, 82,
+ 0, 83, 0, 45, 0, 80, 81, 78, 79, 82,
+ 0, 83, 34, 279, 280, 80, 81, 45, 0, 82,
+ 34, 83, 281, 34, 0, 282, 0, 283, 6, 5,
+ 4, 1, 3, 2, 34, 0, 0, 0, 0, 0,
+ 0, -345, 0, 0, 245, 244, 0, 0, 0, 48,
+ 50, 49, 245, 244, 0, 240, 239, 48, 50, 49,
+ 48, 50, 49, 0, 0, 0, 0, 0, 0, 0,
+ 34, 48, 50, 49, 0, 45, 0, 0, 34, 0,
+ 0, 34, 0, 45, 0, 0, 45, 0, 0, 0,
+ 0, 0, 78, 79, 0, 0, 0, 45, 0, 0,
+ 80, 81, 245, 244, 82, 0, 83, 48, 50, 49,
+ 240, 239, 151, 240, 239, 48, 50, 49, 48, 50,
+ 49, 0, 152, 0, 0, 0, 153, 0, 0, 0,
+ 0, 0, 0, 45, 0, 154, 0, 155, 0, 0,
+ 308, 45, 0, 0, 45, 0, 0, 0, 156, 0,
+ 157, 62, 0, 0, 0, 0, 0, 0, 158, 0,
+ 0, 159, 63, 0, 0, 0, 0, 160, 0, 30,
+ 31, 151, 0, 161, 0, 0, 0, 0, 0, 33,
+ 0, 152, 0, 0, 0, 153, 34, 0, 0, 162,
+ 35, 36, 0, 37, 154, 0, 155, 0, 0, 0,
+ 503, 0, 0, 0, 44, 0, 0, 156, 0, 157,
+ 62, 0, 0, 0, 0, 0, 0, 158, 0, 0,
+ 159, 63, 51, 48, 50, 49, 160, 52, 0, 0,
+ 0, 0, 161, 0, 0, 0, 0, 0, 43, 54,
+ 32, 0, 30, 31, 40, 0, 0, 0, 162, 45,
+ 0, 0, 33, 0, 0, 0, 0, 0, 0, 34,
+ 0, 0, 0, 35, 36, 0, 37, 0, 0, 0,
+ 30, 31, 0, 41, 0, 0, 0, 44, 0, 0,
+ 33, 0, 0, 0, 0, 0, 0, 34, 0, 0,
+ 0, 35, 36, 0, 37, 51, 48, 50, 49, 0,
+ 52, 503, 0, 0, 0, 44, 0, 0, 0, 0,
+ 0, 43, 54, 32, 0, 0, 0, 40, 0, 0,
+ 0, 0, 45, 51, 48, 50, 49, 0, 52, 0,
+ 0, 0, 30, 31, 0, 0, 0, 0, 0, 43,
+ 54, 32, 33, 0, 0, 40, 0, 0, 0, 34,
+ 45, 0, 0, 35, 36, 0, 37, 0, 0, 0,
+ 30, 31, 0, 41, 0, 0, 0, 44, 0, 0,
+ 33, 0, 0, 0, 0, 0, 0, 34, 0, 0,
+ 0, 35, 36, 0, 37, 51, 48, 50, 49, 0,
+ 52, 503, 0, 0, 0, 44, 0, 0, 0, 0,
+ 0, 43, 54, 32, 0, 0, 0, 40, 0, 0,
+ 0, 0, 45, 51, 48, 50, 49, 0, 52, 0,
+ 0, 0, 30, 31, 0, 0, 0, 0, 0, 43,
+ 54, 32, 33, 0, 0, 40, 0, 0, 0, 34,
+ 45, 0, 0, 35, 36, 0, 37, 0, 0, 0,
+ 30, 31, 0, 503, 0, 0, 0, 44, 0, 0,
+ 33, 0, 0, 0, 0, 0, 0, 34, 0, 0,
+ 0, 35, 36, 0, 37, 51, 48, 50, 49, 0,
+ 52, 41, 0, 0, 0, 44, 0, 0, 0, 0,
+ 0, 43, 54, 32, 0, 0, 0, 40, 0, 0,
+ 0, 0, 45, 51, 48, 50, 49, 0, 52, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 43,
+ 54, 32, 0, 0, 0, 40, 0, 0, 0, 0,
+ 45, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 502, 0, 30, 31, 0, 0, 0, 0, 0, 0,
+ 0, 0, 215, 0, 0, 0, 0, 0, 0, 34,
+ 0, 0, 0, 35, 36, 0, 37, 0, 0, 0,
+ 0, 0, 0, 503, 0, 0, 0, 44, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 51, 504, 506, 505, 0,
+ 52, 0, 0, 0, 0, 226, 0, 0, 0, 0,
+ 0, 43, 54, 32, 210, 0, 0, 40, 0, 0,
+ 0, 0, 45, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 502, 0, 30, 31, 0, 0, 0, 0,
+ 0, 0, 0, 0, 215, 0, 0, 0, 0, 0,
+ 0, 34, 0, 0, 0, 35, 36, 0, 37, 0,
+ 0, 0, 0, 0, 0, 503, 0, 0, 0, 44,
+ 0, 0, 0, 0, 0, 0, 0, 550, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 51, 504, 506,
+ 505, 0, 52, 0, 0, 0, 0, 226, 0, 0,
+ 0, 0, 0, 43, 54, 32, 210, 0, 0, 40,
+ 0, 0, 0, 0, 45, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 502, 0, 30, 31, 0, 0,
+ 0, 0, 0, 0, 0, 0, 215, 0, 0, 0,
+ 0, 0, 0, 34, 0, 0, 0, 35, 36, 0,
+ 37, 0, 0, 0, 0, 0, 0, 503, 0, 0,
+ 0, 44, 0, 0, 0, 0, 0, 0, 0, 547,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 51,
+ 504, 506, 505, 0, 52, 0, 0, 0, 0, 226,
+ 0, 0, 0, 0, 0, 43, 54, 32, 210, 0,
+ 0, 40, 0, 0, 0, 0, 45, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 29, 30, 31, 0,
+ 0, 0, 0, 0, 0, 0, 0, 33, 0, 0,
+ 0, 0, 0, 0, 34, 0, 0, 0, 35, 36,
+ 0, 37, 0, 0, 0, 38, 0, 39, 41, 42,
+ 0, 0, 44, 0, 0, 0, 46, 0, 47, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 51, 48, 50, 49, 0, 52, 0, 53, 0, 55,
+ 0, 56, 0, 0, 0, 0, 43, 54, 32, 0,
+ 0, 0, 40, 0, 0, 0, 0, 45, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, -122, 0, 0,
+ 0, 29, 30, 31, 0, 0, 0, 0, 0, 0,
+ 0, 0, 33, 0, 0, 0, 0, 0, 0, 34,
+ 0, 0, 0, 35, 36, 0, 37, 0, 0, 0,
+ 38, 0, 39, 41, 42, 0, 0, 44, 0, 0,
+ 0, 46, 0, 47, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 51, 48, 50, 49, 0,
+ 52, 0, 53, 0, 55, 0, 56, 0, 0, 0,
+ 0, 43, 54, 32, 0, 0, 0, 40, 0, 0,
+ 0, 0, 45, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 29, 30, 31, 0, 0, 0, 0, 0,
+ 0, 0, 0, 33, 0, 0, 0, 0, 0, 0,
+ 34, 0, 0, 0, 35, 36, 0, 37, 0, 0,
+ 0, 38, 0, 39, 41, 42, 0, 0, 44, 0,
+ 0, 0, 46, 0, 47, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 51, 48, 50, 49,
+ 0, 52, 0, 53, 0, 55, 271, 56, 0, 0,
+ 0, 0, 43, 54, 32, 0, 0, 0, 40, 0,
+ 0, 0, 0, 45, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 475, 0, 0, 29, 30, 31, 0,
+ 0, 0, 0, 0, 0, 0, 0, 33, 0, 0,
+ 0, 0, 0, 0, 34, 0, 0, 0, 35, 36,
+ 0, 37, 0, 0, 0, 38, 0, 39, 41, 42,
+ 0, 0, 44, 0, 0, 0, 46, 0, 47, 0,
+ 0, 476, 0, 0, 0, 0, 0, 0, 0, 0,
+ 51, 48, 50, 49, 0, 52, 0, 53, 0, 55,
+ 0, 56, 0, 0, 0, 0, 43, 54, 32, 0,
+ 0, 0, 40, 0, 0, 0, 0, 45, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 475, 0, 0,
+ 29, 30, 31, 0, 0, 0, 0, 0, 0, 0,
+ 0, 33, 0, 0, 0, 0, 0, 0, 34, 0,
+ 0, 0, 35, 36, 0, 37, 0, 0, 0, 38,
+ 0, 39, 41, 42, 0, 0, 44, 0, 0, 0,
+ 46, 0, 47, 0, 0, 481, 0, 0, 0, 0,
+ 0, 0, 0, 0, 51, 48, 50, 49, 0, 52,
+ 0, 53, 0, 55, 0, 56, 0, 0, 0, 0,
+ 43, 54, 32, 0, 0, 0, 40, 0, 0, 0,
+ 0, 45, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 483, 0, 0, 29, 30, 31, 0, 0, 0,
+ 0, 0, 0, 0, 0, 33, 0, 0, 0, 0,
+ 0, 0, 34, 0, 0, 0, 35, 36, 0, 37,
+ 0, 0, 0, 38, 0, 39, 41, 42, 0, 0,
+ 44, 0, 0, 0, 46, 0, 47, 0, 0, 484,
+ 0, 0, 0, 0, 0, 0, 0, 0, 51, 48,
+ 50, 49, 0, 52, 0, 53, 0, 55, 0, 56,
+ 0, 0, 0, 0, 43, 54, 32, 0, 0, 0,
+ 40, 0, 0, 0, 0, 45, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 483, 0, 0, 29, 30,
+ 31, 0, 0, 0, 0, 0, 0, 0, 0, 33,
+ 0, 0, 0, 0, 0, 0, 34, 0, 0, 0,
+ 35, 36, 0, 37, 0, 0, 0, 38, 0, 39,
+ 41, 42, 0, 0, 44, 0, 0, 0, 46, 0,
+ 47, 0, 0, 486, 0, 0, 0, 0, 0, 0,
+ 0, 0, 51, 48, 50, 49, 0, 52, 0, 53,
+ 0, 55, 0, 56, 0, 0, 0, 0, 43, 54,
+ 32, 0, 0, 0, 40, 0, 0, 0, 0, 45,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 29,
+ 30, 31, 0, 0, 0, 0, 0, 0, 0, 0,
+ 33, 0, 0, 0, 0, 0, 0, 34, 217, 0,
+ 0, 218, 36, 0, 37, 0, 0, 0, 38, 0,
+ 39, 41, 42, 0, 0, 44, 0, 0, 0, 46,
+ 0, 47, 0, 0, 0, 0, 0, 0, 0, 221,
+ 0, 0, 0, 51, 48, 50, 49, 223, 52, 0,
+ 53, 225, 55, 0, 56, 0, 228, 0, 0, 43,
+ 54, 32, 0, 0, 0, 40, 0, 0, 0, 0,
+ 45, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 29, 30, 31, 0, 0, 0, 0, 0, 0, 0,
+ 0, 33, 0, 0, 0, 0, 0, 0, 34, 217,
+ 0, 0, 582, 583, 0, 37, 0, 0, 0, 38,
+ 0, 39, 41, 42, 0, 0, 44, 0, 0, 0,
+ 46, 0, 47, 0, 0, 0, 0, 0, 0, 0,
+ 221, 0, 0, 0, 51, 48, 50, 49, 223, 52,
+ 0, 53, 225, 55, 0, 56, 0, 228, 0, 0,
+ 43, 54, 32, 0, 0, 0, 40, 0, 0, 0,
+ 0, 45, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 109, 110, 111, 0, 0, 113, 115, 116, 0,
+ 0, 117, 0, 118, 0, 0, 0, 120, 121, 122,
+ 0, 0, 0, 0, 0, 0, 34, 123, 124, 125,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 126, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 129, 0, 0, 0,
+ 0, 0, 0, 48, 50, 49, 130, 131, 132, 0,
+ 134, 135, 136, 137, 138, 139, 0, 0, 127, 133,
+ 119, 112, 114, 128, 0, 0, 0, 0, 0, 45,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 109,
+ 110, 111, 0, 0, 113, 115, 116, 0, 0, 117,
+ 0, 118, 0, 0, 0, 120, 121, 122, 0, 0,
+ 0, 0, 0, 0, 393, 123, 124, 125, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 126, 0,
+ 0, 0, 394, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 129, 0, 0, 0, 0, 0,
+ 398, 395, 397, 0, 130, 131, 132, 0, 134, 135,
+ 136, 137, 138, 139, 0, 0, 127, 133, 119, 112,
+ 114, 128, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 109, 110, 111,
+ 0, 0, 113, 115, 116, 0, 0, 117, 0, 118,
+ 0, 0, 0, 120, 121, 122, 0, 0, 0, 0,
+ 0, 0, 393, 123, 124, 125, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 126, 0, 0, 0,
+ 394, 0, 0, 0, 0, 0, 0, 0, 396, 0,
+ 0, 0, 129, 0, 0, 0, 0, 0, 398, 395,
+ 397, 0, 130, 131, 132, 0, 134, 135, 136, 137,
+ 138, 139, 0, 0, 127, 133, 119, 112, 114, 128,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 209, 0, 0, 0, 0,
+ 211, 0, 29, 30, 31, 213, 0, 0, 0, 0,
+ 0, 0, 214, 215, 0, 0, 0, 0, 0, 0,
+ 216, 217, 0, 0, 218, 36, 0, 37, 0, 0,
+ 0, 38, 0, 39, 41, 42, 0, 0, 44, 0,
+ 0, 0, 46, 0, 47, 0, 0, 0, 0, 0,
+ 220, 0, 221, 0, 0, 0, 51, 219, 222, 49,
+ 223, 52, 224, 53, 225, 55, 226, 56, 227, 228,
+ 0, 0, 43, 54, 32, 210, 212, 0, 40, 0,
+ 0, 0, 0, 45, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 209, 0, 0, 0, 0, 211, 0,
+ 29, 30, 31, 213, 0, 0, 0, 0, 0, 0,
+ 214, 33, 0, 0, 0, 0, 0, 0, 216, 217,
+ 0, 0, 218, 36, 0, 37, 0, 0, 0, 38,
+ 0, 39, 41, 42, 0, 0, 44, 0, 0, 0,
+ 46, 0, 47, 0, 0, 0, 0, 0, 220, 0,
+ 221, 0, 0, 0, 51, 219, 222, 49, 223, 52,
+ 224, 53, 225, 55, 226, 56, 227, 228, 0, 0,
+ 43, 54, 32, 210, 212, 0, 40, 0, 0, 0,
+ 0, 45, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 586, 110, 111, 0, 0, 588, 115, 590, 30,
+ 31, 591, 0, 118, 0, 0, 0, 120, 593, 594,
+ 0, 0, 0, 0, 0, 0, 595, 596, 124, 125,
+ 218, 36, 0, 37, 0, 0, 0, 38, 0, 39,
+ 597, 42, 0, 0, 599, 0, 0, 0, 46, 0,
+ 47, 0, 0, 0, 0, 0, 601, 0, 221, 0,
+ 0, 0, 603, 600, 602, 49, 604, 605, 606, 53,
+ 608, 609, 610, 611, 612, 613, 0, 0, 598, 607,
+ 592, 587, 589, 128, 40, 0, 0, 0, 0, 45,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 361,
+ 110, 111, 0, 0, 363, 115, 365, 30, 31, 366,
+ 0, 118, 0, 0, 0, 120, 368, 369, 0, 0,
+ 0, 0, 0, 0, 370, 371, 124, 125, 218, 36,
+ 0, 37, 0, 0, 0, 38, 0, 39, 372, 42,
+ 0, 0, 374, 0, 0, 0, 46, 0, 47, 0,
+ -268, 0, 0, 0, 376, 0, 221, 0, 0, 0,
+ 378, 375, 377, 49, 379, 380, 381, 53, 383, 384,
+ 385, 386, 387, 388, 0, 0, 373, 382, 367, 362,
+ 364, 128, 40, 0, 0, 0, 0, 45, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,
+
+ 534, 311, 497, 309, 532, 461, 498, 499, 516, 515,
+ 619, 638, 16, 552, 436, 358, 616, 472, 562, 320,
+ 528, 238, 487, 182, 250, 243, 253, 182, 302, 641,
+ 627, 632, 150, 485, 143, 454, 439, 402, 445, 559,
+ 237, 574, 250, 578, 561, 186, 618, 458, 238, 349,
+ 573, 449, 447, 571, 243, 347, 450, 243, 460, 351,
+ 238, 353, 358, 410, 415, 439, 176, 188, 436, 250,
+ 467, 417, 433, 182, 425, 429, 302, 169, 456, 358,
+ 171, 140, 336, 334, 338, 344, 436, 392, 390, 400,
+ 163, 302, 307, 148, 146, 339, 439, 404, 302, 358,
+ 404, 358, 0, 482, 501, 480, 0, 642, 0, 479,
+ 0, 0, 0, 320, 60, 0, 186, 501, 90, 60,
+ 60, 489, 302, 60, 617, 93, 0, 88, 0, 405,
+ 0, 461, 405, 60, 60, 451, 180, 60, 0, 180,
+ 60, 60, 60, 451, 60, 95, 89, 146, 266, 287,
+ 60, 146, 407, 270, 60, 288, 178, 60, 106, 452,
+ 0, 60, 60, 60, 102, 60, 302, 332, 286, 60,
+ 92, 452, 60, 60, 451, 60, 165, 168, 285, 432,
+ 284, 435, 60, 60, 108, 501, 329, 94, 540, 96,
+ 60, 330, 60, 302, 494, 60, 77, 237, 60, 404,
+ 452, 341, 471, 72, 60, 60, 67, 69, 60, 60,
+ 68, 0, 70, 60, 60, 60, 61, 180, 60, 60,
+ 98, 491, 60, 91, 490, 60, 60, 60, 493, 60,
+ 84, 405, 60, 97, 492, 305, 0, 60, 0, 298,
+ 0, 100, 270, 298, 270, 298, 106, 298, 270, 0,
+ 270, 60, 270, 60, 316, 0, 270, 0, 270, 298,
+ 291, 326, 303, 60, 270, 319, 313, 300, 270, 297,
+ 60, 60, 108, 175, 295, 270, 270, 290, 60, 501,
+ 273, 317, 60, 270, 60, 278, 509, 270, 0, 270,
+ 0, 289, 0, 548, 0, 293, 551, 0, 500, 510,
+ 501, 501, 0, 544, 501, 0, 0, 0, 509, 0,
+ 0, 509, 520, 521, 522, 523, 527, 524, 525, 0,
+ 500, 510, 0, 500, 510, 564, 520, 521, 522, 523,
+ 527, 524, 525, 581, 0, 0, 0, 0, 0, 0,
+ 584, 585, 520, 521, 522, 523, 527, 524, 525, 556,
+ 0, 0, 0, 0, 0, 0, 557, 558, 520, 521,
+ 522, 523, 527, 524, 525, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 556, 0, 0, 540, 0, 614,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 472, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0};
+
+const short QQmlJSGrammar::action_check [] = {
+ 36, 36, 24, 7, 55, 7, 7, 7, 60, 36,
+ 8, 7, 37, 7, 7, 33, 55, 55, 60, 36,
+ 36, 33, 33, 55, 8, 33, 7, 7, 34, 36,
+ 16, 20, 7, 36, 7, 7, 33, 36, 33, 60,
+ 7, 7, 7, 5, 7, 5, 5, 90, 33, 36,
+ 7, 33, 7, 36, 7, 33, 66, 36, 7, 36,
+ 29, 7, 33, 31, 1, 7, 17, 55, 60, 33,
+ 60, 2, 8, 7, 48, 66, 1, 7, 36, 2,
+ 8, 7, 36, 2, 60, 2, 8, 7, 17, 1,
+ 60, 36, 0, 36, 8, 36, 48, 36, 33, 8,
+ 61, 1, 6, 36, 60, 8, -1, 8, -1, 15,
+ 48, 10, 7, 8, 61, 8, 20, -1, -1, -1,
+ -1, -1, 8, -1, -1, -1, -1, 48, 34, 79,
+ 40, 79, 8, 77, 61, 8, 60, 8, 8, 79,
+ 8, 51, -1, 40, 42, 61, 62, 8, 61, 62,
+ 8, 7, -1, 56, 51, 53, 55, 8, 90, 60,
+ 50, 79, 8, 56, 54, 61, 62, 61, 62, 61,
+ 62, 40, 61, 62, 60, 40, 61, 62, 61, 62,
+ 56, 8, 51, 56, 50, 7, 51, 15, 54, 60,
+ 60, 25, 60, 27, 25, 56, 27, 61, 62, 61,
+ 62, 36, 60, 29, 38, 29, 34, 38, 36, 25,
+ 61, 27, 29, -1, 60, 25, 12, 27, 29, 25,
+ 29, 27, 38, 25, 29, 27, 61, 62, 38, 12,
+ 7, 12, 38, 60, 8, 25, 38, 27, -1, 61,
+ 62, 25, 8, 27, 7, -1, 15, 7, 38, 75,
+ 25, 75, 27, 8, 38, 25, 33, 27, 75, -1,
+ 86, 57, 86, 38, 75, 34, 75, 63, 38, 86,
+ 75, 15, 15, -1, 57, 86, 57, 86, -1, -1,
+ 63, 86, 63, 61, 62, -1, -1, 61, 62, 15,
+ 34, 34, 36, 36, -1, 61, 62, 47, 61, 62,
+ 15, 61, 62, -1, 18, 19, 61, 62, 34, 15,
+ 36, 61, 62, 91, -1, 92, 18, 19, 33, 34,
+ 29, 36, 18, 19, 18, 19, 29, 33, 34, 29,
+ 36, 45, 46, 25, 29, 27, -1, -1, -1, -1,
+ -1, 91, -1, 45, 46, -1, 38, -1, -1, 45,
+ 46, 45, 46, -1, -1, -1, -1, 66, 67, 68,
+ -1, -1, -1, 66, 67, 68, 66, 67, 68, -1,
+ -1, 66, 67, 68, -1, -1, 23, 24, -1, -1,
+ -1, 29, -1, 92, -1, 32, 23, 24, 35, 92,
+ 37, 29, 92, 23, 24, 32, 29, 92, 35, -1,
+ 37, 29, 32, 23, 24, 35, -1, 37, -1, -1,
+ 29, -1, 32, 23, 24, 35, -1, 37, 66, 67,
+ 68, 31, 32, -1, 29, 35, -1, 37, 66, 67,
+ 68, 36, -1, 66, 67, 68, -1, -1, 66, 67,
+ 68, -1, -1, -1, 92, -1, -1, 66, 67, 68,
+ -1, -1, -1, -1, 92, -1, -1, 23, 24, 92,
+ -1, 66, 67, 68, 92, 31, 32, 23, 24, 35,
+ -1, 37, -1, 92, -1, 31, 32, 23, 24, 35,
+ -1, 37, 29, 23, 24, 31, 32, 92, -1, 35,
+ 29, 37, 32, 29, -1, 35, -1, 37, 94, 95,
+ 96, 97, 98, 99, 29, -1, -1, -1, -1, -1,
+ -1, 36, -1, -1, 61, 62, -1, -1, -1, 66,
+ 67, 68, 61, 62, -1, 61, 62, 66, 67, 68,
+ 66, 67, 68, -1, -1, -1, -1, -1, -1, -1,
+ 29, 66, 67, 68, -1, 92, -1, -1, 29, -1,
+ -1, 29, -1, 92, -1, -1, 92, -1, -1, -1,
+ -1, -1, 23, 24, -1, -1, -1, 92, -1, -1,
+ 31, 32, 61, 62, 35, -1, 37, 66, 67, 68,
+ 61, 62, 3, 61, 62, 66, 67, 68, 66, 67,
+ 68, -1, 13, -1, -1, -1, 17, -1, -1, -1,
+ -1, -1, -1, 92, -1, 26, -1, 28, -1, -1,
+ 31, 92, -1, -1, 92, -1, -1, -1, 39, -1,
+ 41, 42, -1, -1, -1, -1, -1, -1, 49, -1,
+ -1, 52, 53, -1, -1, -1, -1, 58, -1, 12,
+ 13, 3, -1, 64, -1, -1, -1, -1, -1, 22,
+ -1, 13, -1, -1, -1, 17, 29, -1, -1, 80,
+ 33, 34, -1, 36, 26, -1, 28, -1, -1, -1,
+ 43, -1, -1, -1, 47, -1, -1, 39, -1, 41,
+ 42, -1, -1, -1, -1, -1, -1, 49, -1, -1,
+ 52, 53, 65, 66, 67, 68, 58, 70, -1, -1,
+ -1, -1, 64, -1, -1, -1, -1, -1, 81, 82,
+ 83, -1, 12, 13, 87, -1, -1, -1, 80, 92,
+ -1, -1, 22, -1, -1, -1, -1, -1, -1, 29,
+ -1, -1, -1, 33, 34, -1, 36, -1, -1, -1,
+ 12, 13, -1, 43, -1, -1, -1, 47, -1, -1,
+ 22, -1, -1, -1, -1, -1, -1, 29, -1, -1,
+ -1, 33, 34, -1, 36, 65, 66, 67, 68, -1,
+ 70, 43, -1, -1, -1, 47, -1, -1, -1, -1,
+ -1, 81, 82, 83, -1, -1, -1, 87, -1, -1,
+ -1, -1, 92, 65, 66, 67, 68, -1, 70, -1,
+ -1, -1, 12, 13, -1, -1, -1, -1, -1, 81,
+ 82, 83, 22, -1, -1, 87, -1, -1, -1, 29,
+ 92, -1, -1, 33, 34, -1, 36, -1, -1, -1,
+ 12, 13, -1, 43, -1, -1, -1, 47, -1, -1,
+ 22, -1, -1, -1, -1, -1, -1, 29, -1, -1,
+ -1, 33, 34, -1, 36, 65, 66, 67, 68, -1,
+ 70, 43, -1, -1, -1, 47, -1, -1, -1, -1,
+ -1, 81, 82, 83, -1, -1, -1, 87, -1, -1,
+ -1, -1, 92, 65, 66, 67, 68, -1, 70, -1,
+ -1, -1, 12, 13, -1, -1, -1, -1, -1, 81,
+ 82, 83, 22, -1, -1, 87, -1, -1, -1, 29,
+ 92, -1, -1, 33, 34, -1, 36, -1, -1, -1,
+ 12, 13, -1, 43, -1, -1, -1, 47, -1, -1,
+ 22, -1, -1, -1, -1, -1, -1, 29, -1, -1,
+ -1, 33, 34, -1, 36, 65, 66, 67, 68, -1,
+ 70, 43, -1, -1, -1, 47, -1, -1, -1, -1,
+ -1, 81, 82, 83, -1, -1, -1, 87, -1, -1,
+ -1, -1, 92, 65, 66, 67, 68, -1, 70, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, 81,
+ 82, 83, -1, -1, -1, 87, -1, -1, -1, -1,
+ 92, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 10, -1, 12, 13, -1, -1, -1, -1, -1, -1,
+ -1, -1, 22, -1, -1, -1, -1, -1, -1, 29,
+ -1, -1, -1, 33, 34, -1, 36, -1, -1, -1,
+ -1, -1, -1, 43, -1, -1, -1, 47, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 65, 66, 67, 68, -1,
+ 70, -1, -1, -1, -1, 75, -1, -1, -1, -1,
+ -1, 81, 82, 83, 84, -1, -1, 87, -1, -1,
+ -1, -1, 92, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 10, -1, 12, 13, -1, -1, -1, -1,
+ -1, -1, -1, -1, 22, -1, -1, -1, -1, -1,
+ -1, 29, -1, -1, -1, 33, 34, -1, 36, -1,
+ -1, -1, -1, -1, -1, 43, -1, -1, -1, 47,
+ -1, -1, -1, -1, -1, -1, -1, 55, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 65, 66, 67,
+ 68, -1, 70, -1, -1, -1, -1, 75, -1, -1,
+ -1, -1, -1, 81, 82, 83, 84, -1, -1, 87,
+ -1, -1, -1, -1, 92, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 10, -1, 12, 13, -1, -1,
+ -1, -1, -1, -1, -1, -1, 22, -1, -1, -1,
+ -1, -1, -1, 29, -1, -1, -1, 33, 34, -1,
+ 36, -1, -1, -1, -1, -1, -1, 43, -1, -1,
+ -1, 47, -1, -1, -1, -1, -1, -1, -1, 55,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, 65,
+ 66, 67, 68, -1, 70, -1, -1, -1, -1, 75,
+ -1, -1, -1, -1, -1, 81, 82, 83, 84, -1,
+ -1, 87, -1, -1, -1, -1, 92, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 11, 12, 13, -1,
+ -1, -1, -1, -1, -1, -1, -1, 22, -1, -1,
+ -1, -1, -1, -1, 29, -1, -1, -1, 33, 34,
+ -1, 36, -1, -1, -1, 40, -1, 42, 43, 44,
+ -1, -1, 47, -1, -1, -1, 51, -1, 53, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 65, 66, 67, 68, -1, 70, -1, 72, -1, 74,
+ -1, 76, -1, -1, -1, -1, 81, 82, 83, -1,
+ -1, -1, 87, -1, -1, -1, -1, 92, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 7, -1, -1,
+ -1, 11, 12, 13, -1, -1, -1, -1, -1, -1,
+ -1, -1, 22, -1, -1, -1, -1, -1, -1, 29,
+ -1, -1, -1, 33, 34, -1, 36, -1, -1, -1,
+ 40, -1, 42, 43, 44, -1, -1, 47, -1, -1,
+ -1, 51, -1, 53, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 65, 66, 67, 68, -1,
+ 70, -1, 72, -1, 74, -1, 76, -1, -1, -1,
+ -1, 81, 82, 83, -1, -1, -1, 87, -1, -1,
+ -1, -1, 92, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 11, 12, 13, -1, -1, -1, -1, -1,
+ -1, -1, -1, 22, -1, -1, -1, -1, -1, -1,
+ 29, -1, -1, -1, 33, 34, -1, 36, -1, -1,
+ -1, 40, -1, 42, 43, 44, -1, -1, 47, -1,
+ -1, -1, 51, -1, 53, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 65, 66, 67, 68,
+ -1, 70, -1, 72, -1, 74, 75, 76, -1, -1,
+ -1, -1, 81, 82, 83, -1, -1, -1, 87, -1,
+ -1, -1, -1, 92, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 8, -1, -1, 11, 12, 13, -1,
+ -1, -1, -1, -1, -1, -1, -1, 22, -1, -1,
+ -1, -1, -1, -1, 29, -1, -1, -1, 33, 34,
+ -1, 36, -1, -1, -1, 40, -1, 42, 43, 44,
+ -1, -1, 47, -1, -1, -1, 51, -1, 53, -1,
+ -1, 56, -1, -1, -1, -1, -1, -1, -1, -1,
+ 65, 66, 67, 68, -1, 70, -1, 72, -1, 74,
+ -1, 76, -1, -1, -1, -1, 81, 82, 83, -1,
+ -1, -1, 87, -1, -1, -1, -1, 92, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 8, -1, -1,
+ 11, 12, 13, -1, -1, -1, -1, -1, -1, -1,
+ -1, 22, -1, -1, -1, -1, -1, -1, 29, -1,
+ -1, -1, 33, 34, -1, 36, -1, -1, -1, 40,
+ -1, 42, 43, 44, -1, -1, 47, -1, -1, -1,
+ 51, -1, 53, -1, -1, 56, -1, -1, -1, -1,
+ -1, -1, -1, -1, 65, 66, 67, 68, -1, 70,
+ -1, 72, -1, 74, -1, 76, -1, -1, -1, -1,
+ 81, 82, 83, -1, -1, -1, 87, -1, -1, -1,
+ -1, 92, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 8, -1, -1, 11, 12, 13, -1, -1, -1,
+ -1, -1, -1, -1, -1, 22, -1, -1, -1, -1,
+ -1, -1, 29, -1, -1, -1, 33, 34, -1, 36,
+ -1, -1, -1, 40, -1, 42, 43, 44, -1, -1,
+ 47, -1, -1, -1, 51, -1, 53, -1, -1, 56,
+ -1, -1, -1, -1, -1, -1, -1, -1, 65, 66,
+ 67, 68, -1, 70, -1, 72, -1, 74, -1, 76,
+ -1, -1, -1, -1, 81, 82, 83, -1, -1, -1,
+ 87, -1, -1, -1, -1, 92, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 8, -1, -1, 11, 12,
+ 13, -1, -1, -1, -1, -1, -1, -1, -1, 22,
+ -1, -1, -1, -1, -1, -1, 29, -1, -1, -1,
+ 33, 34, -1, 36, -1, -1, -1, 40, -1, 42,
+ 43, 44, -1, -1, 47, -1, -1, -1, 51, -1,
+ 53, -1, -1, 56, -1, -1, -1, -1, -1, -1,
+ -1, -1, 65, 66, 67, 68, -1, 70, -1, 72,
+ -1, 74, -1, 76, -1, -1, -1, -1, 81, 82,
+ 83, -1, -1, -1, 87, -1, -1, -1, -1, 92,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, 11,
+ 12, 13, -1, -1, -1, -1, -1, -1, -1, -1,
+ 22, -1, -1, -1, -1, -1, -1, 29, 30, -1,
+ -1, 33, 34, -1, 36, -1, -1, -1, 40, -1,
+ 42, 43, 44, -1, -1, 47, -1, -1, -1, 51,
+ -1, 53, -1, -1, -1, -1, -1, -1, -1, 61,
+ -1, -1, -1, 65, 66, 67, 68, 69, 70, -1,
+ 72, 73, 74, -1, 76, -1, 78, -1, -1, 81,
+ 82, 83, -1, -1, -1, 87, -1, -1, -1, -1,
+ 92, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 11, 12, 13, -1, -1, -1, -1, -1, -1, -1,
+ -1, 22, -1, -1, -1, -1, -1, -1, 29, 30,
+ -1, -1, 33, 34, -1, 36, -1, -1, -1, 40,
+ -1, 42, 43, 44, -1, -1, 47, -1, -1, -1,
+ 51, -1, 53, -1, -1, -1, -1, -1, -1, -1,
+ 61, -1, -1, -1, 65, 66, 67, 68, 69, 70,
+ -1, 72, 73, 74, -1, 76, -1, 78, -1, -1,
+ 81, 82, 83, -1, -1, -1, 87, -1, -1, -1,
+ -1, 92, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 4, 5, 6, -1, -1, 9, 10, 11, -1,
+ -1, 14, -1, 16, -1, -1, -1, 20, 21, 22,
+ -1, -1, -1, -1, -1, -1, 29, 30, 31, 32,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 43, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 59, -1, -1, -1,
+ -1, -1, -1, 66, 67, 68, 69, 70, 71, -1,
+ 73, 74, 75, 76, 77, 78, -1, -1, 81, 82,
+ 83, 84, 85, 86, -1, -1, -1, -1, -1, 92,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, 4,
+ 5, 6, -1, -1, 9, 10, 11, -1, -1, 14,
+ -1, 16, -1, -1, -1, 20, 21, 22, -1, -1,
+ -1, -1, -1, -1, 29, 30, 31, 32, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, 43, -1,
+ -1, -1, 47, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 59, -1, -1, -1, -1, -1,
+ 65, 66, 67, -1, 69, 70, 71, -1, 73, 74,
+ 75, 76, 77, 78, -1, -1, 81, 82, 83, 84,
+ 85, 86, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 4, 5, 6,
+ -1, -1, 9, 10, 11, -1, -1, 14, -1, 16,
+ -1, -1, -1, 20, 21, 22, -1, -1, -1, -1,
+ -1, -1, 29, 30, 31, 32, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 43, -1, -1, -1,
+ 47, -1, -1, -1, -1, -1, -1, -1, 55, -1,
+ -1, -1, 59, -1, -1, -1, -1, -1, 65, 66,
+ 67, -1, 69, 70, 71, -1, 73, 74, 75, 76,
+ 77, 78, -1, -1, 81, 82, 83, 84, 85, 86,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 4, -1, -1, -1, -1,
+ 9, -1, 11, 12, 13, 14, -1, -1, -1, -1,
+ -1, -1, 21, 22, -1, -1, -1, -1, -1, -1,
+ 29, 30, -1, -1, 33, 34, -1, 36, -1, -1,
+ -1, 40, -1, 42, 43, 44, -1, -1, 47, -1,
+ -1, -1, 51, -1, 53, -1, -1, -1, -1, -1,
+ 59, -1, 61, -1, -1, -1, 65, 66, 67, 68,
+ 69, 70, 71, 72, 73, 74, 75, 76, 77, 78,
+ -1, -1, 81, 82, 83, 84, 85, -1, 87, -1,
+ -1, -1, -1, 92, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 4, -1, -1, -1, -1, 9, -1,
+ 11, 12, 13, 14, -1, -1, -1, -1, -1, -1,
+ 21, 22, -1, -1, -1, -1, -1, -1, 29, 30,
+ -1, -1, 33, 34, -1, 36, -1, -1, -1, 40,
+ -1, 42, 43, 44, -1, -1, 47, -1, -1, -1,
+ 51, -1, 53, -1, -1, -1, -1, -1, 59, -1,
+ 61, -1, -1, -1, 65, 66, 67, 68, 69, 70,
+ 71, 72, 73, 74, 75, 76, 77, 78, -1, -1,
+ 81, 82, 83, 84, 85, -1, 87, -1, -1, -1,
+ -1, 92, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 4, 5, 6, -1, -1, 9, 10, 11, 12,
+ 13, 14, -1, 16, -1, -1, -1, 20, 21, 22,
+ -1, -1, -1, -1, -1, -1, 29, 30, 31, 32,
+ 33, 34, -1, 36, -1, -1, -1, 40, -1, 42,
+ 43, 44, -1, -1, 47, -1, -1, -1, 51, -1,
+ 53, -1, -1, -1, -1, -1, 59, -1, 61, -1,
+ -1, -1, 65, 66, 67, 68, 69, 70, 71, 72,
+ 73, 74, 75, 76, 77, 78, -1, -1, 81, 82,
+ 83, 84, 85, 86, 87, -1, -1, -1, -1, 92,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, 4,
+ 5, 6, -1, -1, 9, 10, 11, 12, 13, 14,
+ -1, 16, -1, -1, -1, 20, 21, 22, -1, -1,
+ -1, -1, -1, -1, 29, 30, 31, 32, 33, 34,
+ -1, 36, -1, -1, -1, 40, -1, 42, 43, 44,
+ -1, -1, 47, -1, -1, -1, 51, -1, 53, -1,
+ 55, -1, -1, -1, 59, -1, 61, -1, -1, -1,
+ 65, 66, 67, 68, 69, 70, 71, 72, 73, 74,
+ 75, 76, 77, 78, -1, -1, 81, 82, 83, 84,
+ 85, 86, 87, -1, -1, -1, -1, 92, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1,
+
+ 15, 2, 105, 3, 29, 15, 4, 2, 15, 29,
+ 9, 15, 3, 15, 3, 2, 19, 39, 15, 15,
+ 13, 15, 3, 15, 2, 15, 3, 15, 3, 11,
+ 13, 15, 71, 39, 39, 3, 22, 2, 99, 19,
+ 4, 15, 2, 15, 29, 15, 19, 3, 15, 3,
+ 29, 22, 15, 29, 15, 2, 22, 15, 2, 2,
+ 15, 2, 2, 2, 2, 22, 3, 15, 3, 2,
+ 39, 3, 3, 15, 97, 94, 3, 39, 2, 2,
+ 39, 3, 3, 2, 2, 101, 3, 40, 39, 39,
+ 39, 3, 2, 39, 39, 15, 22, 13, 3, 2,
+ 13, 2, -1, 39, 13, 35, -1, 16, -1, 39,
+ -1, -1, -1, 15, 48, -1, 15, 13, 52, 48,
+ 48, 50, 3, 48, 20, 53, -1, 52, -1, 45,
+ -1, 15, 45, 48, 48, 50, 50, 48, -1, 50,
+ 48, 48, 48, 50, 48, 53, 52, 39, 48, 53,
+ 48, 39, 44, 53, 48, 53, 44, 48, 15, 50,
+ -1, 48, 48, 48, 58, 48, 3, 72, 53, 48,
+ 53, 50, 48, 48, 50, 48, 62, 64, 53, 82,
+ 53, 82, 48, 48, 41, 13, 88, 53, 16, 54,
+ 48, 72, 48, 3, 50, 48, 54, 4, 48, 13,
+ 50, 100, 86, 56, 48, 48, 50, 50, 48, 48,
+ 50, -1, 51, 48, 48, 48, 51, 50, 48, 48,
+ 54, 50, 48, 53, 50, 48, 48, 48, 50, 48,
+ 53, 45, 48, 54, 50, 72, -1, 48, -1, 48,
+ -1, 60, 53, 48, 53, 48, 15, 48, 53, -1,
+ 53, 48, 53, 48, 65, -1, 53, -1, 53, 48,
+ 55, 70, 72, 48, 53, 70, 63, 70, 53, 70,
+ 48, 48, 41, 42, 59, 53, 53, 55, 48, 13,
+ 57, 70, 48, 53, 48, 55, 20, 53, -1, 53,
+ -1, 55, -1, 5, -1, 61, 5, -1, 32, 33,
+ 13, 13, -1, 16, 13, -1, -1, -1, 20, -1,
+ -1, 20, 22, 23, 24, 25, 26, 27, 28, -1,
+ 32, 33, -1, 32, 33, 21, 22, 23, 24, 25,
+ 26, 27, 28, 13, -1, -1, -1, -1, -1, -1,
+ 20, 21, 22, 23, 24, 25, 26, 27, 28, 13,
+ -1, -1, -1, -1, -1, -1, 20, 21, 22, 23,
+ 24, 25, 26, 27, 28, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 13, -1, -1, 16, -1, 18,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 39, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1};
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/parser/qqmljsgrammar_p.h b/src/qml/qml/parser/qqmljsgrammar_p.h
new file mode 100644
index 0000000000..455391a862
--- /dev/null
+++ b/src/qml/qml/parser/qqmljsgrammar_p.h
@@ -0,0 +1,211 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of other Qt classes. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+// This file was generated by qlalr - DO NOT EDIT!
+#ifndef QQMLJSGRAMMAR_P_H
+#define QQMLJSGRAMMAR_P_H
+
+#include <QtCore/qglobal.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQmlJSGrammar
+{
+public:
+ enum VariousConstants {
+ EOF_SYMBOL = 0,
+ REDUCE_HERE = 101,
+ SHIFT_THERE = 100,
+ T_AND = 1,
+ T_AND_AND = 2,
+ T_AND_EQ = 3,
+ T_AS = 91,
+ T_AUTOMATIC_SEMICOLON = 62,
+ T_BREAK = 4,
+ T_CASE = 5,
+ T_CATCH = 6,
+ T_COLON = 7,
+ T_COMMA = 8,
+ T_COMMENT = 88,
+ T_CONST = 84,
+ T_CONTINUE = 9,
+ T_DEBUGGER = 85,
+ T_DEFAULT = 10,
+ T_DELETE = 11,
+ T_DIVIDE_ = 12,
+ T_DIVIDE_EQ = 13,
+ T_DO = 14,
+ T_DOT = 15,
+ T_ELSE = 16,
+ T_EQ = 17,
+ T_EQ_EQ = 18,
+ T_EQ_EQ_EQ = 19,
+ T_ERROR = 93,
+ T_FALSE = 83,
+ T_FEED_JS_EXPRESSION = 97,
+ T_FEED_JS_PROGRAM = 99,
+ T_FEED_JS_SOURCE_ELEMENT = 98,
+ T_FEED_JS_STATEMENT = 96,
+ T_FEED_UI_OBJECT_MEMBER = 95,
+ T_FEED_UI_PROGRAM = 94,
+ T_FINALLY = 20,
+ T_FOR = 21,
+ T_FUNCTION = 22,
+ T_GE = 23,
+ T_GT = 24,
+ T_GT_GT = 25,
+ T_GT_GT_EQ = 26,
+ T_GT_GT_GT = 27,
+ T_GT_GT_GT_EQ = 28,
+ T_IDENTIFIER = 29,
+ T_IF = 30,
+ T_IMPORT = 90,
+ T_IN = 31,
+ T_INSTANCEOF = 32,
+ T_LBRACE = 33,
+ T_LBRACKET = 34,
+ T_LE = 35,
+ T_LPAREN = 36,
+ T_LT = 37,
+ T_LT_LT = 38,
+ T_LT_LT_EQ = 39,
+ T_MINUS = 40,
+ T_MINUS_EQ = 41,
+ T_MINUS_MINUS = 42,
+ T_MULTILINE_STRING_LITERAL = 87,
+ T_NEW = 43,
+ T_NOT = 44,
+ T_NOT_EQ = 45,
+ T_NOT_EQ_EQ = 46,
+ T_NULL = 81,
+ T_NUMERIC_LITERAL = 47,
+ T_ON = 92,
+ T_OR = 48,
+ T_OR_EQ = 49,
+ T_OR_OR = 50,
+ T_PLUS = 51,
+ T_PLUS_EQ = 52,
+ T_PLUS_PLUS = 53,
+ T_PROPERTY = 66,
+ T_PUBLIC = 89,
+ T_QUESTION = 54,
+ T_RBRACE = 55,
+ T_RBRACKET = 56,
+ T_READONLY = 68,
+ T_REMAINDER = 57,
+ T_REMAINDER_EQ = 58,
+ T_RESERVED_WORD = 86,
+ T_RETURN = 59,
+ T_RPAREN = 60,
+ T_SEMICOLON = 61,
+ T_SIGNAL = 67,
+ T_STAR = 63,
+ T_STAR_EQ = 64,
+ T_STRING_LITERAL = 65,
+ T_SWITCH = 69,
+ T_THIS = 70,
+ T_THROW = 71,
+ T_TILDE = 72,
+ T_TRUE = 82,
+ T_TRY = 73,
+ T_TYPEOF = 74,
+ T_VAR = 75,
+ T_VOID = 76,
+ T_WHILE = 77,
+ T_WITH = 78,
+ T_XOR = 79,
+ T_XOR_EQ = 80,
+
+ ACCEPT_STATE = 644,
+ RULE_COUNT = 349,
+ STATE_COUNT = 645,
+ TERMINAL_COUNT = 102,
+ NON_TERMINAL_COUNT = 107,
+
+ GOTO_INDEX_OFFSET = 645,
+ GOTO_INFO_OFFSET = 2807,
+ GOTO_CHECK_OFFSET = 2807
+ };
+
+ static const char *const spell [];
+ static const short lhs [];
+ static const short rhs [];
+ static const short goto_default [];
+ static const short action_default [];
+ static const short action_index [];
+ static const short action_info [];
+ static const short action_check [];
+
+ static inline int nt_action (int state, int nt)
+ {
+ const int yyn = action_index [GOTO_INDEX_OFFSET + state] + nt;
+ if (yyn < 0 || action_check [GOTO_CHECK_OFFSET + yyn] != nt)
+ return goto_default [nt];
+
+ return action_info [GOTO_INFO_OFFSET + yyn];
+ }
+
+ static inline int t_action (int state, int token)
+ {
+ const int yyn = action_index [state] + token;
+
+ if (yyn < 0 || action_check [yyn] != token)
+ return - action_default [state];
+
+ return action_info [yyn];
+ }
+};
+
+
+QT_END_NAMESPACE
+#endif // QQMLJSGRAMMAR_P_H
+
diff --git a/src/qml/qml/parser/qqmljskeywords_p.h b/src/qml/qml/parser/qqmljskeywords_p.h
new file mode 100644
index 0000000000..bbcc4855a3
--- /dev/null
+++ b/src/qml/qml/parser/qqmljskeywords_p.h
@@ -0,0 +1,860 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLJSKEYWORDS_P_H
+#define QQMLJSKEYWORDS_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.
+//
+
+static inline int classify2(const QChar *s, bool qmlMode) {
+ if (s[0].unicode() == 'a') {
+ if (s[1].unicode() == 's') {
+ return qmlMode ? Lexer::T_AS : Lexer::T_RESERVED_WORD;
+ }
+ }
+ else if (s[0].unicode() == 'd') {
+ if (s[1].unicode() == 'o') {
+ return Lexer::T_DO;
+ }
+ }
+ else if (s[0].unicode() == 'i') {
+ if (s[1].unicode() == 'f') {
+ return Lexer::T_IF;
+ }
+ else if (s[1].unicode() == 'n') {
+ return Lexer::T_IN;
+ }
+ }
+ else if (qmlMode && s[0].unicode() == 'o') {
+ if (s[1].unicode() == 'n') {
+ return Lexer::T_ON;
+ }
+ }
+ return Lexer::T_IDENTIFIER;
+}
+
+static inline int classify3(const QChar *s, bool /*qmlMode*/) {
+ if (s[0].unicode() == 'f') {
+ if (s[1].unicode() == 'o') {
+ if (s[2].unicode() == 'r') {
+ return Lexer::T_FOR;
+ }
+ }
+ }
+ else if (s[0].unicode() == 'i') {
+ if (s[1].unicode() == 'n') {
+ if (s[2].unicode() == 't') {
+ return Lexer::T_INT;
+ }
+ }
+ }
+ else if (s[0].unicode() == 'n') {
+ if (s[1].unicode() == 'e') {
+ if (s[2].unicode() == 'w') {
+ return Lexer::T_NEW;
+ }
+ }
+ }
+ else if (s[0].unicode() == 't') {
+ if (s[1].unicode() == 'r') {
+ if (s[2].unicode() == 'y') {
+ return Lexer::T_TRY;
+ }
+ }
+ }
+ else if (s[0].unicode() == 'v') {
+ if (s[1].unicode() == 'a') {
+ if (s[2].unicode() == 'r') {
+ return Lexer::T_VAR;
+ }
+ }
+ }
+ return Lexer::T_IDENTIFIER;
+}
+
+static inline int classify4(const QChar *s, bool /*qmlMode*/) {
+ if (s[0].unicode() == 'b') {
+ if (s[1].unicode() == 'y') {
+ if (s[2].unicode() == 't') {
+ if (s[3].unicode() == 'e') {
+ return Lexer::T_BYTE;
+ }
+ }
+ }
+ }
+ else if (s[0].unicode() == 'c') {
+ if (s[1].unicode() == 'a') {
+ if (s[2].unicode() == 's') {
+ if (s[3].unicode() == 'e') {
+ return Lexer::T_CASE;
+ }
+ }
+ }
+ else if (s[1].unicode() == 'h') {
+ if (s[2].unicode() == 'a') {
+ if (s[3].unicode() == 'r') {
+ return Lexer::T_CHAR;
+ }
+ }
+ }
+ }
+ else if (s[0].unicode() == 'e') {
+ if (s[1].unicode() == 'l') {
+ if (s[2].unicode() == 's') {
+ if (s[3].unicode() == 'e') {
+ return Lexer::T_ELSE;
+ }
+ }
+ }
+ else if (s[1].unicode() == 'n') {
+ if (s[2].unicode() == 'u') {
+ if (s[3].unicode() == 'm') {
+ return Lexer::T_ENUM;
+ }
+ }
+ }
+ }
+ else if (s[0].unicode() == 'g') {
+ if (s[1].unicode() == 'o') {
+ if (s[2].unicode() == 't') {
+ if (s[3].unicode() == 'o') {
+ return Lexer::T_GOTO;
+ }
+ }
+ }
+ }
+ else if (s[0].unicode() == 'l') {
+ if (s[1].unicode() == 'o') {
+ if (s[2].unicode() == 'n') {
+ if (s[3].unicode() == 'g') {
+ return Lexer::T_LONG;
+ }
+ }
+ }
+ }
+ else if (s[0].unicode() == 'n') {
+ if (s[1].unicode() == 'u') {
+ if (s[2].unicode() == 'l') {
+ if (s[3].unicode() == 'l') {
+ return Lexer::T_NULL;
+ }
+ }
+ }
+ }
+ else if (s[0].unicode() == 't') {
+ if (s[1].unicode() == 'h') {
+ if (s[2].unicode() == 'i') {
+ if (s[3].unicode() == 's') {
+ return Lexer::T_THIS;
+ }
+ }
+ }
+ else if (s[1].unicode() == 'r') {
+ if (s[2].unicode() == 'u') {
+ if (s[3].unicode() == 'e') {
+ return Lexer::T_TRUE;
+ }
+ }
+ }
+ }
+ else if (s[0].unicode() == 'v') {
+ if (s[1].unicode() == 'o') {
+ if (s[2].unicode() == 'i') {
+ if (s[3].unicode() == 'd') {
+ return Lexer::T_VOID;
+ }
+ }
+ }
+ }
+ else if (s[0].unicode() == 'w') {
+ if (s[1].unicode() == 'i') {
+ if (s[2].unicode() == 't') {
+ if (s[3].unicode() == 'h') {
+ return Lexer::T_WITH;
+ }
+ }
+ }
+ }
+ return Lexer::T_IDENTIFIER;
+}
+
+static inline int classify5(const QChar *s, bool /*qmlMode*/) {
+ if (s[0].unicode() == 'b') {
+ if (s[1].unicode() == 'r') {
+ if (s[2].unicode() == 'e') {
+ if (s[3].unicode() == 'a') {
+ if (s[4].unicode() == 'k') {
+ return Lexer::T_BREAK;
+ }
+ }
+ }
+ }
+ }
+ else if (s[0].unicode() == 'c') {
+ if (s[1].unicode() == 'a') {
+ if (s[2].unicode() == 't') {
+ if (s[3].unicode() == 'c') {
+ if (s[4].unicode() == 'h') {
+ return Lexer::T_CATCH;
+ }
+ }
+ }
+ }
+ else if (s[1].unicode() == 'l') {
+ if (s[2].unicode() == 'a') {
+ if (s[3].unicode() == 's') {
+ if (s[4].unicode() == 's') {
+ return Lexer::T_CLASS;
+ }
+ }
+ }
+ }
+ else if (s[1].unicode() == 'o') {
+ if (s[2].unicode() == 'n') {
+ if (s[3].unicode() == 's') {
+ if (s[4].unicode() == 't') {
+ return Lexer::T_CONST;
+ }
+ }
+ }
+ }
+ }
+ else if (s[0].unicode() == 'f') {
+ if (s[1].unicode() == 'a') {
+ if (s[2].unicode() == 'l') {
+ if (s[3].unicode() == 's') {
+ if (s[4].unicode() == 'e') {
+ return Lexer::T_FALSE;
+ }
+ }
+ }
+ }
+ else if (s[1].unicode() == 'i') {
+ if (s[2].unicode() == 'n') {
+ if (s[3].unicode() == 'a') {
+ if (s[4].unicode() == 'l') {
+ return Lexer::T_FINAL;
+ }
+ }
+ }
+ }
+ else if (s[1].unicode() == 'l') {
+ if (s[2].unicode() == 'o') {
+ if (s[3].unicode() == 'a') {
+ if (s[4].unicode() == 't') {
+ return Lexer::T_FLOAT;
+ }
+ }
+ }
+ }
+ }
+ else if (s[0].unicode() == 's') {
+ if (s[1].unicode() == 'h') {
+ if (s[2].unicode() == 'o') {
+ if (s[3].unicode() == 'r') {
+ if (s[4].unicode() == 't') {
+ return Lexer::T_SHORT;
+ }
+ }
+ }
+ }
+ else if (s[1].unicode() == 'u') {
+ if (s[2].unicode() == 'p') {
+ if (s[3].unicode() == 'e') {
+ if (s[4].unicode() == 'r') {
+ return Lexer::T_SUPER;
+ }
+ }
+ }
+ }
+ }
+ else if (s[0].unicode() == 't') {
+ if (s[1].unicode() == 'h') {
+ if (s[2].unicode() == 'r') {
+ if (s[3].unicode() == 'o') {
+ if (s[4].unicode() == 'w') {
+ return Lexer::T_THROW;
+ }
+ }
+ }
+ }
+ }
+ else if (s[0].unicode() == 'w') {
+ if (s[1].unicode() == 'h') {
+ if (s[2].unicode() == 'i') {
+ if (s[3].unicode() == 'l') {
+ if (s[4].unicode() == 'e') {
+ return Lexer::T_WHILE;
+ }
+ }
+ }
+ }
+ }
+ return Lexer::T_IDENTIFIER;
+}
+
+static inline int classify6(const QChar *s, bool qmlMode) {
+ if (s[0].unicode() == 'd') {
+ if (s[1].unicode() == 'e') {
+ if (s[2].unicode() == 'l') {
+ if (s[3].unicode() == 'e') {
+ if (s[4].unicode() == 't') {
+ if (s[5].unicode() == 'e') {
+ return Lexer::T_DELETE;
+ }
+ }
+ }
+ }
+ }
+ else if (s[1].unicode() == 'o') {
+ if (s[2].unicode() == 'u') {
+ if (s[3].unicode() == 'b') {
+ if (s[4].unicode() == 'l') {
+ if (s[5].unicode() == 'e') {
+ return Lexer::T_DOUBLE;
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (s[0].unicode() == 'e') {
+ if (s[1].unicode() == 'x') {
+ if (s[2].unicode() == 'p') {
+ if (s[3].unicode() == 'o') {
+ if (s[4].unicode() == 'r') {
+ if (s[5].unicode() == 't') {
+ return Lexer::T_EXPORT;
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (s[0].unicode() == 'i') {
+ if (s[1].unicode() == 'm') {
+ if (s[2].unicode() == 'p') {
+ if (s[3].unicode() == 'o') {
+ if (s[4].unicode() == 'r') {
+ if (s[5].unicode() == 't') {
+ return qmlMode ? Lexer::T_IMPORT : Lexer::T_RESERVED_WORD;
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (s[0].unicode() == 'n') {
+ if (s[1].unicode() == 'a') {
+ if (s[2].unicode() == 't') {
+ if (s[3].unicode() == 'i') {
+ if (s[4].unicode() == 'v') {
+ if (s[5].unicode() == 'e') {
+ return Lexer::T_NATIVE;
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (s[0].unicode() == 'p') {
+ if (s[1].unicode() == 'u') {
+ if (s[2].unicode() == 'b') {
+ if (s[3].unicode() == 'l') {
+ if (s[4].unicode() == 'i') {
+ if (s[5].unicode() == 'c') {
+ return qmlMode ? Lexer::T_PUBLIC : Lexer::T_RESERVED_WORD;
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (s[0].unicode() == 'r') {
+ if (s[1].unicode() == 'e') {
+ if (s[2].unicode() == 't') {
+ if (s[3].unicode() == 'u') {
+ if (s[4].unicode() == 'r') {
+ if (s[5].unicode() == 'n') {
+ return Lexer::T_RETURN;
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (s[0].unicode() == 's') {
+ if (qmlMode && s[1].unicode() == 'i') {
+ if (s[2].unicode() == 'g') {
+ if (s[3].unicode() == 'n') {
+ if (s[4].unicode() == 'a') {
+ if (s[5].unicode() == 'l') {
+ return Lexer::T_SIGNAL;
+ }
+ }
+ }
+ }
+ }
+ else if (s[1].unicode() == 't') {
+ if (s[2].unicode() == 'a') {
+ if (s[3].unicode() == 't') {
+ if (s[4].unicode() == 'i') {
+ if (s[5].unicode() == 'c') {
+ return Lexer::T_STATIC;
+ }
+ }
+ }
+ }
+ }
+ else if (s[1].unicode() == 'w') {
+ if (s[2].unicode() == 'i') {
+ if (s[3].unicode() == 't') {
+ if (s[4].unicode() == 'c') {
+ if (s[5].unicode() == 'h') {
+ return Lexer::T_SWITCH;
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (s[0].unicode() == 't') {
+ if (s[1].unicode() == 'h') {
+ if (s[2].unicode() == 'r') {
+ if (s[3].unicode() == 'o') {
+ if (s[4].unicode() == 'w') {
+ if (s[5].unicode() == 's') {
+ return Lexer::T_THROWS;
+ }
+ }
+ }
+ }
+ }
+ else if (s[1].unicode() == 'y') {
+ if (s[2].unicode() == 'p') {
+ if (s[3].unicode() == 'e') {
+ if (s[4].unicode() == 'o') {
+ if (s[5].unicode() == 'f') {
+ return Lexer::T_TYPEOF;
+ }
+ }
+ }
+ }
+ }
+ }
+ return Lexer::T_IDENTIFIER;
+}
+
+static inline int classify7(const QChar *s, bool /*qmlMode*/) {
+ if (s[0].unicode() == 'b') {
+ if (s[1].unicode() == 'o') {
+ if (s[2].unicode() == 'o') {
+ if (s[3].unicode() == 'l') {
+ if (s[4].unicode() == 'e') {
+ if (s[5].unicode() == 'a') {
+ if (s[6].unicode() == 'n') {
+ return Lexer::T_BOOLEAN;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (s[0].unicode() == 'd') {
+ if (s[1].unicode() == 'e') {
+ if (s[2].unicode() == 'f') {
+ if (s[3].unicode() == 'a') {
+ if (s[4].unicode() == 'u') {
+ if (s[5].unicode() == 'l') {
+ if (s[6].unicode() == 't') {
+ return Lexer::T_DEFAULT;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (s[0].unicode() == 'e') {
+ if (s[1].unicode() == 'x') {
+ if (s[2].unicode() == 't') {
+ if (s[3].unicode() == 'e') {
+ if (s[4].unicode() == 'n') {
+ if (s[5].unicode() == 'd') {
+ if (s[6].unicode() == 's') {
+ return Lexer::T_EXTENDS;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (s[0].unicode() == 'f') {
+ if (s[1].unicode() == 'i') {
+ if (s[2].unicode() == 'n') {
+ if (s[3].unicode() == 'a') {
+ if (s[4].unicode() == 'l') {
+ if (s[5].unicode() == 'l') {
+ if (s[6].unicode() == 'y') {
+ return Lexer::T_FINALLY;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (s[0].unicode() == 'p') {
+ if (s[1].unicode() == 'a') {
+ if (s[2].unicode() == 'c') {
+ if (s[3].unicode() == 'k') {
+ if (s[4].unicode() == 'a') {
+ if (s[5].unicode() == 'g') {
+ if (s[6].unicode() == 'e') {
+ return Lexer::T_PACKAGE;
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (s[1].unicode() == 'r') {
+ if (s[2].unicode() == 'i') {
+ if (s[3].unicode() == 'v') {
+ if (s[4].unicode() == 'a') {
+ if (s[5].unicode() == 't') {
+ if (s[6].unicode() == 'e') {
+ return Lexer::T_PRIVATE;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return Lexer::T_IDENTIFIER;
+}
+
+static inline int classify8(const QChar *s, bool qmlMode) {
+ if (s[0].unicode() == 'a') {
+ if (s[1].unicode() == 'b') {
+ if (s[2].unicode() == 's') {
+ if (s[3].unicode() == 't') {
+ if (s[4].unicode() == 'r') {
+ if (s[5].unicode() == 'a') {
+ if (s[6].unicode() == 'c') {
+ if (s[7].unicode() == 't') {
+ return Lexer::T_ABSTRACT;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (s[0].unicode() == 'c') {
+ if (s[1].unicode() == 'o') {
+ if (s[2].unicode() == 'n') {
+ if (s[3].unicode() == 't') {
+ if (s[4].unicode() == 'i') {
+ if (s[5].unicode() == 'n') {
+ if (s[6].unicode() == 'u') {
+ if (s[7].unicode() == 'e') {
+ return Lexer::T_CONTINUE;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (s[0].unicode() == 'd') {
+ if (s[1].unicode() == 'e') {
+ if (s[2].unicode() == 'b') {
+ if (s[3].unicode() == 'u') {
+ if (s[4].unicode() == 'g') {
+ if (s[5].unicode() == 'g') {
+ if (s[6].unicode() == 'e') {
+ if (s[7].unicode() == 'r') {
+ return Lexer::T_DEBUGGER;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (s[0].unicode() == 'f') {
+ if (s[1].unicode() == 'u') {
+ if (s[2].unicode() == 'n') {
+ if (s[3].unicode() == 'c') {
+ if (s[4].unicode() == 't') {
+ if (s[5].unicode() == 'i') {
+ if (s[6].unicode() == 'o') {
+ if (s[7].unicode() == 'n') {
+ return Lexer::T_FUNCTION;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (qmlMode && s[0].unicode() == 'p') {
+ if (s[1].unicode() == 'r') {
+ if (s[2].unicode() == 'o') {
+ if (s[3].unicode() == 'p') {
+ if (s[4].unicode() == 'e') {
+ if (s[5].unicode() == 'r') {
+ if (s[6].unicode() == 't') {
+ if (s[7].unicode() == 'y') {
+ return Lexer::T_PROPERTY;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (qmlMode && s[0].unicode() == 'r') {
+ if (s[1].unicode() == 'e') {
+ if (s[2].unicode() == 'a') {
+ if (s[3].unicode() == 'd') {
+ if (s[4].unicode() == 'o') {
+ if (s[5].unicode() == 'n') {
+ if (s[6].unicode() == 'l') {
+ if (s[7].unicode() == 'y') {
+ return Lexer::T_READONLY;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (s[0].unicode() == 'v') {
+ if (s[1].unicode() == 'o') {
+ if (s[2].unicode() == 'l') {
+ if (s[3].unicode() == 'a') {
+ if (s[4].unicode() == 't') {
+ if (s[5].unicode() == 'i') {
+ if (s[6].unicode() == 'l') {
+ if (s[7].unicode() == 'e') {
+ return Lexer::T_VOLATILE;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return Lexer::T_IDENTIFIER;
+}
+
+static inline int classify9(const QChar *s, bool /*qmlMode*/) {
+ if (s[0].unicode() == 'i') {
+ if (s[1].unicode() == 'n') {
+ if (s[2].unicode() == 't') {
+ if (s[3].unicode() == 'e') {
+ if (s[4].unicode() == 'r') {
+ if (s[5].unicode() == 'f') {
+ if (s[6].unicode() == 'a') {
+ if (s[7].unicode() == 'c') {
+ if (s[8].unicode() == 'e') {
+ return Lexer::T_INTERFACE;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (s[0].unicode() == 'p') {
+ if (s[1].unicode() == 'r') {
+ if (s[2].unicode() == 'o') {
+ if (s[3].unicode() == 't') {
+ if (s[4].unicode() == 'e') {
+ if (s[5].unicode() == 'c') {
+ if (s[6].unicode() == 't') {
+ if (s[7].unicode() == 'e') {
+ if (s[8].unicode() == 'd') {
+ return Lexer::T_PROTECTED;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (s[0].unicode() == 't') {
+ if (s[1].unicode() == 'r') {
+ if (s[2].unicode() == 'a') {
+ if (s[3].unicode() == 'n') {
+ if (s[4].unicode() == 's') {
+ if (s[5].unicode() == 'i') {
+ if (s[6].unicode() == 'e') {
+ if (s[7].unicode() == 'n') {
+ if (s[8].unicode() == 't') {
+ return Lexer::T_TRANSIENT;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return Lexer::T_IDENTIFIER;
+}
+
+static inline int classify10(const QChar *s, bool /*qmlMode*/) {
+ if (s[0].unicode() == 'i') {
+ if (s[1].unicode() == 'm') {
+ if (s[2].unicode() == 'p') {
+ if (s[3].unicode() == 'l') {
+ if (s[4].unicode() == 'e') {
+ if (s[5].unicode() == 'm') {
+ if (s[6].unicode() == 'e') {
+ if (s[7].unicode() == 'n') {
+ if (s[8].unicode() == 't') {
+ if (s[9].unicode() == 's') {
+ return Lexer::T_IMPLEMENTS;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (s[1].unicode() == 'n') {
+ if (s[2].unicode() == 's') {
+ if (s[3].unicode() == 't') {
+ if (s[4].unicode() == 'a') {
+ if (s[5].unicode() == 'n') {
+ if (s[6].unicode() == 'c') {
+ if (s[7].unicode() == 'e') {
+ if (s[8].unicode() == 'o') {
+ if (s[9].unicode() == 'f') {
+ return Lexer::T_INSTANCEOF;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return Lexer::T_IDENTIFIER;
+}
+
+static inline int classify12(const QChar *s, bool /*qmlMode*/) {
+ if (s[0].unicode() == 's') {
+ if (s[1].unicode() == 'y') {
+ if (s[2].unicode() == 'n') {
+ if (s[3].unicode() == 'c') {
+ if (s[4].unicode() == 'h') {
+ if (s[5].unicode() == 'r') {
+ if (s[6].unicode() == 'o') {
+ if (s[7].unicode() == 'n') {
+ if (s[8].unicode() == 'i') {
+ if (s[9].unicode() == 'z') {
+ if (s[10].unicode() == 'e') {
+ if (s[11].unicode() == 'd') {
+ return Lexer::T_SYNCHRONIZED;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return Lexer::T_IDENTIFIER;
+}
+
+int Lexer::classify(const QChar *s, int n, bool qmlMode) {
+ switch (n) {
+ case 2: return classify2(s, qmlMode);
+ case 3: return classify3(s, qmlMode);
+ case 4: return classify4(s, qmlMode);
+ case 5: return classify5(s, qmlMode);
+ case 6: return classify6(s, qmlMode);
+ case 7: return classify7(s, qmlMode);
+ case 8: return classify8(s, qmlMode);
+ case 9: return classify9(s, qmlMode);
+ case 10: return classify10(s, qmlMode);
+ case 12: return classify12(s, qmlMode);
+ default: return Lexer::T_IDENTIFIER;
+ } // switch
+}
+
+#endif // QQMLJSKEYWORDS_P_H
diff --git a/src/qml/qml/parser/qqmljslexer.cpp b/src/qml/qml/parser/qqmljslexer.cpp
new file mode 100644
index 0000000000..c34fc81163
--- /dev/null
+++ b/src/qml/qml/parser/qqmljslexer.cpp
@@ -0,0 +1,1166 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qqmljslexer_p.h"
+#include "qqmljsengine_p.h"
+#include "qqmljsmemorypool_p.h"
+
+#include <QtCore/QCoreApplication>
+#include <QtCore/QVarLengthArray>
+#include <QtCore/QDebug>
+
+QT_BEGIN_NAMESPACE
+Q_CORE_EXPORT double qstrtod(const char *s00, char const **se, bool *ok);
+QT_END_NAMESPACE
+
+using namespace QQmlJS;
+
+static int regExpFlagFromChar(const QChar &ch)
+{
+ switch (ch.unicode()) {
+ case 'g': return Lexer::RegExp_Global;
+ case 'i': return Lexer::RegExp_IgnoreCase;
+ case 'm': return Lexer::RegExp_Multiline;
+ }
+ return 0;
+}
+
+static unsigned char convertHex(ushort c)
+{
+ if (c >= '0' && c <= '9')
+ return (c - '0');
+ else if (c >= 'a' && c <= 'f')
+ return (c - 'a' + 10);
+ else
+ return (c - 'A' + 10);
+}
+
+static QChar convertHex(QChar c1, QChar c2)
+{
+ return QChar((convertHex(c1.unicode()) << 4) + convertHex(c2.unicode()));
+}
+
+static QChar convertUnicode(QChar c1, QChar c2, QChar c3, QChar c4)
+{
+ return QChar((convertHex(c3.unicode()) << 4) + convertHex(c4.unicode()),
+ (convertHex(c1.unicode()) << 4) + convertHex(c2.unicode()));
+}
+
+Lexer::Lexer(Engine *engine)
+ : _engine(engine)
+ , _codePtr(0)
+ , _lastLinePtr(0)
+ , _tokenLinePtr(0)
+ , _tokenStartPtr(0)
+ , _char(QLatin1Char('\n'))
+ , _errorCode(NoError)
+ , _currentLineNumber(0)
+ , _tokenValue(0)
+ , _parenthesesState(IgnoreParentheses)
+ , _parenthesesCount(0)
+ , _stackToken(-1)
+ , _patternFlags(0)
+ , _tokenKind(0)
+ , _tokenLength(0)
+ , _tokenLine(0)
+ , _validTokenText(false)
+ , _prohibitAutomaticSemicolon(false)
+ , _restrictedKeyword(false)
+ , _terminator(false)
+ , _followsClosingBrace(false)
+ , _delimited(true)
+ , _qmlMode(true)
+{
+ if (engine)
+ engine->setLexer(this);
+}
+
+bool Lexer::qmlMode() const
+{
+ return _qmlMode;
+}
+
+QString Lexer::code() const
+{
+ return _code;
+}
+
+void Lexer::setCode(const QString &code, int lineno, bool qmlMode)
+{
+ if (_engine)
+ _engine->setCode(code);
+
+ _qmlMode = qmlMode;
+ _code = code;
+ _tokenText.clear();
+ _tokenText.reserve(1024);
+ _errorMessage.clear();
+ _tokenSpell = QStringRef();
+
+ _codePtr = code.unicode();
+ _lastLinePtr = _codePtr;
+ _tokenLinePtr = _codePtr;
+ _tokenStartPtr = _codePtr;
+
+ _char = QLatin1Char('\n');
+ _errorCode = NoError;
+
+ _currentLineNumber = lineno;
+ _tokenValue = 0;
+
+ // parentheses state
+ _parenthesesState = IgnoreParentheses;
+ _parenthesesCount = 0;
+
+ _stackToken = -1;
+
+ _patternFlags = 0;
+ _tokenLength = 0;
+ _tokenLine = lineno;
+
+ _validTokenText = false;
+ _prohibitAutomaticSemicolon = false;
+ _restrictedKeyword = false;
+ _terminator = false;
+ _followsClosingBrace = false;
+ _delimited = true;
+}
+
+void Lexer::scanChar()
+{
+ _char = *_codePtr++;
+
+ if (_char == QLatin1Char('\n')) {
+ _lastLinePtr = _codePtr; // points to the first character after the newline
+ ++_currentLineNumber;
+ }
+}
+
+int Lexer::lex()
+{
+ const int previousTokenKind = _tokenKind;
+
+ _tokenSpell = QStringRef();
+ _tokenKind = scanToken();
+ _tokenLength = _codePtr - _tokenStartPtr - 1;
+
+ _delimited = false;
+ _restrictedKeyword = false;
+ _followsClosingBrace = (previousTokenKind == T_RBRACE);
+
+ // update the flags
+ switch (_tokenKind) {
+ case T_LBRACE:
+ case T_SEMICOLON:
+ case T_COLON:
+ _delimited = true;
+ break;
+
+ case T_IF:
+ case T_FOR:
+ case T_WHILE:
+ case T_WITH:
+ _parenthesesState = CountParentheses;
+ _parenthesesCount = 0;
+ break;
+
+ case T_DO:
+ _parenthesesState = BalancedParentheses;
+ break;
+
+ case T_CONTINUE:
+ case T_BREAK:
+ case T_RETURN:
+ case T_THROW:
+ _restrictedKeyword = true;
+ break;
+ } // switch
+
+ // update the parentheses state
+ switch (_parenthesesState) {
+ case IgnoreParentheses:
+ break;
+
+ case CountParentheses:
+ if (_tokenKind == T_RPAREN) {
+ --_parenthesesCount;
+ if (_parenthesesCount == 0)
+ _parenthesesState = BalancedParentheses;
+ } else if (_tokenKind == T_LPAREN) {
+ ++_parenthesesCount;
+ }
+ break;
+
+ case BalancedParentheses:
+ _parenthesesState = IgnoreParentheses;
+ break;
+ } // switch
+
+ return _tokenKind;
+}
+
+bool Lexer::isUnicodeEscapeSequence(const QChar *chars)
+{
+ if (isHexDigit(chars[0]) && isHexDigit(chars[1]) && isHexDigit(chars[2]) && isHexDigit(chars[3]))
+ return true;
+
+ return false;
+}
+
+QChar Lexer::decodeUnicodeEscapeCharacter(bool *ok)
+{
+ if (_char == QLatin1Char('u') && isUnicodeEscapeSequence(&_codePtr[0])) {
+ scanChar(); // skip u
+
+ const QChar c1 = _char;
+ scanChar();
+
+ const QChar c2 = _char;
+ scanChar();
+
+ const QChar c3 = _char;
+ scanChar();
+
+ const QChar c4 = _char;
+ scanChar();
+
+ if (ok)
+ *ok = true;
+
+ return convertUnicode(c1, c2, c3, c4);
+ }
+
+ *ok = false;
+ return QChar();
+}
+
+int Lexer::scanToken()
+{
+ if (_stackToken != -1) {
+ int tk = _stackToken;
+ _stackToken = -1;
+ return tk;
+ }
+
+ _terminator = false;
+
+again:
+ _validTokenText = false;
+ _tokenLinePtr = _lastLinePtr;
+
+ while (_char.isSpace()) {
+ if (_char == QLatin1Char('\n')) {
+ _tokenLinePtr = _codePtr;
+
+ if (_restrictedKeyword) {
+ // automatic semicolon insertion
+ _tokenLine = _currentLineNumber;
+ _tokenStartPtr = _codePtr - 1; // ### TODO: insert it before the optional \r sequence.
+ return T_SEMICOLON;
+ } else {
+ _terminator = true;
+ syncProhibitAutomaticSemicolon();
+ }
+ }
+
+ scanChar();
+ }
+
+ _tokenStartPtr = _codePtr - 1;
+ _tokenLine = _currentLineNumber;
+
+ if (_char.isNull())
+ return EOF_SYMBOL;
+
+ const QChar ch = _char;
+ scanChar();
+
+ switch (ch.unicode()) {
+ case '~': return T_TILDE;
+ case '}': return T_RBRACE;
+
+ case '|':
+ if (_char == QLatin1Char('|')) {
+ scanChar();
+ return T_OR_OR;
+ } else if (_char == QLatin1Char('=')) {
+ scanChar();
+ return T_OR_EQ;
+ }
+ return T_OR;
+
+ case '{': return T_LBRACE;
+
+ case '^':
+ if (_char == QLatin1Char('=')) {
+ scanChar();
+ return T_XOR_EQ;
+ }
+ return T_XOR;
+
+ case ']': return T_RBRACKET;
+ case '[': return T_LBRACKET;
+ case '?': return T_QUESTION;
+
+ case '>':
+ if (_char == QLatin1Char('>')) {
+ scanChar();
+ if (_char == QLatin1Char('>')) {
+ scanChar();
+ if (_char == QLatin1Char('=')) {
+ scanChar();
+ return T_GT_GT_GT_EQ;
+ }
+ return T_GT_GT_GT;
+ } else if (_char == QLatin1Char('=')) {
+ scanChar();
+ return T_GT_GT_EQ;
+ }
+ return T_GT_GT;
+ } else if (_char == QLatin1Char('=')) {
+ scanChar();
+ return T_GE;
+ }
+ return T_GT;
+
+ case '=':
+ if (_char == QLatin1Char('=')) {
+ scanChar();
+ if (_char == QLatin1Char('=')) {
+ scanChar();
+ return T_EQ_EQ_EQ;
+ }
+ return T_EQ_EQ;
+ }
+ return T_EQ;
+
+ case '<':
+ if (_char == QLatin1Char('=')) {
+ scanChar();
+ return T_LE;
+ } else if (_char == QLatin1Char('<')) {
+ scanChar();
+ if (_char == QLatin1Char('=')) {
+ scanChar();
+ return T_LT_LT_EQ;
+ }
+ return T_LT_LT;
+ }
+ return T_LT;
+
+ case ';': return T_SEMICOLON;
+ case ':': return T_COLON;
+
+ case '/':
+ if (_char == QLatin1Char('*')) {
+ scanChar();
+ while (!_char.isNull()) {
+ if (_char == QLatin1Char('*')) {
+ scanChar();
+ if (_char == QLatin1Char('/')) {
+ scanChar();
+
+ if (_engine) {
+ _engine->addComment(tokenOffset() + 2, _codePtr - _tokenStartPtr - 1 - 4,
+ tokenStartLine(), tokenStartColumn() + 2);
+ }
+
+ goto again;
+ }
+ } else {
+ scanChar();
+ }
+ }
+ } else if (_char == QLatin1Char('/')) {
+ while (!_char.isNull() && _char != QLatin1Char('\n')) {
+ scanChar();
+ }
+ if (_engine) {
+ _engine->addComment(tokenOffset() + 2, _codePtr - _tokenStartPtr - 1 - 2,
+ tokenStartLine(), tokenStartColumn() + 2);
+ }
+ goto again;
+ } if (_char == QLatin1Char('=')) {
+ scanChar();
+ return T_DIVIDE_EQ;
+ }
+ return T_DIVIDE_;
+
+ case '.':
+ if (_char.isDigit()) {
+ QVarLengthArray<char,32> chars;
+
+ chars.append(ch.unicode()); // append the `.'
+
+ while (_char.isDigit()) {
+ chars.append(_char.unicode());
+ scanChar();
+ }
+
+ if (_char == QLatin1Char('e') || _char == QLatin1Char('E')) {
+ if (_codePtr[0].isDigit() || ((_codePtr[0] == QLatin1Char('+') || _codePtr[0] == QLatin1Char('-')) &&
+ _codePtr[1].isDigit())) {
+
+ chars.append(_char.unicode());
+ scanChar(); // consume `e'
+
+ if (_char == QLatin1Char('+') || _char == QLatin1Char('-')) {
+ chars.append(_char.unicode());
+ scanChar(); // consume the sign
+ }
+
+ while (_char.isDigit()) {
+ chars.append(_char.unicode());
+ scanChar();
+ }
+ }
+ }
+
+ chars.append('\0');
+
+ const char *begin = chars.constData();
+ const char *end = 0;
+ bool ok = false;
+
+ _tokenValue = qstrtod(begin, &end, &ok);
+
+ if (end - begin != chars.size() - 1) {
+ _errorCode = IllegalExponentIndicator;
+ _errorMessage = QCoreApplication::translate("QQmlParser", "Illegal syntax for exponential number");
+ return T_ERROR;
+ }
+
+ return T_NUMERIC_LITERAL;
+ }
+ return T_DOT;
+
+ case '-':
+ if (_char == QLatin1Char('=')) {
+ scanChar();
+ return T_MINUS_EQ;
+ } else if (_char == QLatin1Char('-')) {
+ scanChar();
+
+ if (_terminator && !_delimited && !_prohibitAutomaticSemicolon) {
+ _stackToken = T_MINUS_MINUS;
+ return T_SEMICOLON;
+ }
+
+ return T_MINUS_MINUS;
+ }
+ return T_MINUS;
+
+ case ',': return T_COMMA;
+
+ case '+':
+ if (_char == QLatin1Char('=')) {
+ scanChar();
+ return T_PLUS_EQ;
+ } else if (_char == QLatin1Char('+')) {
+ scanChar();
+
+ if (_terminator && !_delimited && !_prohibitAutomaticSemicolon) {
+ _stackToken = T_PLUS_PLUS;
+ return T_SEMICOLON;
+ }
+
+ return T_PLUS_PLUS;
+ }
+ return T_PLUS;
+
+ case '*':
+ if (_char == QLatin1Char('=')) {
+ scanChar();
+ return T_STAR_EQ;
+ }
+ return T_STAR;
+
+ case ')': return T_RPAREN;
+ case '(': return T_LPAREN;
+
+ case '&':
+ if (_char == QLatin1Char('=')) {
+ scanChar();
+ return T_AND_EQ;
+ } else if (_char == QLatin1Char('&')) {
+ scanChar();
+ return T_AND_AND;
+ }
+ return T_AND;
+
+ case '%':
+ if (_char == QLatin1Char('=')) {
+ scanChar();
+ return T_REMAINDER_EQ;
+ }
+ return T_REMAINDER;
+
+ case '!':
+ if (_char == QLatin1Char('=')) {
+ scanChar();
+ if (_char == QLatin1Char('=')) {
+ scanChar();
+ return T_NOT_EQ_EQ;
+ }
+ return T_NOT_EQ;
+ }
+ return T_NOT;
+
+ case '\'':
+ case '"': {
+ const QChar quote = ch;
+ bool multilineStringLiteral = false;
+
+ const QChar *startCode = _codePtr;
+
+ if (_engine) {
+ while (!_char.isNull()) {
+ if (_char == QLatin1Char('\n') || _char == QLatin1Char('\\')) {
+ break;
+ } else if (_char == quote) {
+ _tokenSpell = _engine->midRef(startCode - _code.unicode() - 1, _codePtr - startCode);
+ scanChar();
+
+ return T_STRING_LITERAL;
+ }
+ scanChar();
+ }
+ }
+
+ _validTokenText = true;
+ _tokenText.resize(0);
+ startCode--;
+ while (startCode != _codePtr - 1)
+ _tokenText += *startCode++;
+
+ while (! _char.isNull()) {
+ if (_char == QLatin1Char('\n')) {
+ multilineStringLiteral = true;
+ _tokenText += _char;
+ scanChar();
+ } else if (_char == quote) {
+ scanChar();
+
+ if (_engine)
+ _tokenSpell = _engine->newStringRef(_tokenText);
+
+ return multilineStringLiteral ? T_MULTILINE_STRING_LITERAL : T_STRING_LITERAL;
+ } else if (_char == QLatin1Char('\\')) {
+ scanChar();
+
+ QChar u;
+ bool ok = false;
+
+ switch (_char.unicode()) {
+ // unicode escape sequence
+ case 'u':
+ u = decodeUnicodeEscapeCharacter(&ok);
+ if (! ok)
+ u = _char;
+ break;
+
+ // hex escape sequence
+ case 'x':
+ case 'X':
+ if (isHexDigit(_codePtr[0]) && isHexDigit(_codePtr[1])) {
+ scanChar();
+
+ const QChar c1 = _char;
+ scanChar();
+
+ const QChar c2 = _char;
+ scanChar();
+
+ u = convertHex(c1, c2);
+ } else {
+ u = _char;
+ }
+ break;
+
+ // single character escape sequence
+ case '\\': u = QLatin1Char('\\'); scanChar(); break;
+ case '\'': u = QLatin1Char('\''); scanChar(); break;
+ case '\"': u = QLatin1Char('\"'); scanChar(); break;
+ case 'b': u = QLatin1Char('\b'); scanChar(); break;
+ case 'f': u = QLatin1Char('\f'); scanChar(); break;
+ case 'n': u = QLatin1Char('\n'); scanChar(); break;
+ case 'r': u = QLatin1Char('\r'); scanChar(); break;
+ case 't': u = QLatin1Char('\t'); scanChar(); break;
+ case 'v': u = QLatin1Char('\v'); scanChar(); break;
+
+ case '0':
+ if (! _codePtr[1].isDigit()) {
+ scanChar();
+ u = QLatin1Char('\0');
+ } else {
+ // ### parse deprecated octal escape sequence ?
+ u = _char;
+ }
+ break;
+
+ case '\r':
+ while (_char == QLatin1Char('\r'))
+ scanChar();
+
+ if (_char == QLatin1Char('\n')) {
+ u = _char;
+ scanChar();
+ } else {
+ u = QLatin1Char('\n');
+ }
+
+ break;
+
+ case '\n':
+ u = _char;
+ scanChar();
+ break;
+
+ default:
+ // non escape character
+ u = _char;
+ scanChar();
+ }
+
+ _tokenText += u;
+ } else {
+ _tokenText += _char;
+ scanChar();
+ }
+ }
+
+ _errorCode = UnclosedStringLiteral;
+ _errorMessage = QCoreApplication::translate("QQmlParser", "Unclosed string at end of line");
+ return T_ERROR;
+ }
+
+ default:
+ if (ch.isLetter() || ch == QLatin1Char('$') || ch == QLatin1Char('_') || (ch == QLatin1Char('\\') && _char == QLatin1Char('u'))) {
+ bool identifierWithEscapeChars = false;
+ if (ch == QLatin1Char('\\')) {
+ identifierWithEscapeChars = true;
+ _tokenText.resize(0);
+ bool ok = false;
+ _tokenText += decodeUnicodeEscapeCharacter(&ok);
+ _validTokenText = true;
+ if (! ok) {
+ _errorCode = IllegalUnicodeEscapeSequence;
+ _errorMessage = QCoreApplication::translate("QQmlParser", "Illegal unicode escape sequence");
+ return T_ERROR;
+ }
+ }
+ while (true) {
+ if (_char.isLetterOrNumber() || _char == QLatin1Char('$') || _char == QLatin1Char('_')) {
+ if (identifierWithEscapeChars)
+ _tokenText += _char;
+
+ scanChar();
+ } else if (_char == QLatin1Char('\\') && _codePtr[0] == QLatin1Char('u')) {
+ if (! identifierWithEscapeChars) {
+ identifierWithEscapeChars = true;
+ _tokenText.resize(0);
+ _tokenText.insert(0, _tokenStartPtr, _codePtr - _tokenStartPtr - 1);
+ _validTokenText = true;
+ }
+
+ scanChar(); // skip '\\'
+ bool ok = false;
+ _tokenText += decodeUnicodeEscapeCharacter(&ok);
+ if (! ok) {
+ _errorCode = IllegalUnicodeEscapeSequence;
+ _errorMessage = QCoreApplication::translate("QQmlParser", "Illegal unicode escape sequence");
+ return T_ERROR;
+ }
+ } else {
+ _tokenLength = _codePtr - _tokenStartPtr - 1;
+
+ int kind = T_IDENTIFIER;
+
+ if (! identifierWithEscapeChars)
+ kind = classify(_tokenStartPtr, _tokenLength, _qmlMode);
+
+ if (_engine) {
+ if (kind == T_IDENTIFIER && identifierWithEscapeChars)
+ _tokenSpell = _engine->newStringRef(_tokenText);
+ else
+ _tokenSpell = _engine->midRef(_tokenStartPtr - _code.unicode(), _tokenLength);
+ }
+
+ return kind;
+ }
+ }
+ } else if (ch.isDigit()) {
+ if (ch != QLatin1Char('0')) {
+ double integer = ch.unicode() - '0';
+
+ QChar n = _char;
+ const QChar *code = _codePtr;
+ while (n.isDigit()) {
+ integer = integer * 10 + (n.unicode() - '0');
+ n = *code++;
+ }
+
+ if (n != QLatin1Char('.') && n != QLatin1Char('e') && n != QLatin1Char('E')) {
+ if (code != _codePtr) {
+ _codePtr = code - 1;
+ scanChar();
+ }
+ _tokenValue = integer;
+ return T_NUMERIC_LITERAL;
+ }
+ }
+
+ QVarLengthArray<char,32> chars;
+ chars.append(ch.unicode());
+
+ if (ch == QLatin1Char('0') && (_char == QLatin1Char('x') || _char == QLatin1Char('X'))) {
+ // parse hex integer literal
+
+ chars.append(_char.unicode());
+ scanChar(); // consume `x'
+
+ while (isHexDigit(_char)) {
+ chars.append(_char.unicode());
+ scanChar();
+ }
+
+ _tokenValue = integerFromString(chars.constData(), chars.size(), 16);
+ return T_NUMERIC_LITERAL;
+ }
+
+ // decimal integer literal
+ while (_char.isDigit()) {
+ chars.append(_char.unicode());
+ scanChar(); // consume the digit
+ }
+
+ if (_char == QLatin1Char('.')) {
+ chars.append(_char.unicode());
+ scanChar(); // consume `.'
+
+ while (_char.isDigit()) {
+ chars.append(_char.unicode());
+ scanChar();
+ }
+
+ if (_char == QLatin1Char('e') || _char == QLatin1Char('E')) {
+ if (_codePtr[0].isDigit() || ((_codePtr[0] == QLatin1Char('+') || _codePtr[0] == QLatin1Char('-')) &&
+ _codePtr[1].isDigit())) {
+
+ chars.append(_char.unicode());
+ scanChar(); // consume `e'
+
+ if (_char == QLatin1Char('+') || _char == QLatin1Char('-')) {
+ chars.append(_char.unicode());
+ scanChar(); // consume the sign
+ }
+
+ while (_char.isDigit()) {
+ chars.append(_char.unicode());
+ scanChar();
+ }
+ }
+ }
+ } else if (_char == QLatin1Char('e') || _char == QLatin1Char('E')) {
+ if (_codePtr[0].isDigit() || ((_codePtr[0] == QLatin1Char('+') || _codePtr[0] == QLatin1Char('-')) &&
+ _codePtr[1].isDigit())) {
+
+ chars.append(_char.unicode());
+ scanChar(); // consume `e'
+
+ if (_char == QLatin1Char('+') || _char == QLatin1Char('-')) {
+ chars.append(_char.unicode());
+ scanChar(); // consume the sign
+ }
+
+ while (_char.isDigit()) {
+ chars.append(_char.unicode());
+ scanChar();
+ }
+ }
+ }
+
+ chars.append('\0');
+
+ const char *begin = chars.constData();
+ const char *end = 0;
+ bool ok = false;
+
+ _tokenValue = qstrtod(begin, &end, &ok);
+
+ if (end - begin != chars.size() - 1) {
+ _errorCode = IllegalExponentIndicator;
+ _errorMessage = QCoreApplication::translate("QQmlParser", "Illegal syntax for exponential number");
+ return T_ERROR;
+ }
+
+ return T_NUMERIC_LITERAL;
+ }
+
+ break;
+ }
+
+ return T_ERROR;
+}
+
+bool Lexer::scanRegExp(RegExpBodyPrefix prefix)
+{
+ _tokenText.resize(0);
+ _validTokenText = true;
+ _patternFlags = 0;
+
+ if (prefix == EqualPrefix)
+ _tokenText += QLatin1Char('=');
+
+ while (true) {
+ switch (_char.unicode()) {
+ case 0: // eof
+ case '\n': case '\r': // line terminator
+ _errorMessage = QCoreApplication::translate("QQmlParser", "Unterminated regular expression literal");
+ return false;
+
+ case '/':
+ scanChar();
+
+ // scan the flags
+ _patternFlags = 0;
+ while (isIdentLetter(_char)) {
+ int flag = regExpFlagFromChar(_char);
+ if (flag == 0) {
+ _errorMessage = QCoreApplication::translate("QQmlParser", "Invalid regular expression flag '%0'")
+ .arg(QChar(_char));
+ return false;
+ }
+ _patternFlags |= flag;
+ scanChar();
+ }
+
+ _tokenLength = _codePtr - _tokenStartPtr - 1;
+ return true;
+
+ case '\\':
+ // regular expression backslash sequence
+ _tokenText += _char;
+ scanChar();
+
+ if (_char.isNull() || isLineTerminator()) {
+ _errorMessage = QCoreApplication::translate("QQmlParser", "Unterminated regular expression backslash sequence");
+ return false;
+ }
+
+ _tokenText += _char;
+ scanChar();
+ break;
+
+ case '[':
+ // regular expression class
+ _tokenText += _char;
+ scanChar();
+
+ while (! _char.isNull() && ! isLineTerminator()) {
+ if (_char == QLatin1Char(']'))
+ break;
+ else if (_char == QLatin1Char('\\')) {
+ // regular expression backslash sequence
+ _tokenText += _char;
+ scanChar();
+
+ if (_char.isNull() || isLineTerminator()) {
+ _errorMessage = QCoreApplication::translate("QQmlParser", "Unterminated regular expression backslash sequence");
+ return false;
+ }
+
+ _tokenText += _char;
+ scanChar();
+ } else {
+ _tokenText += _char;
+ scanChar();
+ }
+ }
+
+ if (_char != QLatin1Char(']')) {
+ _errorMessage = QCoreApplication::translate("QQmlParser", "Unterminated regular expression class");
+ return false;
+ }
+
+ _tokenText += _char;
+ scanChar(); // skip ]
+ break;
+
+ default:
+ _tokenText += _char;
+ scanChar();
+ } // switch
+ } // while
+
+ return false;
+}
+
+bool Lexer::isLineTerminator() const
+{
+ return (_char == QLatin1Char('\n') || _char == QLatin1Char('\r'));
+}
+
+bool Lexer::isIdentLetter(QChar ch)
+{
+ // ASCII-biased, since all reserved words are ASCII, aand hence the
+ // bulk of content to be parsed.
+ if ((ch >= QLatin1Char('a') && ch <= QLatin1Char('z'))
+ || (ch >= QLatin1Char('A') && ch <= QLatin1Char('Z'))
+ || ch == QLatin1Char('$')
+ || ch == QLatin1Char('_'))
+ return true;
+ if (ch.unicode() < 128)
+ return false;
+ return ch.isLetterOrNumber();
+}
+
+bool Lexer::isDecimalDigit(ushort c)
+{
+ return (c >= '0' && c <= '9');
+}
+
+bool Lexer::isHexDigit(QChar c)
+{
+ return ((c >= QLatin1Char('0') && c <= QLatin1Char('9'))
+ || (c >= QLatin1Char('a') && c <= QLatin1Char('f'))
+ || (c >= QLatin1Char('A') && c <= QLatin1Char('F')));
+}
+
+bool Lexer::isOctalDigit(ushort c)
+{
+ return (c >= '0' && c <= '7');
+}
+
+int Lexer::tokenKind() const
+{
+ return _tokenKind;
+}
+
+int Lexer::tokenOffset() const
+{
+ return _tokenStartPtr - _code.unicode();
+}
+
+int Lexer::tokenLength() const
+{
+ return _tokenLength;
+}
+
+int Lexer::tokenStartLine() const
+{
+ return _tokenLine;
+}
+
+int Lexer::tokenStartColumn() const
+{
+ return _tokenStartPtr - _tokenLinePtr + 1;
+}
+
+int Lexer::tokenEndLine() const
+{
+ return _currentLineNumber;
+}
+
+int Lexer::tokenEndColumn() const
+{
+ return _codePtr - _lastLinePtr;
+}
+
+QStringRef Lexer::tokenSpell() const
+{
+ return _tokenSpell;
+}
+
+double Lexer::tokenValue() const
+{
+ return _tokenValue;
+}
+
+QString Lexer::tokenText() const
+{
+ if (_validTokenText)
+ return _tokenText;
+
+ if (_tokenKind == T_STRING_LITERAL)
+ return QString(_tokenStartPtr + 1, _tokenLength - 2);
+
+ return QString(_tokenStartPtr, _tokenLength);
+}
+
+Lexer::Error Lexer::errorCode() const
+{
+ return _errorCode;
+}
+
+QString Lexer::errorMessage() const
+{
+ return _errorMessage;
+}
+
+void Lexer::syncProhibitAutomaticSemicolon()
+{
+ if (_parenthesesState == BalancedParentheses) {
+ // we have seen something like "if (foo)", which means we should
+ // never insert an automatic semicolon at this point, since it would
+ // then be expanded into an empty statement (ECMA-262 7.9.1)
+ _prohibitAutomaticSemicolon = true;
+ _parenthesesState = IgnoreParentheses;
+ } else {
+ _prohibitAutomaticSemicolon = false;
+ }
+}
+
+bool Lexer::prevTerminator() const
+{
+ return _terminator;
+}
+
+bool Lexer::followsClosingBrace() const
+{
+ return _followsClosingBrace;
+}
+
+bool Lexer::canInsertAutomaticSemicolon(int token) const
+{
+ return token == T_RBRACE
+ || token == EOF_SYMBOL
+ || _terminator
+ || _followsClosingBrace;
+}
+
+bool Lexer::scanDirectives(Directives *directives)
+{
+ if (_qmlMode) {
+ // the directives are a Javascript-only extension.
+ return false;
+ }
+
+ lex(); // fetch the first token
+
+ if (_tokenKind != T_DOT)
+ return true;
+
+ do {
+ lex(); // skip T_DOT
+
+ const int lineNumber = tokenStartLine();
+
+ if (! (_tokenKind == T_IDENTIFIER || _tokenKind == T_RESERVED_WORD))
+ return false; // expected a valid QML/JS directive
+
+ const QString directiveName = tokenText();
+
+ if (! (directiveName == QLatin1String("pragma") ||
+ directiveName == QLatin1String("import")))
+ return false; // not a valid directive name
+
+ // it must be a pragma or an import directive.
+ if (directiveName == QLatin1String("pragma")) {
+ // .pragma library
+ if (! (lex() == T_IDENTIFIER && tokenText() == QLatin1String("library")))
+ return false; // expected `library
+
+ // we found a .pragma library directive
+ directives->pragmaLibrary();
+
+ } else {
+ Q_ASSERT(directiveName == QLatin1String("import"));
+ lex(); // skip .import
+
+ QString pathOrUri;
+ QString version;
+ bool fileImport = false; // file or uri import
+
+ if (_tokenKind == T_STRING_LITERAL) {
+ // .import T_STRING_LITERAL as T_IDENTIFIER
+
+ fileImport = true;
+ pathOrUri = tokenText();
+
+ } else if (_tokenKind == T_IDENTIFIER) {
+ // .import T_IDENTIFIER (. T_IDENTIFIER)* T_NUMERIC_LITERAL as T_IDENTIFIER
+
+ pathOrUri = tokenText();
+
+ lex(); // skip the first T_IDENTIFIER
+ for (; _tokenKind == T_DOT; lex()) {
+ if (lex() != T_IDENTIFIER)
+ return false;
+
+ pathOrUri += QLatin1Char('.');
+ pathOrUri += tokenText();
+ }
+
+ if (_tokenKind != T_NUMERIC_LITERAL)
+ return false; // expected the module version number
+
+ version = tokenText();
+ }
+
+ //
+ // recognize the mandatory `as' followed by the module name
+ //
+ if (! (lex() == T_RESERVED_WORD && tokenText() == QLatin1String("as")))
+ return false; // expected `as'
+
+ if (lex() != T_IDENTIFIER)
+ return false; // expected module name
+
+ const QString module = tokenText();
+
+ if (fileImport)
+ directives->importFile(pathOrUri, module);
+ else
+ directives->importModule(pathOrUri, version, module);
+ }
+
+ if (tokenStartLine() != lineNumber)
+ return false; // the directives cannot span over multiple lines
+
+ // fetch the first token after the .pragma/.import directive
+ lex();
+ } while (_tokenKind == T_DOT);
+
+ return true;
+}
+
+#include "qqmljskeywords_p.h"
diff --git a/src/qml/qml/parser/qqmljslexer_p.h b/src/qml/qml/parser/qqmljslexer_p.h
new file mode 100644
index 0000000000..6b51852f5f
--- /dev/null
+++ b/src/qml/qml/parser/qqmljslexer_p.h
@@ -0,0 +1,248 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLJSLEXER_P_H
+#define QQMLJSLEXER_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 "qqmljsglobal_p.h"
+#include "qqmljsgrammar_p.h"
+#include <QtCore/QString>
+
+QT_QML_BEGIN_NAMESPACE
+
+namespace QQmlJS {
+
+class Engine;
+
+class QML_PARSER_EXPORT Directives {
+public:
+ virtual ~Directives() {}
+
+ virtual void pragmaLibrary()
+ {
+ }
+
+ virtual void importFile(const QString &jsfile, const QString &module)
+ {
+ Q_UNUSED(jsfile);
+ Q_UNUSED(module);
+ }
+
+ virtual void importModule(const QString &uri, const QString &version, const QString &module)
+ {
+ Q_UNUSED(uri);
+ Q_UNUSED(version);
+ Q_UNUSED(module);
+ }
+};
+
+class QML_PARSER_EXPORT Lexer: public QQmlJSGrammar
+{
+public:
+ enum {
+ T_ABSTRACT = T_RESERVED_WORD,
+ T_BOOLEAN = T_RESERVED_WORD,
+ T_BYTE = T_RESERVED_WORD,
+ T_CHAR = T_RESERVED_WORD,
+ T_CLASS = T_RESERVED_WORD,
+ T_DOUBLE = T_RESERVED_WORD,
+ T_ENUM = T_RESERVED_WORD,
+ T_EXPORT = T_RESERVED_WORD,
+ T_EXTENDS = T_RESERVED_WORD,
+ T_FINAL = T_RESERVED_WORD,
+ T_FLOAT = T_RESERVED_WORD,
+ T_GOTO = T_RESERVED_WORD,
+ T_IMPLEMENTS = T_RESERVED_WORD,
+ T_INT = T_RESERVED_WORD,
+ T_INTERFACE = T_RESERVED_WORD,
+ T_LET = T_RESERVED_WORD,
+ T_LONG = T_RESERVED_WORD,
+ T_NATIVE = T_RESERVED_WORD,
+ T_PACKAGE = T_RESERVED_WORD,
+ T_PRIVATE = T_RESERVED_WORD,
+ T_PROTECTED = T_RESERVED_WORD,
+ T_SHORT = T_RESERVED_WORD,
+ T_STATIC = T_RESERVED_WORD,
+ T_SUPER = T_RESERVED_WORD,
+ T_SYNCHRONIZED = T_RESERVED_WORD,
+ T_THROWS = T_RESERVED_WORD,
+ T_TRANSIENT = T_RESERVED_WORD,
+ T_VOLATILE = T_RESERVED_WORD,
+ T_YIELD = T_RESERVED_WORD
+ };
+
+ enum Error {
+ NoError,
+ IllegalCharacter,
+ UnclosedStringLiteral,
+ IllegalEscapeSequence,
+ IllegalUnicodeEscapeSequence,
+ UnclosedComment,
+ IllegalExponentIndicator,
+ IllegalIdentifier
+ };
+
+ enum RegExpBodyPrefix {
+ NoPrefix,
+ EqualPrefix
+ };
+
+ enum RegExpFlag {
+ RegExp_Global = 0x01,
+ RegExp_IgnoreCase = 0x02,
+ RegExp_Multiline = 0x04
+ };
+
+public:
+ Lexer(Engine *engine);
+
+ bool qmlMode() const;
+
+ QString code() const;
+ void setCode(const QString &code, int lineno, bool qmlMode = true);
+
+ int lex();
+
+ bool scanRegExp(RegExpBodyPrefix prefix = NoPrefix);
+ bool scanDirectives(Directives *directives);
+
+ int regExpFlags() const { return _patternFlags; }
+ QString regExpPattern() const { return _tokenText; }
+
+ int tokenKind() const;
+ int tokenOffset() const;
+ int tokenLength() const;
+
+ int tokenStartLine() const;
+ int tokenStartColumn() const;
+
+ int tokenEndLine() const;
+ int tokenEndColumn() const;
+
+ QStringRef tokenSpell() const;
+ double tokenValue() const;
+ QString tokenText() const;
+
+ Error errorCode() const;
+ QString errorMessage() const;
+
+ bool prevTerminator() const;
+ bool followsClosingBrace() const;
+ bool canInsertAutomaticSemicolon(int token) const;
+
+ enum ParenthesesState {
+ IgnoreParentheses,
+ CountParentheses,
+ BalancedParentheses
+ };
+
+protected:
+ int classify(const QChar *s, int n, bool qmlMode);
+
+private:
+ inline void scanChar();
+ int scanToken();
+
+ bool isLineTerminator() const;
+ static bool isIdentLetter(QChar c);
+ static bool isDecimalDigit(ushort c);
+ static bool isHexDigit(QChar c);
+ static bool isOctalDigit(ushort c);
+ static bool isUnicodeEscapeSequence(const QChar *chars);
+
+ void syncProhibitAutomaticSemicolon();
+ QChar decodeUnicodeEscapeCharacter(bool *ok);
+
+private:
+ Engine *_engine;
+
+ QString _code;
+ QString _tokenText;
+ QString _errorMessage;
+ QStringRef _tokenSpell;
+
+ const QChar *_codePtr;
+ const QChar *_lastLinePtr;
+ const QChar *_tokenLinePtr;
+ const QChar *_tokenStartPtr;
+
+ QChar _char;
+ Error _errorCode;
+
+ int _currentLineNumber;
+ double _tokenValue;
+
+ // parentheses state
+ ParenthesesState _parenthesesState;
+ int _parenthesesCount;
+
+ int _stackToken;
+
+ int _patternFlags;
+ int _tokenKind;
+ int _tokenLength;
+ int _tokenLine;
+
+ bool _validTokenText;
+ bool _prohibitAutomaticSemicolon;
+ bool _restrictedKeyword;
+ bool _terminator;
+ bool _followsClosingBrace;
+ bool _delimited;
+ bool _qmlMode;
+};
+
+} // end of namespace QQmlJS
+
+QT_QML_END_NAMESPACE
+
+#endif // LEXER_H
diff --git a/src/qml/qml/parser/qqmljsmemorypool_p.h b/src/qml/qml/parser/qqmljsmemorypool_p.h
new file mode 100644
index 0000000000..fd52fd25e4
--- /dev/null
+++ b/src/qml/qml/parser/qqmljsmemorypool_p.h
@@ -0,0 +1,173 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLJSMEMORYPOOL_P_H
+#define QQMLJSMEMORYPOOL_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 "qqmljsglobal_p.h"
+
+#include <QtCore/qglobal.h>
+#include <QtCore/qshareddata.h>
+#include <QtCore/qdebug.h>
+
+#include <cstring>
+
+QT_QML_BEGIN_NAMESPACE
+
+namespace QQmlJS {
+
+class QML_PARSER_EXPORT MemoryPool : public QSharedData
+{
+ MemoryPool(const MemoryPool &other);
+ void operator =(const MemoryPool &other);
+
+public:
+ MemoryPool()
+ : _blocks(0),
+ _allocatedBlocks(0),
+ _blockCount(-1),
+ _ptr(0),
+ _end(0)
+ { }
+
+ ~MemoryPool()
+ {
+ if (_blocks) {
+ for (int i = 0; i < _allocatedBlocks; ++i) {
+ if (char *b = _blocks[i])
+ qFree(b);
+ }
+
+ qFree(_blocks);
+ }
+ }
+
+ inline void *allocate(size_t size)
+ {
+ size = (size + 7) & ~7;
+ if (_ptr && (_ptr + size < _end)) {
+ void *addr = _ptr;
+ _ptr += size;
+ return addr;
+ }
+ return allocate_helper(size);
+ }
+
+ void reset()
+ {
+ _blockCount = -1;
+ _ptr = _end = 0;
+ }
+
+private:
+ void *allocate_helper(size_t size)
+ {
+ Q_ASSERT(size < BLOCK_SIZE);
+
+ if (++_blockCount == _allocatedBlocks) {
+ if (! _allocatedBlocks)
+ _allocatedBlocks = DEFAULT_BLOCK_COUNT;
+ else
+ _allocatedBlocks *= 2;
+
+ _blocks = (char **) qRealloc(_blocks, sizeof(char *) * _allocatedBlocks);
+
+ for (int index = _blockCount; index < _allocatedBlocks; ++index)
+ _blocks[index] = 0;
+ }
+
+ char *&block = _blocks[_blockCount];
+
+ if (! block)
+ block = (char *) qMalloc(BLOCK_SIZE);
+
+ _ptr = block;
+ _end = _ptr + BLOCK_SIZE;
+
+ void *addr = _ptr;
+ _ptr += size;
+ return addr;
+ }
+
+private:
+ char **_blocks;
+ int _allocatedBlocks;
+ int _blockCount;
+ char *_ptr;
+ char *_end;
+
+ enum
+ {
+ BLOCK_SIZE = 8 * 1024,
+ DEFAULT_BLOCK_COUNT = 8
+ };
+};
+
+class QML_PARSER_EXPORT Managed
+{
+ Managed(const Managed &other);
+ void operator = (const Managed &other);
+
+public:
+ Managed() {}
+ ~Managed() {}
+
+ void *operator new(size_t size, MemoryPool *pool) { return pool->allocate(size); }
+ void operator delete(void *) {}
+ void operator delete(void *, MemoryPool *) {}
+};
+
+} // namespace QQmlJS
+
+QT_QML_END_NAMESPACE
+
+#endif
diff --git a/src/qml/qml/parser/qqmljsparser.cpp b/src/qml/qml/parser/qqmljsparser.cpp
new file mode 100644
index 0000000000..bc89b2ac84
--- /dev/null
+++ b/src/qml/qml/parser/qqmljsparser.cpp
@@ -0,0 +1,1812 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtCore/QtDebug>
+#include <QtCore/QCoreApplication>
+
+#include <string.h>
+
+#include "qqmljsengine_p.h"
+#include "qqmljslexer_p.h"
+#include "qqmljsast_p.h"
+#include "qqmljsmemorypool_p.h"
+
+
+
+#include "qqmljsparser_p.h"
+#include <QVarLengthArray>
+
+//
+// This file is automatically generated from qmljs.g.
+// Changes will be lost.
+//
+
+using namespace QQmlJS;
+
+QT_QML_BEGIN_NAMESPACE
+
+void Parser::reallocateStack()
+{
+ if (! stack_size)
+ stack_size = 128;
+ else
+ stack_size <<= 1;
+
+ sym_stack = reinterpret_cast<Value*> (realloc(sym_stack, stack_size * sizeof(Value)));
+ state_stack = reinterpret_cast<int*> (realloc(state_stack, stack_size * sizeof(int)));
+ location_stack = reinterpret_cast<AST::SourceLocation*> (realloc(location_stack, stack_size * sizeof(AST::SourceLocation)));
+ string_stack = reinterpret_cast<QStringRef*> (realloc(string_stack, stack_size * sizeof(QStringRef)));
+}
+
+Parser::Parser(Engine *engine):
+ driver(engine),
+ pool(engine->pool()),
+ tos(0),
+ stack_size(0),
+ sym_stack(0),
+ state_stack(0),
+ location_stack(0),
+ string_stack(0),
+ first_token(0),
+ last_token(0)
+{
+}
+
+Parser::~Parser()
+{
+ if (stack_size) {
+ free(sym_stack);
+ free(state_stack);
+ free(location_stack);
+ free(string_stack);
+ }
+}
+
+static inline AST::SourceLocation location(Lexer *lexer)
+{
+ AST::SourceLocation loc;
+ loc.offset = lexer->tokenOffset();
+ loc.length = lexer->tokenLength();
+ loc.startLine = lexer->tokenStartLine();
+ loc.startColumn = lexer->tokenStartColumn();
+ return loc;
+}
+
+AST::UiQualifiedId *Parser::reparseAsQualifiedId(AST::ExpressionNode *expr)
+{
+ QVarLengthArray<QStringRef, 4> nameIds;
+ QVarLengthArray<AST::SourceLocation, 4> locations;
+
+ AST::ExpressionNode *it = expr;
+ while (AST::FieldMemberExpression *m = AST::cast<AST::FieldMemberExpression *>(it)) {
+ nameIds.append(m->name);
+ locations.append(m->identifierToken);
+ it = m->base;
+ }
+
+ if (AST::IdentifierExpression *idExpr = AST::cast<AST::IdentifierExpression *>(it)) {
+ AST::UiQualifiedId *q = new (pool) AST::UiQualifiedId(idExpr->name);
+ q->identifierToken = idExpr->identifierToken;
+
+ AST::UiQualifiedId *currentId = q;
+ for (int i = nameIds.size() - 1; i != -1; --i) {
+ currentId = new (pool) AST::UiQualifiedId(currentId, nameIds[i]);
+ currentId->identifierToken = locations[i];
+ }
+
+ return currentId->finish();
+ }
+
+ return 0;
+}
+
+bool Parser::parse(int startToken)
+{
+ Lexer *lexer = driver->lexer();
+ bool hadErrors = false;
+ int yytoken = -1;
+ int action = 0;
+
+ token_buffer[0].token = startToken;
+ first_token = &token_buffer[0];
+ last_token = &token_buffer[1];
+
+ tos = -1;
+ program = 0;
+
+ do {
+ if (++tos == stack_size)
+ reallocateStack();
+
+ state_stack[tos] = action;
+
+ _Lcheck_token:
+ if (yytoken == -1 && -TERMINAL_COUNT != action_index[action]) {
+ yyprevlloc = yylloc;
+
+ if (first_token == last_token) {
+ yytoken = lexer->lex();
+ yylval = lexer->tokenValue();
+ yytokenspell = lexer->tokenSpell();
+ yylloc = location(lexer);
+ } else {
+ yytoken = first_token->token;
+ yylval = first_token->dval;
+ yytokenspell = first_token->spell;
+ yylloc = first_token->loc;
+ ++first_token;
+ }
+ }
+
+ action = t_action(action, yytoken);
+ if (action > 0) {
+ if (action != ACCEPT_STATE) {
+ yytoken = -1;
+ sym(1).dval = yylval;
+ stringRef(1) = yytokenspell;
+ loc(1) = yylloc;
+ } else {
+ --tos;
+ return ! hadErrors;
+ }
+ } else if (action < 0) {
+ const int r = -action - 1;
+ tos -= rhs[r];
+
+ switch (r) {
+
+case 0: {
+ sym(1).Node = sym(2).Node;
+ program = sym(1).Node;
+} break;
+
+case 1: {
+ sym(1).Node = sym(2).Node;
+ program = sym(1).Node;
+} break;
+
+case 2: {
+ sym(1).Node = sym(2).Node;
+ program = sym(1).Node;
+} break;
+
+case 3: {
+ sym(1).Node = sym(2).Node;
+ program = sym(1).Node;
+} break;
+
+case 4: {
+ sym(1).Node = sym(2).Node;
+ program = sym(1).Node;
+} break;
+
+case 5: {
+ sym(1).Node = sym(2).Node;
+ program = sym(1).Node;
+} break;
+
+case 6: {
+ sym(1).UiProgram = new (pool) AST::UiProgram(sym(1).UiImportList,
+ sym(2).UiObjectMemberList->finish());
+} break;
+
+case 8: {
+ sym(1).Node = sym(1).UiImportList->finish();
+} break;
+
+case 9: {
+ sym(1).Node = new (pool) AST::UiImportList(sym(1).UiImport);
+} break;
+
+case 10: {
+ sym(1).Node = new (pool) AST::UiImportList(sym(1).UiImportList, sym(2).UiImport);
+} break;
+
+case 13: {
+ sym(1).UiImport->semicolonToken = loc(2);
+} break;
+
+case 15: {
+ sym(1).UiImport->versionToken = loc(2);
+ sym(1).UiImport->semicolonToken = loc(3);
+} break;
+
+case 17: {
+ sym(1).UiImport->versionToken = loc(2);
+ sym(1).UiImport->asToken = loc(3);
+ sym(1).UiImport->importIdToken = loc(4);
+ sym(1).UiImport->importId = stringRef(4);
+ sym(1).UiImport->semicolonToken = loc(5);
+} break;
+
+case 19: {
+ sym(1).UiImport->asToken = loc(2);
+ sym(1).UiImport->importIdToken = loc(3);
+ sym(1).UiImport->importId = stringRef(3);
+ sym(1).UiImport->semicolonToken = loc(4);
+} break;
+
+case 20: {
+ AST::UiImport *node = 0;
+
+ if (AST::StringLiteral *importIdLiteral = AST::cast<AST::StringLiteral *>(sym(2).Expression)) {
+ node = new (pool) AST::UiImport(importIdLiteral->value);
+ node->fileNameToken = loc(2);
+ } else if (AST::UiQualifiedId *qualifiedId = reparseAsQualifiedId(sym(2).Expression)) {
+ node = new (pool) AST::UiImport(qualifiedId);
+ node->fileNameToken = loc(2);
+ }
+
+ sym(1).Node = node;
+
+ if (node) {
+ node->importToken = loc(1);
+ } else {
+ diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, loc(1),
+ QLatin1String("Expected a qualified name id or a string literal")));
+
+ return false; // ### remove me
+ }
+} break;
+
+case 21: {
+ sym(1).Node = 0;
+} break;
+
+case 22: {
+ sym(1).Node = new (pool) AST::UiObjectMemberList(sym(1).UiObjectMember);
+} break;
+
+case 23: {
+ sym(1).Node = new (pool) AST::UiObjectMemberList(sym(1).UiObjectMember);
+} break;
+
+case 24: {
+ AST::UiObjectMemberList *node = new (pool) AST:: UiObjectMemberList(
+ sym(1).UiObjectMemberList, sym(2).UiObjectMember);
+ sym(1).Node = node;
+} break;
+
+case 25: {
+ sym(1).Node = new (pool) AST::UiArrayMemberList(sym(1).UiObjectMember);
+} break;
+
+case 26: {
+ AST::UiArrayMemberList *node = new (pool) AST::UiArrayMemberList(
+ sym(1).UiArrayMemberList, sym(3).UiObjectMember);
+ node->commaToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 27: {
+ AST::UiObjectInitializer *node = new (pool) AST::UiObjectInitializer((AST::UiObjectMemberList*)0);
+ node->lbraceToken = loc(1);
+ node->rbraceToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 28: {
+ AST::UiObjectInitializer *node = new (pool) AST::UiObjectInitializer(sym(2).UiObjectMemberList->finish());
+ node->lbraceToken = loc(1);
+ node->rbraceToken = loc(3);
+ sym(1).Node = node;
+} break;
+
+case 29: {
+ AST::UiObjectDefinition *node = new (pool) AST::UiObjectDefinition(sym(1).UiQualifiedId,
+ sym(2).UiObjectInitializer);
+ sym(1).Node = node;
+} break;
+
+case 31: {
+ AST::UiArrayBinding *node = new (pool) AST::UiArrayBinding(
+ sym(1).UiQualifiedId, sym(4).UiArrayMemberList->finish());
+ node->colonToken = loc(2);
+ node->lbracketToken = loc(3);
+ node->rbracketToken = loc(5);
+ sym(1).Node = node;
+} break;
+
+case 32: {
+ AST::UiObjectBinding *node = new (pool) AST::UiObjectBinding(
+ sym(1).UiQualifiedId, sym(3).UiQualifiedId, sym(4).UiObjectInitializer);
+ node->colonToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 33: {
+ AST::UiObjectBinding *node = new (pool) AST::UiObjectBinding(
+ sym(3).UiQualifiedId, sym(1).UiQualifiedId, sym(4).UiObjectInitializer);
+ node->colonToken = loc(2);
+ node->hasOnToken = true;
+ sym(1).Node = node;
+} break;
+
+case 41:
+{
+ AST::UiScriptBinding *node = new (pool) AST::UiScriptBinding(
+ sym(1).UiQualifiedId, sym(3).Statement);
+ node->colonToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 45: {
+ sym(1).Node = 0;
+} break;
+
+case 46: {
+ sym(1).Node = sym(1).UiParameterList->finish ();
+} break;
+
+case 47: {
+ AST::UiParameterList *node = new (pool) AST::UiParameterList(stringRef(1), stringRef(2));
+ node->propertyTypeToken = loc(1);
+ node->identifierToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 48: {
+ AST::UiParameterList *node = new (pool) AST::UiParameterList(sym(1).UiParameterList, stringRef(3), stringRef(4));
+ node->commaToken = loc(2);
+ node->identifierToken = loc(4);
+ sym(1).Node = node;
+} break;
+
+case 50: {
+ AST::UiPublicMember *node = new (pool) AST::UiPublicMember(QStringRef(), stringRef(2));
+ node->type = AST::UiPublicMember::Signal;
+ node->propertyToken = loc(1);
+ node->typeToken = loc(2);
+ node->identifierToken = loc(2);
+ node->parameters = sym(4).UiParameterList;
+ node->semicolonToken = loc(6);
+ sym(1).Node = node;
+} break;
+
+case 52: {
+ AST::UiPublicMember *node = new (pool) AST::UiPublicMember(QStringRef(), stringRef(2));
+ node->type = AST::UiPublicMember::Signal;
+ node->propertyToken = loc(1);
+ node->typeToken = loc(2);
+ node->identifierToken = loc(2);
+ node->semicolonToken = loc(3);
+ sym(1).Node = node;
+} break;
+
+case 54: {
+ AST::UiPublicMember *node = new (pool) AST::UiPublicMember(stringRef(4), stringRef(6));
+ node->typeModifier = stringRef(2);
+ node->propertyToken = loc(1);
+ node->typeModifierToken = loc(2);
+ node->typeToken = loc(4);
+ node->identifierToken = loc(6);
+ node->semicolonToken = loc(7);
+ sym(1).Node = node;
+} break;
+
+case 56: {
+ AST::UiPublicMember *node = new (pool) AST::UiPublicMember(stringRef(2), stringRef(3));
+ node->propertyToken = loc(1);
+ node->typeToken = loc(2);
+ node->identifierToken = loc(3);
+ node->semicolonToken = loc(4);
+ sym(1).Node = node;
+} break;
+
+case 58: {
+ AST::UiPublicMember *node = new (pool) AST::UiPublicMember(stringRef(3), stringRef(4));
+ node->isDefaultMember = true;
+ node->defaultToken = loc(1);
+ node->propertyToken = loc(2);
+ node->typeToken = loc(3);
+ node->identifierToken = loc(4);
+ node->semicolonToken = loc(5);
+ sym(1).Node = node;
+} break;
+
+case 59: {
+ AST::UiPublicMember *node = new (pool) AST::UiPublicMember(stringRef(2), stringRef(3),
+ sym(5).Statement);
+ node->propertyToken = loc(1);
+ node->typeToken = loc(2);
+ node->identifierToken = loc(3);
+ node->colonToken = loc(4);
+ sym(1).Node = node;
+} break;
+
+case 60: {
+ AST::UiPublicMember *node = new (pool) AST::UiPublicMember(stringRef(3), stringRef(4),
+ sym(6).Statement);
+ node->isReadonlyMember = true;
+ node->readonlyToken = loc(1);
+ node->propertyToken = loc(2);
+ node->typeToken = loc(3);
+ node->identifierToken = loc(4);
+ node->colonToken = loc(5);
+ sym(1).Node = node;
+} break;
+
+case 61: {
+ AST::UiPublicMember *node = new (pool) AST::UiPublicMember(stringRef(3), stringRef(4),
+ sym(6).Statement);
+ node->isDefaultMember = true;
+ node->defaultToken = loc(1);
+ node->propertyToken = loc(2);
+ node->typeToken = loc(3);
+ node->identifierToken = loc(4);
+ node->colonToken = loc(5);
+ sym(1).Node = node;
+} break;
+
+case 62: {
+ AST::UiPublicMember *node = new (pool) AST::UiPublicMember(stringRef(4), stringRef(6));
+ node->typeModifier = stringRef(2);
+ node->propertyToken = loc(1);
+ node->typeModifierToken = loc(2);
+ node->typeToken = loc(4);
+ node->identifierToken = loc(6);
+ node->semicolonToken = loc(7); // insert a fake ';' before ':'
+
+ AST::UiQualifiedId *propertyName = new (pool) AST::UiQualifiedId(stringRef(6));
+ propertyName->identifierToken = loc(6);
+ propertyName->next = 0;
+
+ AST::UiArrayBinding *binding = new (pool) AST::UiArrayBinding(
+ propertyName, sym(9).UiArrayMemberList->finish());
+ binding->colonToken = loc(7);
+ binding->lbracketToken = loc(8);
+ binding->rbracketToken = loc(10);
+
+ node->binding = binding;
+
+ sym(1).Node = node;
+} break;
+
+case 63: {
+ AST::UiPublicMember *node = new (pool) AST::UiPublicMember(stringRef(2), stringRef(3));
+ node->propertyToken = loc(1);
+ node->typeToken = loc(2);
+ node->identifierToken = loc(3);
+ node->semicolonToken = loc(4); // insert a fake ';' before ':'
+
+ AST::UiQualifiedId *propertyName = new (pool) AST::UiQualifiedId(stringRef(3));
+ propertyName->identifierToken = loc(3);
+ propertyName->next = 0;
+
+ AST::UiObjectBinding *binding = new (pool) AST::UiObjectBinding(
+ propertyName, sym(5).UiQualifiedId, sym(6).UiObjectInitializer);
+ binding->colonToken = loc(4);
+
+ node->binding = binding;
+
+ sym(1).Node = node;
+} break;
+
+case 64: {
+ sym(1).Node = new (pool) AST::UiSourceElement(sym(1).Node);
+} break;
+
+case 65: {
+ sym(1).Node = new (pool) AST::UiSourceElement(sym(1).Node);
+} break;
+
+case 71: {
+ AST::ThisExpression *node = new (pool) AST::ThisExpression();
+ node->thisToken = loc(1);
+ sym(1).Node = node;
+} break;
+
+case 72: {
+ AST::IdentifierExpression *node = new (pool) AST::IdentifierExpression(stringRef(1));
+ node->identifierToken = loc(1);
+ sym(1).Node = node;
+} break;
+
+case 73: {
+ AST::NullExpression *node = new (pool) AST::NullExpression();
+ node->nullToken = loc(1);
+ sym(1).Node = node;
+} break;
+
+case 74: {
+ AST::TrueLiteral *node = new (pool) AST::TrueLiteral();
+ node->trueToken = loc(1);
+ sym(1).Node = node;
+} break;
+
+case 75: {
+ AST::FalseLiteral *node = new (pool) AST::FalseLiteral();
+ node->falseToken = loc(1);
+ sym(1).Node = node;
+} break;
+
+case 76: {
+ AST::NumericLiteral *node = new (pool) AST::NumericLiteral(sym(1).dval);
+ node->literalToken = loc(1);
+ sym(1).Node = node;
+} break;
+case 77:
+case 78: {
+ AST::StringLiteral *node = new (pool) AST::StringLiteral(stringRef(1));
+ node->literalToken = loc(1);
+ sym(1).Node = node;
+} break;
+
+case 79: {
+ bool rx = lexer->scanRegExp(Lexer::NoPrefix);
+ if (!rx) {
+ diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, location(lexer), lexer->errorMessage()));
+ return false; // ### remove me
+ }
+
+ loc(1).length = lexer->tokenLength();
+ yylloc = loc(1); // adjust the location of the current token
+
+ AST::RegExpLiteral *node = new (pool) AST::RegExpLiteral(
+ driver->newStringRef(lexer->regExpPattern()), lexer->regExpFlags());
+ node->literalToken = loc(1);
+ sym(1).Node = node;
+} break;
+
+case 80: {
+ bool rx = lexer->scanRegExp(Lexer::EqualPrefix);
+ if (!rx) {
+ diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, location(lexer), lexer->errorMessage()));
+ return false;
+ }
+
+ loc(1).length = lexer->tokenLength();
+ yylloc = loc(1); // adjust the location of the current token
+
+ AST::RegExpLiteral *node = new (pool) AST::RegExpLiteral(
+ driver->newStringRef(lexer->regExpPattern()), lexer->regExpFlags());
+ node->literalToken = loc(1);
+ sym(1).Node = node;
+} break;
+
+case 81: {
+ AST::ArrayLiteral *node = new (pool) AST::ArrayLiteral((AST::Elision *) 0);
+ node->lbracketToken = loc(1);
+ node->rbracketToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 82: {
+ AST::ArrayLiteral *node = new (pool) AST::ArrayLiteral(sym(2).Elision->finish());
+ node->lbracketToken = loc(1);
+ node->rbracketToken = loc(3);
+ sym(1).Node = node;
+} break;
+
+case 83: {
+ AST::ArrayLiteral *node = new (pool) AST::ArrayLiteral(sym(2).ElementList->finish ());
+ node->lbracketToken = loc(1);
+ node->rbracketToken = loc(3);
+ sym(1).Node = node;
+} break;
+
+case 84: {
+ AST::ArrayLiteral *node = new (pool) AST::ArrayLiteral(sym(2).ElementList->finish (),
+ (AST::Elision *) 0);
+ node->lbracketToken = loc(1);
+ node->commaToken = loc(3);
+ node->rbracketToken = loc(4);
+ sym(1).Node = node;
+} break;
+
+case 85: {
+ AST::ArrayLiteral *node = new (pool) AST::ArrayLiteral(sym(2).ElementList->finish (),
+ sym(4).Elision->finish());
+ node->lbracketToken = loc(1);
+ node->commaToken = loc(3);
+ node->rbracketToken = loc(5);
+ sym(1).Node = node;
+} break;
+
+case 86: {
+ AST::ObjectLiteral *node = 0;
+ if (sym(2).Node)
+ node = new (pool) AST::ObjectLiteral(
+ sym(2).PropertyNameAndValueList->finish ());
+ else
+ node = new (pool) AST::ObjectLiteral();
+ node->lbraceToken = loc(1);
+ node->rbraceToken = loc(3);
+ sym(1).Node = node;
+} break;
+
+case 87: {
+ AST::ObjectLiteral *node = new (pool) AST::ObjectLiteral(
+ sym(2).PropertyNameAndValueList->finish ());
+ node->lbraceToken = loc(1);
+ node->rbraceToken = loc(4);
+ sym(1).Node = node;
+} break;
+
+case 88: {
+ AST::NestedExpression *node = new (pool) AST::NestedExpression(sym(2).Expression);
+ node->lparenToken = loc(1);
+ node->rparenToken = loc(3);
+ sym(1).Node = node;
+} break;
+
+case 89: {
+ if (AST::ArrayMemberExpression *mem = AST::cast<AST::ArrayMemberExpression *>(sym(1).Expression)) {
+ diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Warning, mem->lbracketToken,
+ QLatin1String("Ignored annotation")));
+
+ sym(1).Expression = mem->base;
+ }
+
+ if (AST::UiQualifiedId *qualifiedId = reparseAsQualifiedId(sym(1).Expression)) {
+ sym(1).UiQualifiedId = qualifiedId;
+ } else {
+ sym(1).UiQualifiedId = 0;
+
+ diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, loc(1),
+ QLatin1String("Expected a qualified name id")));
+
+ return false; // ### recover
+ }
+} break;
+
+case 90: {
+ sym(1).Node = new (pool) AST::ElementList((AST::Elision *) 0, sym(1).Expression);
+} break;
+
+case 91: {
+ sym(1).Node = new (pool) AST::ElementList(sym(1).Elision->finish(), sym(2).Expression);
+} break;
+
+case 92: {
+ AST::ElementList *node = new (pool) AST::ElementList(sym(1).ElementList,
+ (AST::Elision *) 0, sym(3).Expression);
+ node->commaToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 93: {
+ AST::ElementList *node = new (pool) AST::ElementList(sym(1).ElementList, sym(3).Elision->finish(),
+ sym(4).Expression);
+ node->commaToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 94: {
+ AST::Elision *node = new (pool) AST::Elision();
+ node->commaToken = loc(1);
+ sym(1).Node = node;
+} break;
+
+case 95: {
+ AST::Elision *node = new (pool) AST::Elision(sym(1).Elision);
+ node->commaToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 96: {
+ AST::PropertyNameAndValueList *node = new (pool) AST::PropertyNameAndValueList(
+ sym(1).PropertyName, sym(3).Expression);
+ node->colonToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 97: {
+ AST::PropertyNameAndValueList *node = new (pool) AST::PropertyNameAndValueList(
+ sym(1).PropertyNameAndValueList, sym(3).PropertyName, sym(5).Expression);
+ node->commaToken = loc(2);
+ node->colonToken = loc(4);
+ sym(1).Node = node;
+} break;
+
+case 98: {
+ AST::IdentifierPropertyName *node = new (pool) AST::IdentifierPropertyName(stringRef(1));
+ node->propertyNameToken = loc(1);
+ sym(1).Node = node;
+} break;
+case 99:
+case 100: {
+ AST::IdentifierPropertyName *node = new (pool) AST::IdentifierPropertyName(stringRef(1));
+ node->propertyNameToken = loc(1);
+ sym(1).Node = node;
+} break;
+
+case 101: {
+ AST::StringLiteralPropertyName *node = new (pool) AST::StringLiteralPropertyName(stringRef(1));
+ node->propertyNameToken = loc(1);
+ sym(1).Node = node;
+} break;
+
+case 102: {
+ AST::NumericLiteralPropertyName *node = new (pool) AST::NumericLiteralPropertyName(sym(1).dval);
+ node->propertyNameToken = loc(1);
+ sym(1).Node = node;
+} break;
+
+case 103: {
+ AST::IdentifierPropertyName *node = new (pool) AST::IdentifierPropertyName(stringRef(1));
+ node->propertyNameToken = loc(1);
+ sym(1).Node = node;
+} break;
+
+case 139: {
+ AST::ArrayMemberExpression *node = new (pool) AST::ArrayMemberExpression(sym(1).Expression, sym(3).Expression);
+ node->lbracketToken = loc(2);
+ node->rbracketToken = loc(4);
+ sym(1).Node = node;
+} break;
+
+case 140: {
+ AST::FieldMemberExpression *node = new (pool) AST::FieldMemberExpression(sym(1).Expression, stringRef(3));
+ node->dotToken = loc(2);
+ node->identifierToken = loc(3);
+ sym(1).Node = node;
+} break;
+
+case 141: {
+ AST::NewMemberExpression *node = new (pool) AST::NewMemberExpression(sym(2).Expression, sym(4).ArgumentList);
+ node->newToken = loc(1);
+ node->lparenToken = loc(3);
+ node->rparenToken = loc(5);
+ sym(1).Node = node;
+} break;
+
+case 143: {
+ AST::NewExpression *node = new (pool) AST::NewExpression(sym(2).Expression);
+ node->newToken = loc(1);
+ sym(1).Node = node;
+} break;
+
+case 144: {
+ AST::CallExpression *node = new (pool) AST::CallExpression(sym(1).Expression, sym(3).ArgumentList);
+ node->lparenToken = loc(2);
+ node->rparenToken = loc(4);
+ sym(1).Node = node;
+} break;
+
+case 145: {
+ AST::CallExpression *node = new (pool) AST::CallExpression(sym(1).Expression, sym(3).ArgumentList);
+ node->lparenToken = loc(2);
+ node->rparenToken = loc(4);
+ sym(1).Node = node;
+} break;
+
+case 146: {
+ AST::ArrayMemberExpression *node = new (pool) AST::ArrayMemberExpression(sym(1).Expression, sym(3).Expression);
+ node->lbracketToken = loc(2);
+ node->rbracketToken = loc(4);
+ sym(1).Node = node;
+} break;
+
+case 147: {
+ AST::FieldMemberExpression *node = new (pool) AST::FieldMemberExpression(sym(1).Expression, stringRef(3));
+ node->dotToken = loc(2);
+ node->identifierToken = loc(3);
+ sym(1).Node = node;
+} break;
+
+case 148: {
+ sym(1).Node = 0;
+} break;
+
+case 149: {
+ sym(1).Node = sym(1).ArgumentList->finish();
+} break;
+
+case 150: {
+ sym(1).Node = new (pool) AST::ArgumentList(sym(1).Expression);
+} break;
+
+case 151: {
+ AST::ArgumentList *node = new (pool) AST::ArgumentList(sym(1).ArgumentList, sym(3).Expression);
+ node->commaToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 155: {
+ AST::PostIncrementExpression *node = new (pool) AST::PostIncrementExpression(sym(1).Expression);
+ node->incrementToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 156: {
+ AST::PostDecrementExpression *node = new (pool) AST::PostDecrementExpression(sym(1).Expression);
+ node->decrementToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 158: {
+ AST::DeleteExpression *node = new (pool) AST::DeleteExpression(sym(2).Expression);
+ node->deleteToken = loc(1);
+ sym(1).Node = node;
+} break;
+
+case 159: {
+ AST::VoidExpression *node = new (pool) AST::VoidExpression(sym(2).Expression);
+ node->voidToken = loc(1);
+ sym(1).Node = node;
+} break;
+
+case 160: {
+ AST::TypeOfExpression *node = new (pool) AST::TypeOfExpression(sym(2).Expression);
+ node->typeofToken = loc(1);
+ sym(1).Node = node;
+} break;
+
+case 161: {
+ AST::PreIncrementExpression *node = new (pool) AST::PreIncrementExpression(sym(2).Expression);
+ node->incrementToken = loc(1);
+ sym(1).Node = node;
+} break;
+
+case 162: {
+ AST::PreDecrementExpression *node = new (pool) AST::PreDecrementExpression(sym(2).Expression);
+ node->decrementToken = loc(1);
+ sym(1).Node = node;
+} break;
+
+case 163: {
+ AST::UnaryPlusExpression *node = new (pool) AST::UnaryPlusExpression(sym(2).Expression);
+ node->plusToken = loc(1);
+ sym(1).Node = node;
+} break;
+
+case 164: {
+ AST::UnaryMinusExpression *node = new (pool) AST::UnaryMinusExpression(sym(2).Expression);
+ node->minusToken = loc(1);
+ sym(1).Node = node;
+} break;
+
+case 165: {
+ AST::TildeExpression *node = new (pool) AST::TildeExpression(sym(2).Expression);
+ node->tildeToken = loc(1);
+ sym(1).Node = node;
+} break;
+
+case 166: {
+ AST::NotExpression *node = new (pool) AST::NotExpression(sym(2).Expression);
+ node->notToken = loc(1);
+ sym(1).Node = node;
+} break;
+
+case 168: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::Mul, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 169: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::Div, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 170: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::Mod, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 172: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::Add, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 173: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::Sub, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 175: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::LShift, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 176: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::RShift, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 177: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::URShift, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 179: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::Lt, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 180: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::Gt, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 181: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::Le, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 182: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::Ge, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 183: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::InstanceOf, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 184: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::In, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 186: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::Lt, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 187: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::Gt, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 188: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::Le, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 189: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::Ge, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 190: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::InstanceOf, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 192: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::Equal, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 193: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::NotEqual, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 194: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::StrictEqual, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 195: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::StrictNotEqual, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 197: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::Equal, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 198: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::NotEqual, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 199: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::StrictEqual, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 200: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::StrictNotEqual, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 202: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::BitAnd, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 204: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::BitAnd, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 206: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::BitXor, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 208: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::BitXor, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 210: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::BitOr, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 212: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::BitOr, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 214: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::And, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 216: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::And, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 218: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::Or, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 220: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::Or, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 222: {
+ AST::ConditionalExpression *node = new (pool) AST::ConditionalExpression(sym(1).Expression,
+ sym(3).Expression, sym(5).Expression);
+ node->questionToken = loc(2);
+ node->colonToken = loc(4);
+ sym(1).Node = node;
+} break;
+
+case 224: {
+ AST::ConditionalExpression *node = new (pool) AST::ConditionalExpression(sym(1).Expression,
+ sym(3).Expression, sym(5).Expression);
+ node->questionToken = loc(2);
+ node->colonToken = loc(4);
+ sym(1).Node = node;
+} break;
+
+case 226: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ sym(2).ival, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 228: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ sym(2).ival, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 229: {
+ sym(1).ival = QSOperator::Assign;
+} break;
+
+case 230: {
+ sym(1).ival = QSOperator::InplaceMul;
+} break;
+
+case 231: {
+ sym(1).ival = QSOperator::InplaceDiv;
+} break;
+
+case 232: {
+ sym(1).ival = QSOperator::InplaceMod;
+} break;
+
+case 233: {
+ sym(1).ival = QSOperator::InplaceAdd;
+} break;
+
+case 234: {
+ sym(1).ival = QSOperator::InplaceSub;
+} break;
+
+case 235: {
+ sym(1).ival = QSOperator::InplaceLeftShift;
+} break;
+
+case 236: {
+ sym(1).ival = QSOperator::InplaceRightShift;
+} break;
+
+case 237: {
+ sym(1).ival = QSOperator::InplaceURightShift;
+} break;
+
+case 238: {
+ sym(1).ival = QSOperator::InplaceAnd;
+} break;
+
+case 239: {
+ sym(1).ival = QSOperator::InplaceXor;
+} break;
+
+case 240: {
+ sym(1).ival = QSOperator::InplaceOr;
+} break;
+
+case 242: {
+ AST::Expression *node = new (pool) AST::Expression(sym(1).Expression, sym(3).Expression);
+ node->commaToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 243: {
+ sym(1).Node = 0;
+} break;
+
+case 246: {
+ AST::Expression *node = new (pool) AST::Expression(sym(1).Expression, sym(3).Expression);
+ node->commaToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 247: {
+ sym(1).Node = 0;
+} break;
+
+case 264: {
+ AST::Block *node = new (pool) AST::Block(sym(2).StatementList);
+ node->lbraceToken = loc(1);
+ node->rbraceToken = loc(3);
+ sym(1).Node = node;
+} break;
+
+case 265: {
+ sym(1).Node = new (pool) AST::StatementList(sym(1).Statement);
+} break;
+
+case 266: {
+ sym(1).Node = new (pool) AST::StatementList(sym(1).StatementList, sym(2).Statement);
+} break;
+
+case 267: {
+ sym(1).Node = 0;
+} break;
+
+case 268: {
+ sym(1).Node = sym(1).StatementList->finish ();
+} break;
+
+case 270: {
+ AST::VariableStatement *node = new (pool) AST::VariableStatement(
+ sym(2).VariableDeclarationList->finish (/*readOnly=*/sym(1).ival == T_CONST));
+ node->declarationKindToken = loc(1);
+ node->semicolonToken = loc(3);
+ sym(1).Node = node;
+} break;
+
+case 271: {
+ sym(1).ival = T_CONST;
+} break;
+
+case 272: {
+ sym(1).ival = T_VAR;
+} break;
+
+case 273: {
+ sym(1).Node = new (pool) AST::VariableDeclarationList(sym(1).VariableDeclaration);
+} break;
+
+case 274: {
+ AST::VariableDeclarationList *node = new (pool) AST::VariableDeclarationList(
+ sym(1).VariableDeclarationList, sym(3).VariableDeclaration);
+ node->commaToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 275: {
+ sym(1).Node = new (pool) AST::VariableDeclarationList(sym(1).VariableDeclaration);
+} break;
+
+case 276: {
+ sym(1).Node = new (pool) AST::VariableDeclarationList(sym(1).VariableDeclarationList, sym(3).VariableDeclaration);
+} break;
+
+case 277: {
+ AST::VariableDeclaration *node = new (pool) AST::VariableDeclaration(stringRef(1), sym(2).Expression);
+ node->identifierToken = loc(1);
+ sym(1).Node = node;
+} break;
+
+case 278: {
+ AST::VariableDeclaration *node = new (pool) AST::VariableDeclaration(stringRef(1), sym(2).Expression);
+ node->identifierToken = loc(1);
+ sym(1).Node = node;
+} break;
+
+case 279: {
+ // ### TODO: AST for initializer
+ sym(1) = sym(2);
+} break;
+
+case 280: {
+ sym(1).Node = 0;
+} break;
+
+case 282: {
+ // ### TODO: AST for initializer
+ sym(1) = sym(2);
+} break;
+
+case 283: {
+ sym(1).Node = 0;
+} break;
+
+case 285: {
+ AST::EmptyStatement *node = new (pool) AST::EmptyStatement();
+ node->semicolonToken = loc(1);
+ sym(1).Node = node;
+} break;
+
+case 287: {
+ AST::ExpressionStatement *node = new (pool) AST::ExpressionStatement(sym(1).Expression);
+ node->semicolonToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 288: {
+ AST::IfStatement *node = new (pool) AST::IfStatement(sym(3).Expression, sym(5).Statement, sym(7).Statement);
+ node->ifToken = loc(1);
+ node->lparenToken = loc(2);
+ node->rparenToken = loc(4);
+ node->elseToken = loc(6);
+ sym(1).Node = node;
+} break;
+
+case 289: {
+ AST::IfStatement *node = new (pool) AST::IfStatement(sym(3).Expression, sym(5).Statement);
+ node->ifToken = loc(1);
+ node->lparenToken = loc(2);
+ node->rparenToken = loc(4);
+ sym(1).Node = node;
+} break;
+
+case 291: {
+ AST::DoWhileStatement *node = new (pool) AST::DoWhileStatement(sym(2).Statement, sym(5).Expression);
+ node->doToken = loc(1);
+ node->whileToken = loc(3);
+ node->lparenToken = loc(4);
+ node->rparenToken = loc(6);
+ node->semicolonToken = loc(7);
+ sym(1).Node = node;
+} break;
+
+case 292: {
+ AST::WhileStatement *node = new (pool) AST::WhileStatement(sym(3).Expression, sym(5).Statement);
+ node->whileToken = loc(1);
+ node->lparenToken = loc(2);
+ node->rparenToken = loc(4);
+ sym(1).Node = node;
+} break;
+
+case 293: {
+ AST::ForStatement *node = new (pool) AST::ForStatement(sym(3).Expression,
+ sym(5).Expression, sym(7).Expression, sym(9).Statement);
+ node->forToken = loc(1);
+ node->lparenToken = loc(2);
+ node->firstSemicolonToken = loc(4);
+ node->secondSemicolonToken = loc(6);
+ node->rparenToken = loc(8);
+ sym(1).Node = node;
+} break;
+
+case 294: {
+ AST::LocalForStatement *node = new (pool) AST::LocalForStatement(
+ sym(4).VariableDeclarationList->finish (/*readOnly=*/false), sym(6).Expression,
+ sym(8).Expression, sym(10).Statement);
+ node->forToken = loc(1);
+ node->lparenToken = loc(2);
+ node->varToken = loc(3);
+ node->firstSemicolonToken = loc(5);
+ node->secondSemicolonToken = loc(7);
+ node->rparenToken = loc(9);
+ sym(1).Node = node;
+} break;
+
+case 295: {
+ AST:: ForEachStatement *node = new (pool) AST::ForEachStatement(sym(3).Expression,
+ sym(5).Expression, sym(7).Statement);
+ node->forToken = loc(1);
+ node->lparenToken = loc(2);
+ node->inToken = loc(4);
+ node->rparenToken = loc(6);
+ sym(1).Node = node;
+} break;
+
+case 296: {
+ AST::LocalForEachStatement *node = new (pool) AST::LocalForEachStatement(
+ sym(4).VariableDeclaration, sym(6).Expression, sym(8).Statement);
+ node->forToken = loc(1);
+ node->lparenToken = loc(2);
+ node->varToken = loc(3);
+ node->inToken = loc(5);
+ node->rparenToken = loc(7);
+ sym(1).Node = node;
+} break;
+
+case 298: {
+ AST::ContinueStatement *node = new (pool) AST::ContinueStatement();
+ node->continueToken = loc(1);
+ node->semicolonToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 300: {
+ AST::ContinueStatement *node = new (pool) AST::ContinueStatement(stringRef(2));
+ node->continueToken = loc(1);
+ node->identifierToken = loc(2);
+ node->semicolonToken = loc(3);
+ sym(1).Node = node;
+} break;
+
+case 302: {
+ AST::BreakStatement *node = new (pool) AST::BreakStatement(QStringRef());
+ node->breakToken = loc(1);
+ node->semicolonToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 304: {
+ AST::BreakStatement *node = new (pool) AST::BreakStatement(stringRef(2));
+ node->breakToken = loc(1);
+ node->identifierToken = loc(2);
+ node->semicolonToken = loc(3);
+ sym(1).Node = node;
+} break;
+
+case 306: {
+ AST::ReturnStatement *node = new (pool) AST::ReturnStatement(sym(2).Expression);
+ node->returnToken = loc(1);
+ node->semicolonToken = loc(3);
+ sym(1).Node = node;
+} break;
+
+case 307: {
+ AST::WithStatement *node = new (pool) AST::WithStatement(sym(3).Expression, sym(5).Statement);
+ node->withToken = loc(1);
+ node->lparenToken = loc(2);
+ node->rparenToken = loc(4);
+ sym(1).Node = node;
+} break;
+
+case 308: {
+ AST::SwitchStatement *node = new (pool) AST::SwitchStatement(sym(3).Expression, sym(5).CaseBlock);
+ node->switchToken = loc(1);
+ node->lparenToken = loc(2);
+ node->rparenToken = loc(4);
+ sym(1).Node = node;
+} break;
+
+case 309: {
+ AST::CaseBlock *node = new (pool) AST::CaseBlock(sym(2).CaseClauses);
+ node->lbraceToken = loc(1);
+ node->rbraceToken = loc(3);
+ sym(1).Node = node;
+} break;
+
+case 310: {
+ AST::CaseBlock *node = new (pool) AST::CaseBlock(sym(2).CaseClauses, sym(3).DefaultClause, sym(4).CaseClauses);
+ node->lbraceToken = loc(1);
+ node->rbraceToken = loc(5);
+ sym(1).Node = node;
+} break;
+
+case 311: {
+ sym(1).Node = new (pool) AST::CaseClauses(sym(1).CaseClause);
+} break;
+
+case 312: {
+ sym(1).Node = new (pool) AST::CaseClauses(sym(1).CaseClauses, sym(2).CaseClause);
+} break;
+
+case 313: {
+ sym(1).Node = 0;
+} break;
+
+case 314: {
+ sym(1).Node = sym(1).CaseClauses->finish ();
+} break;
+
+case 315: {
+ AST::CaseClause *node = new (pool) AST::CaseClause(sym(2).Expression, sym(4).StatementList);
+ node->caseToken = loc(1);
+ node->colonToken = loc(3);
+ sym(1).Node = node;
+} break;
+
+case 316: {
+ AST::DefaultClause *node = new (pool) AST::DefaultClause(sym(3).StatementList);
+ node->defaultToken = loc(1);
+ node->colonToken = loc(2);
+ sym(1).Node = node;
+} break;
+case 317:
+case 318: {
+ AST::LabelledStatement *node = new (pool) AST::LabelledStatement(stringRef(1), sym(3).Statement);
+ node->identifierToken = loc(1);
+ node->colonToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 319: {
+ AST::LabelledStatement *node = new (pool) AST::LabelledStatement(stringRef(1), sym(3).Statement);
+ node->identifierToken = loc(1);
+ node->colonToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 321: {
+ AST::ThrowStatement *node = new (pool) AST::ThrowStatement(sym(2).Expression);
+ node->throwToken = loc(1);
+ node->semicolonToken = loc(3);
+ sym(1).Node = node;
+} break;
+
+case 322: {
+ AST::TryStatement *node = new (pool) AST::TryStatement(sym(2).Statement, sym(3).Catch);
+ node->tryToken = loc(1);
+ sym(1).Node = node;
+} break;
+
+case 323: {
+ AST::TryStatement *node = new (pool) AST::TryStatement(sym(2).Statement, sym(3).Finally);
+ node->tryToken = loc(1);
+ sym(1).Node = node;
+} break;
+
+case 324: {
+ AST::TryStatement *node = new (pool) AST::TryStatement(sym(2).Statement, sym(3).Catch, sym(4).Finally);
+ node->tryToken = loc(1);
+ sym(1).Node = node;
+} break;
+
+case 325: {
+ AST::Catch *node = new (pool) AST::Catch(stringRef(3), sym(5).Block);
+ node->catchToken = loc(1);
+ node->lparenToken = loc(2);
+ node->identifierToken = loc(3);
+ node->rparenToken = loc(4);
+ sym(1).Node = node;
+} break;
+
+case 326: {
+ AST::Finally *node = new (pool) AST::Finally(sym(2).Block);
+ node->finallyToken = loc(1);
+ sym(1).Node = node;
+} break;
+
+case 328: {
+ AST::DebuggerStatement *node = new (pool) AST::DebuggerStatement();
+ node->debuggerToken = loc(1);
+ node->semicolonToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 329: {
+ AST::FunctionDeclaration *node = new (pool) AST::FunctionDeclaration(stringRef(2), sym(4).FormalParameterList, sym(7).FunctionBody);
+ node->functionToken = loc(1);
+ node->identifierToken = loc(2);
+ node->lparenToken = loc(3);
+ node->rparenToken = loc(5);
+ node->lbraceToken = loc(6);
+ node->rbraceToken = loc(8);
+ sym(1).Node = node;
+} break;
+
+case 330: {
+ AST::FunctionExpression *node = new (pool) AST::FunctionExpression(stringRef(2), sym(4).FormalParameterList, sym(7).FunctionBody);
+ node->functionToken = loc(1);
+ if (! stringRef(2).isNull())
+ node->identifierToken = loc(2);
+ node->lparenToken = loc(3);
+ node->rparenToken = loc(5);
+ node->lbraceToken = loc(6);
+ node->rbraceToken = loc(8);
+ sym(1).Node = node;
+} break;
+
+case 331: {
+ AST::FormalParameterList *node = new (pool) AST::FormalParameterList(stringRef(1));
+ node->identifierToken = loc(1);
+ sym(1).Node = node;
+} break;
+
+case 332: {
+ AST::FormalParameterList *node = new (pool) AST::FormalParameterList(sym(1).FormalParameterList, stringRef(3));
+ node->commaToken = loc(2);
+ node->identifierToken = loc(3);
+ sym(1).Node = node;
+} break;
+
+case 333: {
+ sym(1).Node = 0;
+} break;
+
+case 334: {
+ sym(1).Node = sym(1).FormalParameterList->finish ();
+} break;
+
+case 335: {
+ sym(1).Node = 0;
+} break;
+
+case 337: {
+ sym(1).Node = new (pool) AST::FunctionBody(sym(1).SourceElements->finish ());
+} break;
+
+case 339: {
+ sym(1).Node = new (pool) AST::Program(sym(1).SourceElements->finish ());
+} break;
+
+case 340: {
+ sym(1).Node = new (pool) AST::SourceElements(sym(1).SourceElement);
+} break;
+
+case 341: {
+ sym(1).Node = new (pool) AST::SourceElements(sym(1).SourceElements, sym(2).SourceElement);
+} break;
+
+case 342: {
+ sym(1).Node = new (pool) AST::StatementSourceElement(sym(1).Statement);
+} break;
+
+case 343: {
+ sym(1).Node = new (pool) AST::FunctionSourceElement(sym(1).FunctionDeclaration);
+} break;
+
+case 344: {
+ stringRef(1) = QStringRef();
+} break;
+
+case 346: {
+ sym(1).Node = 0;
+} break;
+
+ } // switch
+ action = nt_action(state_stack[tos], lhs[r] - TERMINAL_COUNT);
+ } // if
+ } while (action != 0);
+
+ if (first_token == last_token) {
+ const int errorState = state_stack[tos];
+
+ // automatic insertion of `;'
+ if (yytoken != -1 && t_action(errorState, T_AUTOMATIC_SEMICOLON) && lexer->canInsertAutomaticSemicolon(yytoken)) {
+ SavedToken &tk = token_buffer[0];
+ tk.token = yytoken;
+ tk.dval = yylval;
+ tk.spell = yytokenspell;
+ tk.loc = yylloc;
+
+ yylloc = yyprevlloc;
+ yylloc.offset += yylloc.length;
+ yylloc.startColumn += yylloc.length;
+ yylloc.length = 0;
+
+ //const QString msg = qApp->translate("QQmlParser", "Missing `;'");
+ //diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Warning, yylloc, msg));
+
+ first_token = &token_buffer[0];
+ last_token = &token_buffer[1];
+
+ yytoken = T_SEMICOLON;
+ yylval = 0;
+
+ action = errorState;
+
+ goto _Lcheck_token;
+ }
+
+ hadErrors = true;
+
+ token_buffer[0].token = yytoken;
+ token_buffer[0].dval = yylval;
+ token_buffer[0].spell = yytokenspell;
+ token_buffer[0].loc = yylloc;
+
+ token_buffer[1].token = yytoken = lexer->lex();
+ token_buffer[1].dval = yylval = lexer->tokenValue();
+ token_buffer[1].spell = yytokenspell = lexer->tokenSpell();
+ token_buffer[1].loc = yylloc = location(lexer);
+
+ if (t_action(errorState, yytoken)) {
+ QString msg;
+ int token = token_buffer[0].token;
+ if (token < 0 || token >= TERMINAL_COUNT)
+ msg = qApp->translate("QQmlParser", "Syntax error");
+ else
+ msg = qApp->translate("QQmlParser", "Unexpected token `%1'").arg(QLatin1String(spell[token]));
+ diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, token_buffer[0].loc, msg));
+
+ action = errorState;
+ goto _Lcheck_token;
+ }
+
+ static int tokens[] = {
+ T_PLUS,
+ T_EQ,
+
+ T_COMMA,
+ T_COLON,
+ T_SEMICOLON,
+
+ T_RPAREN, T_RBRACKET, T_RBRACE,
+
+ T_NUMERIC_LITERAL,
+ T_IDENTIFIER,
+
+ T_LPAREN, T_LBRACKET, T_LBRACE,
+
+ EOF_SYMBOL
+ };
+
+ for (int *tk = tokens; *tk != EOF_SYMBOL; ++tk) {
+ int a = t_action(errorState, *tk);
+ if (a > 0 && t_action(a, yytoken)) {
+ const QString msg = qApp->translate("QQmlParser", "Expected token `%1'").arg(QLatin1String(spell[*tk]));
+ diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, token_buffer[0].loc, msg));
+
+ yytoken = *tk;
+ yylval = 0;
+ yylloc = token_buffer[0].loc;
+ yylloc.length = 0;
+
+ first_token = &token_buffer[0];
+ last_token = &token_buffer[2];
+
+ action = errorState;
+ goto _Lcheck_token;
+ }
+ }
+
+ for (int tk = 1; tk < TERMINAL_COUNT; ++tk) {
+ if (tk == T_AUTOMATIC_SEMICOLON || tk == T_FEED_UI_PROGRAM ||
+ tk == T_FEED_JS_STATEMENT || tk == T_FEED_JS_EXPRESSION ||
+ tk == T_FEED_JS_SOURCE_ELEMENT)
+ continue;
+
+ int a = t_action(errorState, tk);
+ if (a > 0 && t_action(a, yytoken)) {
+ const QString msg = qApp->translate("QQmlParser", "Expected token `%1'").arg(QLatin1String(spell[tk]));
+ diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, token_buffer[0].loc, msg));
+
+ yytoken = tk;
+ yylval = 0;
+ yylloc = token_buffer[0].loc;
+ yylloc.length = 0;
+
+ action = errorState;
+ goto _Lcheck_token;
+ }
+ }
+
+ const QString msg = qApp->translate("QQmlParser", "Syntax error");
+ diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, token_buffer[0].loc, msg));
+ }
+
+ return false;
+}
+
+QT_QML_END_NAMESPACE
+
+
diff --git a/src/qml/qml/parser/qqmljsparser_p.h b/src/qml/qml/parser/qqmljsparser_p.h
new file mode 100644
index 0000000000..ad532c32c7
--- /dev/null
+++ b/src/qml/qml/parser/qqmljsparser_p.h
@@ -0,0 +1,248 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+//
+// 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.
+//
+
+//
+// This file is automatically generated from qmljs.g.
+// Changes will be lost.
+//
+
+#ifndef QQMLJSPARSER_P_H
+#define QQMLJSPARSER_P_H
+
+#include "qqmljsglobal_p.h"
+#include "qqmljsgrammar_p.h"
+#include "qqmljsast_p.h"
+#include "qqmljsengine_p.h"
+
+#include <QtCore/QList>
+#include <QtCore/QString>
+
+QT_QML_BEGIN_NAMESPACE
+
+namespace QQmlJS {
+
+class Engine;
+
+class QML_PARSER_EXPORT Parser: protected QQmlJSGrammar
+{
+public:
+ union Value {
+ int ival;
+ double dval;
+ AST::ArgumentList *ArgumentList;
+ AST::CaseBlock *CaseBlock;
+ AST::CaseClause *CaseClause;
+ AST::CaseClauses *CaseClauses;
+ AST::Catch *Catch;
+ AST::DefaultClause *DefaultClause;
+ AST::ElementList *ElementList;
+ AST::Elision *Elision;
+ AST::ExpressionNode *Expression;
+ AST::Finally *Finally;
+ AST::FormalParameterList *FormalParameterList;
+ AST::FunctionBody *FunctionBody;
+ AST::FunctionDeclaration *FunctionDeclaration;
+ AST::Node *Node;
+ AST::PropertyName *PropertyName;
+ AST::PropertyNameAndValueList *PropertyNameAndValueList;
+ AST::SourceElement *SourceElement;
+ AST::SourceElements *SourceElements;
+ AST::Statement *Statement;
+ AST::StatementList *StatementList;
+ AST::Block *Block;
+ AST::VariableDeclaration *VariableDeclaration;
+ AST::VariableDeclarationList *VariableDeclarationList;
+
+ AST::UiProgram *UiProgram;
+ AST::UiImportList *UiImportList;
+ AST::UiImport *UiImport;
+ AST::UiParameterList *UiParameterList;
+ AST::UiPublicMember *UiPublicMember;
+ AST::UiObjectDefinition *UiObjectDefinition;
+ AST::UiObjectInitializer *UiObjectInitializer;
+ AST::UiObjectBinding *UiObjectBinding;
+ AST::UiScriptBinding *UiScriptBinding;
+ AST::UiArrayBinding *UiArrayBinding;
+ AST::UiObjectMember *UiObjectMember;
+ AST::UiObjectMemberList *UiObjectMemberList;
+ AST::UiArrayMemberList *UiArrayMemberList;
+ AST::UiQualifiedId *UiQualifiedId;
+ };
+
+public:
+ Parser(Engine *engine);
+ ~Parser();
+
+ // parse a UI program
+ bool parse() { return parse(T_FEED_UI_PROGRAM); }
+ bool parseStatement() { return parse(T_FEED_JS_STATEMENT); }
+ bool parseExpression() { return parse(T_FEED_JS_EXPRESSION); }
+ bool parseSourceElement() { return parse(T_FEED_JS_SOURCE_ELEMENT); }
+ bool parseUiObjectMember() { return parse(T_FEED_UI_OBJECT_MEMBER); }
+ bool parseProgram() { return parse(T_FEED_JS_PROGRAM); }
+
+ AST::UiProgram *ast() const
+ { return AST::cast<AST::UiProgram *>(program); }
+
+ AST::Statement *statement() const
+ {
+ if (! program)
+ return 0;
+
+ return program->statementCast();
+ }
+
+ AST::ExpressionNode *expression() const
+ {
+ if (! program)
+ return 0;
+
+ return program->expressionCast();
+ }
+
+ AST::UiObjectMember *uiObjectMember() const
+ {
+ if (! program)
+ return 0;
+
+ return program->uiObjectMemberCast();
+ }
+
+ AST::Node *rootNode() const
+ { return program; }
+
+ QList<DiagnosticMessage> diagnosticMessages() const
+ { return diagnostic_messages; }
+
+ inline DiagnosticMessage diagnosticMessage() const
+ {
+ foreach (const DiagnosticMessage &d, diagnostic_messages) {
+ if (! d.kind == DiagnosticMessage::Warning)
+ return d;
+ }
+
+ return DiagnosticMessage();
+ }
+
+ inline QString errorMessage() const
+ { return diagnosticMessage().message; }
+
+ inline int errorLineNumber() const
+ { return diagnosticMessage().loc.startLine; }
+
+ inline int errorColumnNumber() const
+ { return diagnosticMessage().loc.startColumn; }
+
+protected:
+ bool parse(int startToken);
+
+ void reallocateStack();
+
+ inline Value &sym(int index)
+ { return sym_stack [tos + index - 1]; }
+
+ inline QStringRef &stringRef(int index)
+ { return string_stack [tos + index - 1]; }
+
+ inline AST::SourceLocation &loc(int index)
+ { return location_stack [tos + index - 1]; }
+
+ AST::UiQualifiedId *reparseAsQualifiedId(AST::ExpressionNode *expr);
+
+protected:
+ Engine *driver;
+ MemoryPool *pool;
+ int tos;
+ int stack_size;
+ Value *sym_stack;
+ int *state_stack;
+ AST::SourceLocation *location_stack;
+ QStringRef *string_stack;
+
+ AST::Node *program;
+
+ // error recovery
+ enum { TOKEN_BUFFER_SIZE = 3 };
+
+ struct SavedToken {
+ int token;
+ double dval;
+ AST::SourceLocation loc;
+ QStringRef spell;
+ };
+
+ double yylval;
+ QStringRef yytokenspell;
+ AST::SourceLocation yylloc;
+ AST::SourceLocation yyprevlloc;
+
+ SavedToken token_buffer[TOKEN_BUFFER_SIZE];
+ SavedToken *first_token;
+ SavedToken *last_token;
+
+ QList<DiagnosticMessage> diagnostic_messages;
+};
+
+} // end of namespace QQmlJS
+
+
+
+#define J_SCRIPT_REGEXPLITERAL_RULE1 79
+
+#define J_SCRIPT_REGEXPLITERAL_RULE2 80
+
+QT_QML_END_NAMESPACE
+
+
+
+#endif // QQMLJSPARSER_P_H
diff --git a/src/qml/qml/qlistmodelinterface.cpp b/src/qml/qml/qlistmodelinterface.cpp
new file mode 100644
index 0000000000..3ea0d3f155
--- /dev/null
+++ b/src/qml/qml/qlistmodelinterface.cpp
@@ -0,0 +1,104 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtDeclaractive module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qlistmodelinterface_p.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \internal
+ \class QListModelInterface
+ \brief The QListModelInterface class can be subclassed to provide C++ models to QQuickGraphics Views
+
+ This class is comprised primarily of pure virtual functions which
+ you must implement in a subclass. You can then use the subclass
+ as a model for a QQuickGraphics view, such as a QQuickListView.
+*/
+
+/*! \fn QListModelInterface::QListModelInterface(QObject *parent)
+ Constructs a QListModelInterface with the specified \a parent.
+*/
+
+ /*! \fn QListModelInterface::QListModelInterface(QObjectPrivate &dd, QObject *parent)
+
+ \internal
+ */
+
+/*! \fn QListModelInterface::~QListModelInterface()
+ The destructor is virtual.
+ */
+
+/*! \fn int QListModelInterface::count() const
+ Returns the number of data entries in the model.
+*/
+
+/*! \fn QVariant QListModelInterface::data(int index, int role) const
+ Returns the data at the given \a index for the specified \a roles.
+*/
+
+/*! \fn QList<int> QListModelInterface::roles() const
+ Returns the list of roles for which the list model interface
+ provides data.
+*/
+
+/*! \fn QString QListModelInterface::toString(int role) const
+ Returns a string description of the specified \a role.
+*/
+
+/*! \fn void QListModelInterface::itemsInserted(int index, int count)
+ Emit this signal when \a count items are inserted at \a index.
+ */
+
+/*! \fn void QListModelInterface::itemsRemoved(int index, int count)
+ Emit this signal when \a count items are removed at \a index.
+ */
+
+/*! \fn void QListModelInterface::itemsMoved(int from, int to, int count)
+ Emit this signal when \a count items are moved from index \a from
+ to index \a to.
+ */
+
+/*! \fn void QListModelInterface::itemsChanged(int index, int count, const QList<int> &roles)
+ Emit this signal when \a count items at \a index have had their
+ \a roles changed.
+ */
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/qlistmodelinterface_p.h b/src/qml/qml/qlistmodelinterface_p.h
new file mode 100644
index 0000000000..c644ce88e6
--- /dev/null
+++ b/src/qml/qml/qlistmodelinterface_p.h
@@ -0,0 +1,83 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QLISTMODELINTERFACE_H
+#define QLISTMODELINTERFACE_H
+
+#include <QtCore/QHash>
+#include <QtCore/QVariant>
+
+#include <private/qtqmlglobal_p.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+
+class Q_QML_PRIVATE_EXPORT QListModelInterface : public QObject
+{
+ Q_OBJECT
+ public:
+ QListModelInterface(QObject *parent = 0) : QObject(parent) {}
+ virtual ~QListModelInterface() {}
+
+ virtual int count() const = 0;
+ virtual QVariant data(int index, int role) const = 0;
+
+ virtual QList<int> roles() const = 0;
+ virtual QString toString(int role) const = 0;
+
+ Q_SIGNALS:
+ void itemsInserted(int index, int count);
+ void itemsRemoved(int index, int count);
+ void itemsMoved(int from, int to, int count);
+ void itemsChanged(int index, int count, const QList<int> &roles);
+
+ protected:
+ QListModelInterface(QObjectPrivate &dd, QObject *parent)
+ : QObject(dd, parent) {}
+};
+
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+#endif //QTREEMODELINTERFACE_H
diff --git a/src/qml/qml/qml.pri b/src/qml/qml/qml.pri
new file mode 100644
index 0000000000..0ce7c7ed5c
--- /dev/null
+++ b/src/qml/qml/qml.pri
@@ -0,0 +1,125 @@
+SOURCES += \
+ $$PWD/qquickapplication.cpp \
+ $$PWD/qqmlinstruction.cpp \
+ $$PWD/qquicklistmodel.cpp \
+ $$PWD/qquicklistmodelworkeragent.cpp \
+ $$PWD/qqmlopenmetaobject.cpp \
+ $$PWD/qqmlvmemetaobject.cpp \
+ $$PWD/qqmlengine.cpp \
+ $$PWD/qqmlexpression.cpp \
+ $$PWD/qqmlbinding.cpp \
+ $$PWD/qqmlproperty.cpp \
+ $$PWD/qqmlcomponent.cpp \
+ $$PWD/qqmlincubator.cpp \
+ $$PWD/qqmlcontext.cpp \
+ $$PWD/qqmlcustomparser.cpp \
+ $$PWD/qqmlpropertyvaluesource.cpp \
+ $$PWD/qqmlpropertyvalueinterceptor.cpp \
+ $$PWD/qqmlproxymetaobject.cpp \
+ $$PWD/qqmlvme.cpp \
+ $$PWD/qqmlcompiler.cpp \
+ $$PWD/qqmlcompileddata.cpp \
+ $$PWD/qqmlboundsignal.cpp \
+ $$PWD/qqmlmetatype.cpp \
+ $$PWD/qqmlstringconverters.cpp \
+ $$PWD/qqmlparserstatus.cpp \
+ $$PWD/qqmltypeloader.cpp \
+ $$PWD/qqmlinfo.cpp \
+ $$PWD/qqmlerror.cpp \
+ $$PWD/qqmlscript.cpp \
+ $$PWD/qqmlrewrite.cpp \
+ $$PWD/qqmlvaluetype.cpp \
+ $$PWD/qqmlaccessors.cpp \
+ $$PWD/qqmlxmlhttprequest.cpp \
+ $$PWD/qqmlwatcher.cpp \
+ $$PWD/qqmlcleanup.cpp \
+ $$PWD/qqmlpropertycache.cpp \
+ $$PWD/qqmlnotifier.cpp \
+ $$PWD/qqmlintegercache.cpp \
+ $$PWD/qqmltypenotavailable.cpp \
+ $$PWD/qqmltypenamecache.cpp \
+ $$PWD/qqmlscriptstring.cpp \
+ $$PWD/qquickworkerscript.cpp \
+ $$PWD/qqmlimageprovider.cpp \
+ $$PWD/qqmlnetworkaccessmanagerfactory.cpp \
+ $$PWD/qqmldirparser.cpp \
+ $$PWD/qqmlextensionplugin.cpp \
+ $$PWD/qqmlimport.cpp \
+ $$PWD/qqmllist.cpp \
+ $$PWD/qqmllocale.cpp \
+ $$PWD/qlistmodelinterface.cpp
+
+HEADERS += \
+ $$PWD/qqmlglobal_p.h \
+ $$PWD/qqmlinstruction_p.h \
+ $$PWD/qquicklistmodel_p.h\
+ $$PWD/qquicklistmodel_p_p.h\
+ $$PWD/qquicklistmodelworkeragent_p.h \
+ $$PWD/qqmlopenmetaobject_p.h \
+ $$PWD/qqmlvmemetaobject_p.h \
+ $$PWD/qqml.h \
+ $$PWD/qquickapplication_p.h \
+ $$PWD/qqmlbinding_p.h \
+ $$PWD/qqmlbinding_p_p.h \
+ $$PWD/qqmlproperty.h \
+ $$PWD/qqmlcomponent.h \
+ $$PWD/qqmlcomponent_p.h \
+ $$PWD/qqmlincubator.h \
+ $$PWD/qqmlincubator_p.h \
+ $$PWD/qqmlcustomparser_p.h \
+ $$PWD/qqmlcustomparser_p_p.h \
+ $$PWD/qqmlpropertyvaluesource.h \
+ $$PWD/qqmlpropertyvalueinterceptor_p.h \
+ $$PWD/qqmlboundsignal_p.h \
+ $$PWD/qqmlparserstatus.h \
+ $$PWD/qqmlproxymetaobject_p.h \
+ $$PWD/qqmlvme_p.h \
+ $$PWD/qqmlcompiler_p.h \
+ $$PWD/qqmlengine_p.h \
+ $$PWD/qqmlexpression_p.h \
+ $$PWD/qqmlprivate.h \
+ $$PWD/qqmlmetatype_p.h \
+ $$PWD/qqmlengine.h \
+ $$PWD/qqmlcontext.h \
+ $$PWD/qqmlexpression.h \
+ $$PWD/qqmlstringconverters_p.h \
+ $$PWD/qqmlinfo.h \
+ $$PWD/qqmlproperty_p.h \
+ $$PWD/qqmlcontext_p.h \
+ $$PWD/qqmltypeloader_p.h \
+ $$PWD/qqmllist.h \
+ $$PWD/qqmllist_p.h \
+ $$PWD/qqmldata_p.h \
+ $$PWD/qqmlerror.h \
+ $$PWD/qqmlscript_p.h \
+ $$PWD/qqmlrewrite_p.h \
+ $$PWD/qqmlvaluetype_p.h \
+ $$PWD/qqmlaccessors_p.h \
+ $$PWD/qqmlxmlhttprequest_p.h \
+ $$PWD/qqmlwatcher_p.h \
+ $$PWD/qqmlcleanup_p.h \
+ $$PWD/qqmlpropertycache_p.h \
+ $$PWD/qqmlnotifier_p.h \
+ $$PWD/qqmlintegercache_p.h \
+ $$PWD/qqmltypenotavailable_p.h \
+ $$PWD/qqmltypenamecache_p.h \
+ $$PWD/qqmlscriptstring.h \
+ $$PWD/qquickworkerscript_p.h \
+ $$PWD/qqmlguard_p.h \
+ $$PWD/qqmlimageprovider.h \
+ $$PWD/qqmlnetworkaccessmanagerfactory.h \
+ $$PWD/qqmldirparser_p.h \
+ $$PWD/qqmlextensioninterface.h \
+ $$PWD/qqmlimport_p.h \
+ $$PWD/qqmlextensionplugin.h \
+ $$PWD/qqmlnullablevalue_p_p.h \
+ $$PWD/qqmlscriptstring_p.h \
+ $$PWD/qqmllocale_p.h \
+ $$PWD/qlistmodelinterface_p.h \
+ $$PWD/qqmlcomponentattached_p.h
+
+include(parser/parser.pri)
+include(rewriter/rewriter.pri)
+include(ftw/ftw.pri)
+include(v4/v4.pri)
+include(v8/v8.pri)
diff --git a/src/qml/qml/qqml.h b/src/qml/qml/qqml.h
new file mode 100644
index 0000000000..32da2c616e
--- /dev/null
+++ b/src/qml/qml/qqml.h
@@ -0,0 +1,451 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQML_H
+#define QQML_H
+
+#include <QtQml/qqmlprivate.h>
+#include <QtQml/qqmlparserstatus.h>
+#include <QtQml/qqmlpropertyvaluesource.h>
+#include <QtQml/qqmllist.h>
+
+#include <QtCore/qbytearray.h>
+#include <QtCore/qmetaobject.h>
+
+QT_BEGIN_HEADER
+
+#define QML_VERSION 0x020000
+#define QML_VERSION_STR "2.0"
+
+#define QML_DECLARE_TYPE(TYPE) \
+ Q_DECLARE_METATYPE(TYPE *) \
+ Q_DECLARE_METATYPE(QQmlListProperty<TYPE>)
+
+#define QML_DECLARE_TYPE_HASMETATYPE(TYPE) \
+ Q_DECLARE_METATYPE(QQmlListProperty<TYPE>)
+
+#define QML_DECLARE_INTERFACE(INTERFACE) \
+ QML_DECLARE_TYPE(INTERFACE)
+
+#define QML_DECLARE_INTERFACE_HASMETATYPE(INTERFACE) \
+ QML_DECLARE_TYPE_HASMETATYPE(INTERFACE)
+
+enum { /* TYPEINFO flags */
+ QML_HAS_ATTACHED_PROPERTIES = 0x01
+};
+
+#define QML_DECLARE_TYPEINFO(TYPE, FLAGS) \
+QT_BEGIN_NAMESPACE \
+template <> \
+class QQmlTypeInfo<TYPE > \
+{ \
+public: \
+ enum { \
+ hasAttachedProperties = (((FLAGS) & QML_HAS_ATTACHED_PROPERTIES) == QML_HAS_ATTACHED_PROPERTIES) \
+ }; \
+}; \
+QT_END_NAMESPACE
+
+QT_BEGIN_NAMESPACE
+
+
+class QQmlPropertyValueInterceptor;
+
+template<typename T>
+int qmlRegisterType()
+{
+ QByteArray name(T::staticMetaObject.className());
+
+ QByteArray pointerName(name + '*');
+ QByteArray listName("QQmlListProperty<" + name + ">");
+
+ QQmlPrivate::RegisterType type = {
+ 0,
+
+ qRegisterMetaType<T *>(pointerName.constData()),
+ qRegisterMetaType<QQmlListProperty<T> >(listName.constData()),
+ 0, 0,
+ QString(),
+
+ 0, 0, 0, 0, &T::staticMetaObject,
+
+ QQmlPrivate::attachedPropertiesFunc<T>(),
+ QQmlPrivate::attachedPropertiesMetaObject<T>(),
+
+ QQmlPrivate::StaticCastSelector<T,QQmlParserStatus>::cast(),
+ QQmlPrivate::StaticCastSelector<T,QQmlPropertyValueSource>::cast(),
+ QQmlPrivate::StaticCastSelector<T,QQmlPropertyValueInterceptor>::cast(),
+
+ 0, 0,
+
+ 0,
+ 0
+ };
+
+ return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type);
+}
+
+int Q_QML_EXPORT qmlRegisterTypeNotAvailable(const char *uri, int versionMajor, int versionMinor, const char *qmlName, const QString& message);
+
+template<typename T>
+int qmlRegisterUncreatableType(const char *uri, int versionMajor, int versionMinor, const char *qmlName, const QString& reason)
+{
+ QByteArray name(T::staticMetaObject.className());
+
+ QByteArray pointerName(name + '*');
+ QByteArray listName("QQmlListProperty<" + name + ">");
+
+ QQmlPrivate::RegisterType type = {
+ 0,
+
+ qRegisterMetaType<T *>(pointerName.constData()),
+ qRegisterMetaType<QQmlListProperty<T> >(listName.constData()),
+ 0, 0,
+ reason,
+
+ uri, versionMajor, versionMinor, qmlName, &T::staticMetaObject,
+
+ QQmlPrivate::attachedPropertiesFunc<T>(),
+ QQmlPrivate::attachedPropertiesMetaObject<T>(),
+
+ QQmlPrivate::StaticCastSelector<T,QQmlParserStatus>::cast(),
+ QQmlPrivate::StaticCastSelector<T,QQmlPropertyValueSource>::cast(),
+ QQmlPrivate::StaticCastSelector<T,QQmlPropertyValueInterceptor>::cast(),
+
+ 0, 0,
+
+ 0,
+ 0
+ };
+
+ return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type);
+}
+
+template<typename T>
+int qmlRegisterType(const char *uri, int versionMajor, int versionMinor, const char *qmlName)
+{
+ QByteArray name(T::staticMetaObject.className());
+
+ QByteArray pointerName(name + '*');
+ QByteArray listName("QQmlListProperty<" + name + ">");
+
+ QQmlPrivate::RegisterType type = {
+ 0,
+
+ qRegisterMetaType<T *>(pointerName.constData()),
+ qRegisterMetaType<QQmlListProperty<T> >(listName.constData()),
+ sizeof(T), QQmlPrivate::createInto<T>,
+ QString(),
+
+ uri, versionMajor, versionMinor, qmlName, &T::staticMetaObject,
+
+ QQmlPrivate::attachedPropertiesFunc<T>(),
+ QQmlPrivate::attachedPropertiesMetaObject<T>(),
+
+ QQmlPrivate::StaticCastSelector<T,QQmlParserStatus>::cast(),
+ QQmlPrivate::StaticCastSelector<T,QQmlPropertyValueSource>::cast(),
+ QQmlPrivate::StaticCastSelector<T,QQmlPropertyValueInterceptor>::cast(),
+
+ 0, 0,
+
+ 0,
+ 0
+ };
+
+ return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type);
+}
+
+template<typename T, int metaObjectRevision>
+int qmlRegisterType(const char *uri, int versionMajor, int versionMinor, const char *qmlName)
+{
+ QByteArray name(T::staticMetaObject.className());
+
+ QByteArray pointerName(name + '*');
+ QByteArray listName("QQmlListProperty<" + name + ">");
+
+ QQmlPrivate::RegisterType type = {
+ 1,
+
+ qRegisterMetaType<T *>(pointerName.constData()),
+ qRegisterMetaType<QQmlListProperty<T> >(listName.constData()),
+ sizeof(T), QQmlPrivate::createInto<T>,
+ QString(),
+
+ uri, versionMajor, versionMinor, qmlName, &T::staticMetaObject,
+
+ QQmlPrivate::attachedPropertiesFunc<T>(),
+ QQmlPrivate::attachedPropertiesMetaObject<T>(),
+
+ QQmlPrivate::StaticCastSelector<T,QQmlParserStatus>::cast(),
+ QQmlPrivate::StaticCastSelector<T,QQmlPropertyValueSource>::cast(),
+ QQmlPrivate::StaticCastSelector<T,QQmlPropertyValueInterceptor>::cast(),
+
+ 0, 0,
+
+ 0,
+ metaObjectRevision
+ };
+
+ return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type);
+}
+
+template<typename T, int metaObjectRevision>
+int qmlRegisterRevision(const char *uri, int versionMajor, int versionMinor)
+{
+ QByteArray name(T::staticMetaObject.className());
+
+ QByteArray pointerName(name + '*');
+ QByteArray listName("QQmlListProperty<" + name + ">");
+
+ QQmlPrivate::RegisterType type = {
+ 1,
+
+ qRegisterMetaType<T *>(pointerName.constData()),
+ qRegisterMetaType<QQmlListProperty<T> >(listName.constData()),
+ sizeof(T), QQmlPrivate::createInto<T>,
+ QString(),
+
+ uri, versionMajor, versionMinor, 0, &T::staticMetaObject,
+
+ QQmlPrivate::attachedPropertiesFunc<T>(),
+ QQmlPrivate::attachedPropertiesMetaObject<T>(),
+
+ QQmlPrivate::StaticCastSelector<T,QQmlParserStatus>::cast(),
+ QQmlPrivate::StaticCastSelector<T,QQmlPropertyValueSource>::cast(),
+ QQmlPrivate::StaticCastSelector<T,QQmlPropertyValueInterceptor>::cast(),
+
+ 0, 0,
+
+ 0,
+ metaObjectRevision
+ };
+
+ return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type);
+}
+
+
+template<typename T, typename E>
+int qmlRegisterExtendedType()
+{
+ QByteArray name(T::staticMetaObject.className());
+
+ QByteArray pointerName(name + '*');
+ QByteArray listName("QQmlListProperty<" + name + ">");
+
+ QQmlPrivate::RegisterType type = {
+ 0,
+
+ qRegisterMetaType<T *>(pointerName.constData()),
+ qRegisterMetaType<QQmlListProperty<T> >(listName.constData()),
+ 0, 0,
+ QString(),
+
+ 0, 0, 0, 0, &T::staticMetaObject,
+
+ QQmlPrivate::attachedPropertiesFunc<T>(),
+ QQmlPrivate::attachedPropertiesMetaObject<T>(),
+
+ QQmlPrivate::StaticCastSelector<T,QQmlParserStatus>::cast(),
+ QQmlPrivate::StaticCastSelector<T,QQmlPropertyValueSource>::cast(),
+ QQmlPrivate::StaticCastSelector<T,QQmlPropertyValueInterceptor>::cast(),
+
+ QQmlPrivate::createParent<E>, &E::staticMetaObject,
+
+ 0,
+ 0
+ };
+
+ return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type);
+}
+
+template<typename T, typename E>
+int qmlRegisterExtendedType(const char *uri, int versionMajor, int versionMinor,
+ const char *qmlName)
+{
+ QByteArray name(T::staticMetaObject.className());
+
+ QByteArray pointerName(name + '*');
+ QByteArray listName("QQmlListProperty<" + name + ">");
+
+ QQmlAttachedPropertiesFunc attached = QQmlPrivate::attachedPropertiesFunc<E>();
+ const QMetaObject * attachedMetaObject = QQmlPrivate::attachedPropertiesMetaObject<E>();
+ if (!attached) {
+ attached = QQmlPrivate::attachedPropertiesFunc<T>();
+ attachedMetaObject = QQmlPrivate::attachedPropertiesMetaObject<T>();
+ }
+
+ QQmlPrivate::RegisterType type = {
+ 0,
+
+ qRegisterMetaType<T *>(pointerName.constData()),
+ qRegisterMetaType<QQmlListProperty<T> >(listName.constData()),
+ sizeof(T), QQmlPrivate::createInto<T>,
+ QString(),
+
+ uri, versionMajor, versionMinor, qmlName, &T::staticMetaObject,
+
+ attached,
+ attachedMetaObject,
+
+ QQmlPrivate::StaticCastSelector<T,QQmlParserStatus>::cast(),
+ QQmlPrivate::StaticCastSelector<T,QQmlPropertyValueSource>::cast(),
+ QQmlPrivate::StaticCastSelector<T,QQmlPropertyValueInterceptor>::cast(),
+
+ QQmlPrivate::createParent<E>, &E::staticMetaObject,
+
+ 0,
+ 0
+ };
+
+ return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type);
+}
+
+template<typename T>
+int qmlRegisterInterface(const char *typeName)
+{
+ QByteArray name(typeName);
+
+ QByteArray pointerName(name + '*');
+ QByteArray listName("QQmlListProperty<" + name + ">");
+
+ QQmlPrivate::RegisterInterface qmlInterface = {
+ 0,
+
+ qRegisterMetaType<T *>(pointerName.constData()),
+ qRegisterMetaType<QQmlListProperty<T> >(listName.constData()),
+
+ qobject_interface_iid<T *>()
+ };
+
+ return QQmlPrivate::qmlregister(QQmlPrivate::InterfaceRegistration, &qmlInterface);
+}
+
+template<typename T>
+int qmlRegisterCustomType(const char *uri, int versionMajor, int versionMinor,
+ const char *qmlName, QQmlCustomParser *parser)
+{
+ QByteArray name(T::staticMetaObject.className());
+
+ QByteArray pointerName(name + '*');
+ QByteArray listName("QQmlListProperty<" + name + ">");
+
+ QQmlPrivate::RegisterType type = {
+ 0,
+
+ qRegisterMetaType<T *>(pointerName.constData()),
+ qRegisterMetaType<QQmlListProperty<T> >(listName.constData()),
+ sizeof(T), QQmlPrivate::createInto<T>,
+ QString(),
+
+ uri, versionMajor, versionMinor, qmlName, &T::staticMetaObject,
+
+ QQmlPrivate::attachedPropertiesFunc<T>(),
+ QQmlPrivate::attachedPropertiesMetaObject<T>(),
+
+ QQmlPrivate::StaticCastSelector<T,QQmlParserStatus>::cast(),
+ QQmlPrivate::StaticCastSelector<T,QQmlPropertyValueSource>::cast(),
+ QQmlPrivate::StaticCastSelector<T,QQmlPropertyValueInterceptor>::cast(),
+
+ 0, 0,
+
+ parser,
+ 0
+ };
+
+ return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type);
+}
+
+class QQmlContext;
+class QQmlEngine;
+class QJSValue;
+class QJSEngine;
+Q_QML_EXPORT void qmlExecuteDeferred(QObject *);
+Q_QML_EXPORT QQmlContext *qmlContext(const QObject *);
+Q_QML_EXPORT QQmlEngine *qmlEngine(const QObject *);
+Q_QML_EXPORT QObject *qmlAttachedPropertiesObjectById(int, const QObject *, bool create = true);
+Q_QML_EXPORT QObject *qmlAttachedPropertiesObject(int *, const QObject *, const QMetaObject *, bool create);
+
+template<typename T>
+QObject *qmlAttachedPropertiesObject(const QObject *obj, bool create = true)
+{
+ static int idx = -1;
+ return qmlAttachedPropertiesObject(&idx, obj, &T::staticMetaObject, create);
+}
+
+// For the use of QtQuick1 module
+Q_QML_EXPORT void qmlRegisterBaseTypes(const char *uri, int versionMajor, int versionMinor);
+
+inline int qmlRegisterModuleApi(const char *uri, int versionMajor, int versionMinor,
+ QJSValue (*callback)(QQmlEngine *, QJSEngine *))
+{
+ QQmlPrivate::RegisterModuleApi api = {
+ 0,
+
+ uri, versionMajor, versionMinor,
+
+ callback, 0
+ };
+
+ return QQmlPrivate::qmlregister(QQmlPrivate::ModuleApiRegistration, &api);
+}
+
+inline int qmlRegisterModuleApi(const char *uri, int versionMajor, int versionMinor,
+ QObject *(*callback)(QQmlEngine *, QJSEngine *))
+{
+ QQmlPrivate::RegisterModuleApi api = {
+ 0,
+
+ uri, versionMajor, versionMinor,
+
+ 0, callback
+ };
+
+ return QQmlPrivate::qmlregister(QQmlPrivate::ModuleApiRegistration, &api);
+}
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QObject)
+Q_DECLARE_METATYPE(QVariant)
+
+QT_END_HEADER
+
+#endif // QQML_H
diff --git a/src/qml/qml/qqmlaccessors.cpp b/src/qml/qml/qqmlaccessors.cpp
new file mode 100644
index 0000000000..ceb4f44789
--- /dev/null
+++ b/src/qml/qml/qqmlaccessors.cpp
@@ -0,0 +1,127 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qqmlaccessors_p.h"
+
+#include "qqmldata_p.h"
+#include "qqmlnotifier_p.h"
+
+QT_BEGIN_NAMESPACE
+
+struct AccessorProperties {
+ AccessorProperties();
+
+ QReadWriteLock lock;
+ QHash<const QMetaObject *, QQmlAccessorProperties::Properties> properties;
+};
+
+Q_GLOBAL_STATIC(AccessorProperties, accessorProperties)
+
+QML_PRIVATE_ACCESSOR(QObject, QString, objectName, objectName)
+
+static void QObject_objectNameNotifier(QObject *object, intptr_t, QQmlNotifier **notifier)
+{
+ *notifier = QQmlData::get(object, true)->objectNameNotifier();
+}
+
+static QQmlAccessors QObject_objectName = { QObject_objectNameRead,
+ QObject_objectNameNotifier };
+
+QML_DECLARE_PROPERTIES(QObject) {
+ { QML_PROPERTY_NAME(objectName), 0, &QObject_objectName }
+};
+
+static void buildNameMask(QQmlAccessorProperties::Properties &properties)
+{
+ quint32 mask = 0;
+
+ for (int ii = 0; ii < properties.count; ++ii) {
+ Q_ASSERT(strlen(properties.properties[ii].name) == properties.properties[ii].nameLength);
+ Q_ASSERT(properties.properties[ii].nameLength > 0);
+
+ mask |= (1 << qMin(31U, properties.properties[ii].nameLength - 1));
+ }
+
+ properties.nameMask = mask;
+}
+
+AccessorProperties::AccessorProperties()
+{
+ // Pre-seed QObject::objectName accessor
+ typedef QQmlAccessorProperties::Properties P;
+ properties.insert(&QObject::staticMetaObject,
+ P(qqml_accessor_properties_QObject,
+ sizeof(qqml_accessor_properties_QObject) /
+ sizeof(QQmlAccessorProperties::Property)));
+}
+
+QQmlAccessorProperties::Properties::Properties(Property *properties, int count)
+: count(count), properties(properties)
+{
+ buildNameMask(*this);
+}
+
+QQmlAccessorProperties::Properties
+QQmlAccessorProperties::properties(const QMetaObject *mo)
+{
+ AccessorProperties *This = accessorProperties();
+
+ QReadLocker lock(&This->lock);
+ return This->properties.value(mo);
+}
+
+void QQmlAccessorProperties::registerProperties(const QMetaObject *mo, int count,
+ Property *props)
+{
+ Q_ASSERT(count > 0);
+
+ Properties properties(props, count);
+
+ AccessorProperties *This = accessorProperties();
+
+ QWriteLocker lock(&This->lock);
+
+ Q_ASSERT(!This->properties.contains(mo) || This->properties.value(mo) == properties);
+
+ This->properties.insert(mo, properties);
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlaccessors_p.h b/src/qml/qml/qqmlaccessors_p.h
new file mode 100644
index 0000000000..a603bede9f
--- /dev/null
+++ b/src/qml/qml/qqmlaccessors_p.h
@@ -0,0 +1,166 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLACCESSORS_P_H
+#define QQMLACCESSORS_P_H
+
+#include <QtQml/qtqmlglobal.h>
+#include <QtCore/qvector.h>
+#include <QtCore/qhash.h>
+#include <QtCore/QReadWriteLock>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class QObject;
+class QQmlNotifier;
+
+// QML "accessor properties" allow V4 and V8 to bypass Qt's meta system to read and, more
+// importantly, subscribe to properties directly. Any property that is primarily read
+// from bindings is a candidate for inclusion as an accessor property.
+//
+// To define accessor properties, use the QML_DECLARE_PROPERTIES() and QML_DEFINE_PROPERTIES()
+// macros. The QML_DECLARE_PROPERTIES() macro is used to specify the properties, and the
+// QML_DEFINE_PROPERTIES() macro to register the properties with the
+// QQmlAccessorProperties singleton.
+//
+// A class with accessor properties must also add the Q_CLASSINFO("qt_HasQmlAccessors", "true")
+// tag to its declaration. This is essential for QML to maintain internal consistency,
+// and forgetting to do so will probably cause your application to qFatal() with a
+// helpful reminder of this requirement.
+//
+// It is important that QML_DEFINE_PROPERTIES() has been called before QML ever sees
+// the type with the accessor properties. As QML_DEFINE_PROPERTIES() is idempotent, it is
+// recommended to call it in the type's constructor as well as when the type is registered
+// as a QML element (if it ever is). QML_DEFINE_PROPERTIES() is a very cheap operation
+// if registration has already occurred.
+
+#define QML_DECLARE_PROPERTIES(type) \
+ static volatile bool qqml_accessor_properties_isregistered_ ## type = false; \
+ static QQmlAccessorProperties::Property qqml_accessor_properties_ ## type[] =
+
+#define QML_DEFINE_PROPERTIES(type) \
+ do { \
+ if (!qqml_accessor_properties_isregistered_ ## type) { \
+ int count = sizeof(qqml_accessor_properties_ ## type) / \
+ sizeof(QQmlAccessorProperties::Property); \
+ QQmlAccessorProperties::registerProperties(&type::staticMetaObject, count, \
+ qqml_accessor_properties_ ## type);\
+ qqml_accessor_properties_isregistered_ ## type = true; \
+ } \
+ } while (false);
+
+#define QML_PRIVATE_ACCESSOR(clazz, cpptype, name, variable) \
+ static void clazz ## _ ## name ## Read(QObject *o, intptr_t, void *rv) \
+ { \
+ clazz ## Private *d = clazz ## Private::get(static_cast<clazz *>(o)); \
+ *static_cast<cpptype *>(rv) = d->variable; \
+ }
+
+#define QML_PROPERTY_NAME(name) #name, sizeof #name - 1
+
+class QQmlAccessors
+{
+public:
+ void (*read)(QObject *object, intptr_t property, void *output);
+ void (*notifier)(QObject *object, intptr_t property, QQmlNotifier **notifier);
+};
+
+namespace QQmlAccessorProperties {
+ struct Property {
+ const char *name;
+ unsigned int nameLength;
+ intptr_t data;
+ QQmlAccessors *accessors;
+ };
+
+ struct Properties {
+ inline Properties();
+ Properties(Property *, int);
+
+ bool operator==(const Properties &o) const {
+ return count == o.count && properties == o.properties;
+ }
+
+ inline Property *property(const char *name);
+
+ int count;
+ Property *properties;
+ quint32 nameMask;
+ };
+
+ Properties properties(const QMetaObject *);
+ void Q_QML_EXPORT registerProperties(const QMetaObject *, int, Property *);
+};
+
+QQmlAccessorProperties::Property *
+QQmlAccessorProperties::Properties::property(const char *name)
+{
+ if (count == 0)
+ return 0;
+
+ unsigned int length = strlen(name);
+
+ Q_ASSERT(length);
+
+ if (nameMask & (1 << qMin(31U, length - 1))) {
+
+ for (int ii = 0; ii < count; ++ii) {
+ if (properties[ii].nameLength == length && 0 == qstrcmp(name, properties[ii].name))
+ return &properties[ii];
+ }
+
+ }
+
+ return 0;
+}
+
+QQmlAccessorProperties::Properties::Properties()
+: count(0), properties(0), nameMask(0)
+{
+}
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QQMLACCESSORS_P_H
diff --git a/src/qml/qml/qqmlbinding.cpp b/src/qml/qml/qqmlbinding.cpp
new file mode 100644
index 0000000000..a19644fb3e
--- /dev/null
+++ b/src/qml/qml/qqmlbinding.cpp
@@ -0,0 +1,551 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qqmlbinding_p.h"
+#include "qqmlbinding_p_p.h"
+
+#include "qqml.h"
+#include "qqmlcontext.h"
+#include "qqmlinfo.h"
+#include "qqmlcompiler_p.h"
+#include "qqmldata_p.h"
+#include <private/qqmlprofilerservice_p.h>
+#include <private/qqmltrace_p.h>
+
+#include <QVariant>
+#include <QtCore/qdebug.h>
+
+QT_BEGIN_NAMESPACE
+
+QQmlAbstractBinding::QQmlAbstractBinding()
+: m_prevBinding(0), m_nextBinding(0)
+{
+}
+
+QQmlAbstractBinding::~QQmlAbstractBinding()
+{
+ Q_ASSERT(m_prevBinding == 0);
+ Q_ASSERT(*m_mePtr == 0);
+}
+
+/*!
+Destroy the binding. Use this instead of calling delete.
+
+Bindings are free to implement their own memory management, so the delete operator is not
+necessarily safe. The default implementation clears the binding, removes it from the object
+and calls delete.
+*/
+void QQmlAbstractBinding::destroy()
+{
+ removeFromObject();
+ clear();
+
+ delete this;
+}
+
+/*!
+Add this binding to \a object.
+
+This transfers ownership of the binding to the object, marks the object's property as
+being bound.
+
+However, it does not enable the binding itself or call update() on it.
+*/
+void QQmlAbstractBinding::addToObject()
+{
+ Q_ASSERT(!m_prevBinding);
+
+ QObject *obj = object();
+ Q_ASSERT(obj);
+
+ int index = propertyIndex();
+
+ QQmlData *data = QQmlData::get(obj, true);
+
+ if (index & 0xFF000000) {
+ // Value type
+
+ int coreIndex = index & 0xFFFFFF;
+
+ // Find the value type proxy (if there is one)
+ QQmlValueTypeProxyBinding *proxy = 0;
+ if (data->hasBindingBit(coreIndex)) {
+ QQmlAbstractBinding *b = data->bindings;
+ while (b && b->propertyIndex() != coreIndex)
+ b = b->m_nextBinding;
+ Q_ASSERT(b && b->bindingType() == QQmlAbstractBinding::ValueTypeProxy);
+ proxy = static_cast<QQmlValueTypeProxyBinding *>(b);
+ }
+
+ if (!proxy) {
+ proxy = new QQmlValueTypeProxyBinding(obj, coreIndex);
+
+ Q_ASSERT(proxy->propertyIndex() == coreIndex);
+ Q_ASSERT(proxy->object() == obj);
+
+ proxy->addToObject();
+ }
+
+ m_nextBinding = proxy->m_bindings;
+ if (m_nextBinding) m_nextBinding->m_prevBinding = &m_nextBinding;
+ m_prevBinding = &proxy->m_bindings;
+ proxy->m_bindings = this;
+
+ } else {
+ m_nextBinding = data->bindings;
+ if (m_nextBinding) m_nextBinding->m_prevBinding = &m_nextBinding;
+ m_prevBinding = &data->bindings;
+ data->bindings = this;
+
+ data->setBindingBit(obj, index);
+ }
+}
+
+/*!
+Remove the binding from the object.
+*/
+void QQmlAbstractBinding::removeFromObject()
+{
+ if (m_prevBinding) {
+ int index = propertyIndex();
+
+ *m_prevBinding = m_nextBinding;
+ if (m_nextBinding) m_nextBinding->m_prevBinding = m_prevBinding;
+ m_prevBinding = 0;
+ m_nextBinding = 0;
+
+ if (index & 0xFF000000) {
+ // Value type - we don't remove the proxy from the object. It will sit their happily
+ // doing nothing until it is removed by a write, a binding change or it is reused
+ // to hold more sub-bindings.
+ } else if (QObject *obj = object()) {
+ QQmlData *data = QQmlData::get(obj, false);
+ if (data) data->clearBindingBit(index);
+ }
+ }
+}
+
+static void bindingDummyDeleter(QQmlAbstractBinding *)
+{
+}
+
+QQmlAbstractBinding::Pointer QQmlAbstractBinding::weakPointer()
+{
+ if (m_mePtr.value().isNull())
+ m_mePtr.value() = QSharedPointer<QQmlAbstractBinding>(this, bindingDummyDeleter);
+
+ return m_mePtr.value().toWeakRef();
+}
+
+void QQmlAbstractBinding::clear()
+{
+ if (!m_mePtr.isNull()) {
+ **m_mePtr = 0;
+ m_mePtr = 0;
+ }
+}
+
+void QQmlAbstractBinding::retargetBinding(QObject *, int)
+{
+ qFatal("QQmlAbstractBinding::retargetBinding() called on illegal binding.");
+}
+
+QString QQmlAbstractBinding::expression() const
+{
+ return QLatin1String("<Unknown>");
+}
+
+void QQmlAbstractBinding::setEnabled(bool enabled, QQmlPropertyPrivate::WriteFlags flags)
+{
+ if (enabled) update(flags);
+}
+
+QQmlBinding::Identifier QQmlBinding::Invalid = -1;
+
+void QQmlBindingPrivate::refresh()
+{
+ Q_Q(QQmlBinding);
+ q->update();
+}
+
+QQmlBindingPrivate::QQmlBindingPrivate()
+: updating(false), enabled(false), target(), targetProperty(0)
+{
+}
+
+QQmlBindingPrivate::~QQmlBindingPrivate()
+{
+}
+
+QQmlBinding *
+QQmlBinding::createBinding(Identifier id, QObject *obj, QQmlContext *ctxt,
+ const QString &url, int lineNumber, QObject *parent)
+{
+ if (id < 0)
+ return 0;
+
+ QQmlContextData *ctxtdata = QQmlContextData::get(ctxt);
+
+ QQmlEnginePrivate *engine = QQmlEnginePrivate::get(ctxt->engine());
+ QQmlCompiledData *cdata = 0;
+ QQmlTypeData *typeData = 0;
+ if (engine && ctxtdata && !ctxtdata->url.isEmpty()) {
+ typeData = engine->typeLoader.get(ctxtdata->url);
+ cdata = typeData->compiledData();
+ }
+ QQmlBinding *rv = cdata ? new QQmlBinding(cdata->primitives.at(id), true, obj, ctxtdata, url, lineNumber, 0, parent) : 0;
+ if (cdata)
+ cdata->release();
+ if (typeData)
+ typeData->release();
+ return rv;
+}
+
+QQmlBinding::QQmlBinding(const QString &str, QObject *obj, QQmlContext *ctxt,
+ QObject *parent)
+: QQmlExpression(QQmlContextData::get(ctxt), obj, str, *new QQmlBindingPrivate)
+{
+ setParent(parent);
+ setNotifyOnValueChanged(true);
+}
+
+QQmlBinding::QQmlBinding(const QString &str, QObject *obj, QQmlContextData *ctxt,
+ QObject *parent)
+: QQmlExpression(ctxt, obj, str, *new QQmlBindingPrivate)
+{
+ setParent(parent);
+ setNotifyOnValueChanged(true);
+}
+
+QQmlBinding::QQmlBinding(const QString &str, bool isRewritten, QObject *obj,
+ QQmlContextData *ctxt,
+ const QString &url, int lineNumber, int columnNumber,
+ QObject *parent)
+: QQmlExpression(ctxt, obj, str, isRewritten, url, lineNumber, columnNumber, *new QQmlBindingPrivate)
+{
+ setParent(parent);
+ setNotifyOnValueChanged(true);
+}
+
+/*!
+ \internal
+
+ To avoid exposing v8 in the public API, functionPtr must be a pointer to a v8::Handle<v8::Function>.
+ For example:
+ v8::Handle<v8::Function> function;
+ new QQmlBinding(&function, scope, ctxt);
+ */
+QQmlBinding::QQmlBinding(void *functionPtr, QObject *obj, QQmlContextData *ctxt,
+ QObject *parent)
+: QQmlExpression(ctxt, obj, functionPtr, *new QQmlBindingPrivate)
+{
+ setParent(parent);
+ setNotifyOnValueChanged(true);
+}
+
+QQmlBinding::~QQmlBinding()
+{
+}
+
+void QQmlBinding::setTarget(const QQmlProperty &prop)
+{
+ Q_D(QQmlBinding);
+ d->property = prop;
+ d->target = d->property.object();
+ d->targetProperty = QQmlPropertyPrivate::get(d->property)->core.encodedIndex();
+
+ update();
+}
+
+void QQmlBinding::setTarget(QObject *object,
+ const QQmlPropertyData &core,
+ QQmlContextData *ctxt)
+{
+ Q_D(QQmlBinding);
+ d->property = QQmlPropertyPrivate::restore(object, core, ctxt);
+ d->target = d->property.object();
+ d->targetProperty = QQmlPropertyPrivate::get(d->property)->core.encodedIndex();
+
+ update();
+}
+
+QQmlProperty QQmlBinding::property() const
+{
+ Q_D(const QQmlBinding);
+ return d->property;
+}
+
+void QQmlBinding::setEvaluateFlags(EvaluateFlags flags)
+{
+ Q_D(QQmlBinding);
+ d->setRequiresThisObject(flags & RequiresThisObject);
+}
+
+QQmlBinding::EvaluateFlags QQmlBinding::evaluateFlags() const
+{
+ Q_D(const QQmlBinding);
+ return d->requiresThisObject()?RequiresThisObject:None;
+}
+
+void QQmlBinding::update(QQmlPropertyPrivate::WriteFlags flags)
+{
+ Q_D(QQmlBinding);
+
+ if (!d->enabled || !d->context() || !d->context()->isValid())
+ return;
+
+ QQmlTrace trace("General Binding Update");
+ trace.addDetail("URL", d->url);
+ trace.addDetail("Line", d->line);
+ trace.addDetail("Column", d->columnNumber);
+
+ if (!d->updating) {
+ QQmlBindingProfiler prof(d->url, d->line, d->column);
+ prof.addDetail(expression());
+ d->updating = true;
+
+ QQmlAbstractExpression::DeleteWatcher watcher(d);
+
+ if (d->property.propertyType() == qMetaTypeId<QQmlBinding *>()) {
+
+ int idx = d->property.index();
+ Q_ASSERT(idx != -1);
+
+ QQmlBinding *t = this;
+ int status = -1;
+ void *a[] = { &t, 0, &status, &flags };
+ QMetaObject::metacall(d->property.object(),
+ QMetaObject::WriteProperty,
+ idx, a);
+
+ } else {
+ QQmlEnginePrivate *ep = QQmlEnginePrivate::get(d->context()->engine);
+ ep->referenceScarceResources();
+
+ bool isUndefined = false;
+
+ v8::HandleScope handle_scope;
+ v8::Context::Scope scope(ep->v8engine()->context());
+ v8::Local<v8::Value> result = d->v8value(0, &isUndefined);
+
+ trace.event("writing binding result");
+
+ bool needsErrorData = false;
+ if (!watcher.wasDeleted() && !d->hasError())
+ needsErrorData = !QQmlPropertyPrivate::writeBinding(d->property, d->context(),
+ d, result,
+ isUndefined, flags);
+
+ if (!watcher.wasDeleted()) {
+
+ if (needsErrorData) {
+ QUrl url = QUrl(d->url);
+ int line = d->line;
+ if (url.isEmpty()) url = QUrl(QLatin1String("<Unknown File>"));
+
+ d->delayedError()->error.setUrl(url);
+ d->delayedError()->error.setLine(line);
+ d->delayedError()->error.setColumn(-1);
+ }
+
+ if (d->hasError()) {
+ if (!d->delayedError()->addError(ep)) ep->warning(this->error());
+ } else {
+ d->clearError();
+ }
+
+ }
+
+ ep->dereferenceScarceResources();
+ }
+
+ if (!watcher.wasDeleted())
+ d->updating = false;
+ } else {
+ QQmlBindingPrivate::printBindingLoopError(d->property);
+ }
+}
+
+void QQmlBindingPrivate::printBindingLoopError(QQmlProperty &prop)
+{
+ qmlInfo(prop.object()) << QQmlBinding::tr("Binding loop detected for property \"%1\"").arg(prop.name());
+}
+
+void QQmlBindingPrivate::expressionChanged()
+{
+ Q_Q(QQmlBinding);
+ q->update();
+}
+
+void QQmlBinding::setEnabled(bool e, QQmlPropertyPrivate::WriteFlags flags)
+{
+ Q_D(QQmlBinding);
+ d->enabled = e;
+ setNotifyOnValueChanged(e);
+
+ if (e)
+ update(flags);
+}
+
+bool QQmlBinding::enabled() const
+{
+ Q_D(const QQmlBinding);
+
+ return d->enabled;
+}
+
+QString QQmlBinding::expression() const
+{
+ return QQmlExpression::expression();
+}
+
+int QQmlBinding::propertyIndex() const
+{
+ Q_D(const QQmlBinding);
+ return d->targetProperty;
+}
+
+QObject *QQmlBinding::object() const
+{
+ Q_D(const QQmlBinding);
+ return d->target;
+}
+
+void QQmlBinding::retargetBinding(QObject *t, int i)
+{
+ Q_D(QQmlBinding);
+ d->target = t;
+ d->targetProperty = i;
+}
+
+QQmlValueTypeProxyBinding::QQmlValueTypeProxyBinding(QObject *o, int index)
+: m_object(o), m_index(index), m_bindings(0)
+{
+}
+
+QQmlValueTypeProxyBinding::~QQmlValueTypeProxyBinding()
+{
+ while (m_bindings) {
+ QQmlAbstractBinding *binding = m_bindings;
+ binding->setEnabled(false, 0);
+ binding->destroy();
+ }
+}
+
+void QQmlValueTypeProxyBinding::setEnabled(bool e, QQmlPropertyPrivate::WriteFlags flags)
+{
+ if (e) {
+ QQmlAbstractBinding *bindings = m_bindings;
+ recursiveEnable(bindings, flags);
+ } else {
+ QQmlAbstractBinding *bindings = m_bindings;
+ recursiveDisable(bindings);
+ }
+}
+
+void QQmlValueTypeProxyBinding::recursiveEnable(QQmlAbstractBinding *b, QQmlPropertyPrivate::WriteFlags flags)
+{
+ if (!b)
+ return;
+
+ recursiveEnable(b->m_nextBinding, flags);
+
+ if (b)
+ b->setEnabled(true, flags);
+}
+
+void QQmlValueTypeProxyBinding::recursiveDisable(QQmlAbstractBinding *b)
+{
+ if (!b)
+ return;
+
+ recursiveDisable(b->m_nextBinding);
+
+ if (b)
+ b->setEnabled(false, 0);
+}
+
+void QQmlValueTypeProxyBinding::update(QQmlPropertyPrivate::WriteFlags)
+{
+}
+
+QQmlAbstractBinding *QQmlValueTypeProxyBinding::binding(int propertyIndex)
+{
+ QQmlAbstractBinding *binding = m_bindings;
+
+ while (binding && binding->propertyIndex() != propertyIndex)
+ binding = binding->m_nextBinding;
+
+ return binding;
+}
+
+/*!
+Removes a collection of bindings, corresponding to the set bits in \a mask.
+*/
+void QQmlValueTypeProxyBinding::removeBindings(quint32 mask)
+{
+ QQmlAbstractBinding *binding = m_bindings;
+ while (binding) {
+ if (mask & (1 << (binding->propertyIndex() >> 24))) {
+ QQmlAbstractBinding *remove = binding;
+ binding = remove->m_nextBinding;
+ *remove->m_prevBinding = remove->m_nextBinding;
+ if (remove->m_nextBinding) remove->m_nextBinding->m_prevBinding = remove->m_prevBinding;
+ remove->m_prevBinding = 0;
+ remove->m_nextBinding = 0;
+ remove->destroy();
+ } else {
+ binding = binding->m_nextBinding;
+ }
+ }
+}
+
+int QQmlValueTypeProxyBinding::propertyIndex() const
+{
+ return m_index;
+}
+
+QObject *QQmlValueTypeProxyBinding::object() const
+{
+ return m_object;
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlbinding_p.h b/src/qml/qml/qqmlbinding_p.h
new file mode 100644
index 0000000000..33823d7e7e
--- /dev/null
+++ b/src/qml/qml/qqmlbinding_p.h
@@ -0,0 +1,219 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLBINDING_P_H
+#define QQMLBINDING_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qqml.h"
+#include "qqmlpropertyvaluesource.h"
+#include "qqmlexpression.h"
+#include "qqmlproperty.h"
+#include "qqmlproperty_p.h"
+
+#include <QtCore/QObject>
+#include <QtCore/QMetaProperty>
+
+#include <private/qpointervaluepair_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q_QML_PRIVATE_EXPORT QQmlAbstractBinding
+{
+public:
+ typedef QWeakPointer<QQmlAbstractBinding> Pointer;
+
+ QQmlAbstractBinding();
+
+ virtual void destroy();
+
+ virtual QString expression() const;
+
+ enum Type { PropertyBinding, ValueTypeProxy };
+ virtual Type bindingType() const { return PropertyBinding; }
+
+ // Should return the encoded property index for the binding. Should return this value
+ // even if the binding is not enabled or added to an object.
+ // Encoding is: coreIndex | (valueTypeIndex << 24)
+ virtual int propertyIndex() const = 0;
+ // Should return the object for the binding. Should return this object even if the
+ // binding is not enabled or added to the object.
+ virtual QObject *object() const = 0;
+
+ void setEnabled(bool e) { setEnabled(e, QQmlPropertyPrivate::DontRemoveBinding); }
+ virtual void setEnabled(bool, QQmlPropertyPrivate::WriteFlags) = 0;
+
+ void update() { update(QQmlPropertyPrivate::DontRemoveBinding); }
+ virtual void update(QQmlPropertyPrivate::WriteFlags) = 0;
+
+ void addToObject();
+ void removeFromObject();
+
+ static inline Pointer getPointer(QQmlAbstractBinding *p);
+
+protected:
+ virtual ~QQmlAbstractBinding();
+ void clear();
+
+ // Called by QQmlPropertyPrivate to "move" a binding to a different property.
+ // This is only used for alias properties, and only used by QQmlBinding not
+ // V8 or V4 bindings. The default implementation qFatal()'s to ensure that the
+ // method is never called for V4 or V8 bindings.
+ virtual void retargetBinding(QObject *, int);
+private:
+ Pointer weakPointer();
+
+ friend class QQmlData;
+ friend class QQmlComponentPrivate;
+ friend class QQmlValueTypeProxyBinding;
+ friend class QQmlPropertyPrivate;
+ friend class QQmlVME;
+ friend class QtSharedPointer::ExternalRefCount<QQmlAbstractBinding>;
+
+ typedef QSharedPointer<QQmlAbstractBinding> SharedPointer;
+ // To save memory, we also store the rarely used weakPointer() instance in here
+ QPointerValuePair<QQmlAbstractBinding*, SharedPointer> m_mePtr;
+
+ QQmlAbstractBinding **m_prevBinding;
+ QQmlAbstractBinding *m_nextBinding;
+};
+
+class QQmlValueTypeProxyBinding : public QQmlAbstractBinding
+{
+public:
+ QQmlValueTypeProxyBinding(QObject *o, int coreIndex);
+
+ virtual Type bindingType() const { return ValueTypeProxy; }
+
+ virtual void setEnabled(bool, QQmlPropertyPrivate::WriteFlags);
+ virtual void update(QQmlPropertyPrivate::WriteFlags);
+ virtual int propertyIndex() const;
+ virtual QObject *object() const;
+
+ QQmlAbstractBinding *binding(int propertyIndex);
+
+ void removeBindings(quint32 mask);
+
+protected:
+ ~QQmlValueTypeProxyBinding();
+
+private:
+ void recursiveEnable(QQmlAbstractBinding *, QQmlPropertyPrivate::WriteFlags);
+ void recursiveDisable(QQmlAbstractBinding *);
+
+ friend class QQmlAbstractBinding;
+ QObject *m_object;
+ int m_index;
+ QQmlAbstractBinding *m_bindings;
+};
+
+class QQmlContext;
+class QQmlBindingPrivate;
+class Q_QML_PRIVATE_EXPORT QQmlBinding : public QQmlExpression,
+ public QQmlAbstractBinding
+{
+Q_OBJECT
+public:
+ enum EvaluateFlag { None = 0x00, RequiresThisObject = 0x01 };
+ Q_DECLARE_FLAGS(EvaluateFlags, EvaluateFlag)
+
+ QQmlBinding(const QString &, QObject *, QQmlContext *, QObject *parent=0);
+ QQmlBinding(const QString &, QObject *, QQmlContextData *, QObject *parent=0);
+ QQmlBinding(const QString &, bool isRewritten, QObject *, QQmlContextData *,
+ const QString &url, int lineNumber, int columnNumber = 0, QObject *parent=0);
+ QQmlBinding(void *, QObject *, QQmlContextData *, QObject *parent=0);
+
+ void setTarget(const QQmlProperty &);
+ void setTarget(QObject *, const QQmlPropertyData &, QQmlContextData *);
+ QQmlProperty property() const;
+
+ void setEvaluateFlags(EvaluateFlags flags);
+ EvaluateFlags evaluateFlags() const;
+
+ bool enabled() const;
+
+ // Inherited from QQmlAbstractBinding
+ virtual void setEnabled(bool, QQmlPropertyPrivate::WriteFlags flags);
+ virtual void update(QQmlPropertyPrivate::WriteFlags flags);
+ virtual QString expression() const;
+ virtual int propertyIndex() const;
+ virtual QObject *object() const;
+ virtual void retargetBinding(QObject *, int);
+
+ typedef int Identifier;
+ static Identifier Invalid;
+ static QQmlBinding *createBinding(Identifier, QObject *, QQmlContext *,
+ const QString &, int, QObject *parent=0);
+
+
+public Q_SLOTS:
+ void update() { update(QQmlPropertyPrivate::DontRemoveBinding); }
+
+protected:
+ ~QQmlBinding();
+
+private:
+ Q_DECLARE_PRIVATE(QQmlBinding)
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QQmlBinding::EvaluateFlags)
+
+QQmlAbstractBinding::Pointer
+QQmlAbstractBinding::getPointer(QQmlAbstractBinding *p)
+{
+ return p ? p->weakPointer() : Pointer();
+}
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(QQmlBinding*)
+
+#endif // QQMLBINDING_P_H
diff --git a/src/qml/qml/qqmlbinding_p_p.h b/src/qml/qml/qqmlbinding_p_p.h
new file mode 100644
index 0000000000..b53c903916
--- /dev/null
+++ b/src/qml/qml/qqmlbinding_p_p.h
@@ -0,0 +1,89 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLBINDING_P_P_H
+#define QQMLBINDING_P_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qqmlbinding_p.h"
+
+#include "qqmlproperty.h"
+#include "qqmlexpression_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QQmlBindingPrivate : public QQmlExpressionPrivate
+{
+ Q_DECLARE_PUBLIC(QQmlBinding)
+public:
+ QQmlBindingPrivate();
+ ~QQmlBindingPrivate();
+
+ virtual void expressionChanged();
+
+ static void printBindingLoopError(QQmlProperty &prop);
+
+protected:
+ virtual void refresh();
+
+private:
+ bool updating:1;
+ bool enabled:1;
+ int columnNumber;
+ QQmlProperty property;
+
+ QObject *target;
+ int targetProperty;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQMLBINDING_P_P_H
diff --git a/src/qml/qml/qqmlboundsignal.cpp b/src/qml/qml/qqmlboundsignal.cpp
new file mode 100644
index 0000000000..6f552450ef
--- /dev/null
+++ b/src/qml/qml/qqmlboundsignal.cpp
@@ -0,0 +1,300 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qqmlboundsignal_p.h"
+
+#include <private/qmetaobjectbuilder_p.h>
+#include "qqmlengine_p.h"
+#include "qqmlexpression_p.h"
+#include "qqmlcontext_p.h"
+#include "qqmlmetatype_p.h"
+#include "qqml.h"
+#include "qqmlcontext.h"
+#include "qqmlglobal_p.h"
+#include <private/qqmlprofilerservice_p.h>
+#include <private/qv8debugservice_p.h>
+
+#include <QtCore/qstringbuilder.h>
+#include <QtCore/qdebug.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQmlBoundSignalParameters : public QObject
+{
+Q_OBJECT
+public:
+ QQmlBoundSignalParameters(const QMetaMethod &, QObject * = 0);
+ ~QQmlBoundSignalParameters();
+
+ void setValues(void **);
+ void clearValues();
+
+private:
+ friend class MetaObject;
+ int metaCall(QMetaObject::Call, int _id, void **);
+ struct MetaObject : public QAbstractDynamicMetaObject {
+ MetaObject(QQmlBoundSignalParameters *b)
+ : parent(b) {}
+
+ int metaCall(QMetaObject::Call c, int id, void **a) {
+ return parent->metaCall(c, id, a);
+ }
+ QQmlBoundSignalParameters *parent;
+ };
+
+ int *types;
+ void **values;
+ QMetaObject *myMetaObject;
+};
+
+static int evaluateIdx = -1;
+
+QQmlAbstractBoundSignal::QQmlAbstractBoundSignal(QObject *parent)
+: QObject(parent)
+{
+}
+
+QQmlAbstractBoundSignal::~QQmlAbstractBoundSignal()
+{
+}
+
+QQmlBoundSignal::QQmlBoundSignal(QObject *scope, const QMetaMethod &signal,
+ QObject *parent)
+: m_expression(0), m_signal(signal), m_paramsValid(false), m_isEvaluating(false), m_params(0)
+{
+ // This is thread safe. Although it may be updated by two threads, they
+ // will both set it to the same value - so the worst thing that can happen
+ // is that they both do the work to figure it out. Boo hoo.
+ if (evaluateIdx == -1) evaluateIdx = metaObject()->methodCount();
+
+ QQml_setParent_noEvent(this, parent);
+ QQmlPropertyPrivate::connect(scope, m_signal.methodIndex(), this, evaluateIdx);
+}
+
+QQmlBoundSignal::QQmlBoundSignal(QQmlContext *ctxt, const QString &val,
+ QObject *scope, const QMetaMethod &signal,
+ QObject *parent)
+: m_expression(0), m_signal(signal), m_paramsValid(false), m_isEvaluating(false), m_params(0)
+{
+ // This is thread safe. Although it may be updated by two threads, they
+ // will both set it to the same value - so the worst thing that can happen
+ // is that they both do the work to figure it out. Boo hoo.
+ if (evaluateIdx == -1) evaluateIdx = metaObject()->methodCount();
+
+ QQml_setParent_noEvent(this, parent);
+ QQmlPropertyPrivate::connect(scope, m_signal.methodIndex(), this, evaluateIdx);
+
+ m_expression = new QQmlExpression(ctxt, scope, val);
+}
+
+QQmlBoundSignal::~QQmlBoundSignal()
+{
+ delete m_expression;
+ m_expression = 0;
+}
+
+int QQmlBoundSignal::index() const
+{
+ return m_signal.methodIndex();
+}
+
+/*!
+ Returns the signal expression.
+*/
+QQmlExpression *QQmlBoundSignal::expression() const
+{
+ return m_expression;
+}
+
+/*!
+ Sets the signal expression to \a e. Returns the current signal expression,
+ or null if there is no signal expression.
+
+ The QQmlBoundSignal instance takes ownership of \a e. The caller is
+ assumes ownership of the returned QQmlExpression.
+*/
+QQmlExpression *QQmlBoundSignal::setExpression(QQmlExpression *e)
+{
+ QQmlExpression *rv = m_expression;
+ m_expression = e;
+ if (m_expression) m_expression->setNotifyOnValueChanged(false);
+ return rv;
+}
+
+QQmlBoundSignal *QQmlBoundSignal::cast(QObject *o)
+{
+ QQmlAbstractBoundSignal *s = qobject_cast<QQmlAbstractBoundSignal*>(o);
+ return static_cast<QQmlBoundSignal *>(s);
+}
+
+int QQmlBoundSignal::qt_metacall(QMetaObject::Call c, int id, void **a)
+{
+ if (c == QMetaObject::InvokeMetaMethod && id == evaluateIdx) {
+ if (!m_expression)
+ return -1;
+ if (QQmlDebugService::isDebuggingEnabled()) {
+ QQmlProfilerService::startRange(QQmlProfilerService::HandlingSignal);
+ QQmlProfilerService::rangeData(QQmlProfilerService::HandlingSignal, QLatin1String(m_signal.signature()) % QLatin1String(": ") % m_expression->expression());
+ QQmlProfilerService::rangeLocation(QQmlProfilerService::HandlingSignal, m_expression->sourceFile(), m_expression->lineNumber(), m_expression->columnNumber());
+ QV8DebugService::instance()->signalEmitted(QString::fromAscii(m_signal.signature()));
+ }
+ m_isEvaluating = true;
+ if (!m_paramsValid) {
+ if (!m_signal.parameterTypes().isEmpty())
+ m_params = new QQmlBoundSignalParameters(m_signal, this);
+ m_paramsValid = true;
+ }
+
+ if (m_params) m_params->setValues(a);
+ if (m_expression && m_expression->engine()) {
+ QQmlExpressionPrivate::get(m_expression)->value(m_params);
+ if (m_expression && m_expression->hasError())
+ QQmlEnginePrivate::warning(m_expression->engine(), m_expression->error());
+ }
+ if (m_params) m_params->clearValues();
+ m_isEvaluating = false;
+ QQmlProfilerService::endRange(QQmlProfilerService::HandlingSignal);
+ return -1;
+ } else {
+ return QObject::qt_metacall(c, id, a);
+ }
+}
+
+QQmlBoundSignalParameters::QQmlBoundSignalParameters(const QMetaMethod &method,
+ QObject *parent)
+: QObject(parent), types(0), values(0)
+{
+ MetaObject *mo = new MetaObject(this);
+
+ // ### Optimize!
+ QMetaObjectBuilder mob;
+ mob.setSuperClass(&QQmlBoundSignalParameters::staticMetaObject);
+ mob.setClassName("QQmlBoundSignalParameters");
+
+ QList<QByteArray> paramTypes = method.parameterTypes();
+ QList<QByteArray> paramNames = method.parameterNames();
+ types = new int[paramTypes.count()];
+ for (int ii = 0; ii < paramTypes.count(); ++ii) {
+ const QByteArray &type = paramTypes.at(ii);
+ const QByteArray &name = paramNames.at(ii);
+
+ if (name.isEmpty() || type.isEmpty()) {
+ types[ii] = 0;
+ continue;
+ }
+
+ QVariant::Type t = (QVariant::Type)QMetaType::type(type.constData());
+ if (QQmlMetaType::isQObject(t)) {
+ types[ii] = QMetaType::QObjectStar;
+ QMetaPropertyBuilder prop = mob.addProperty(name, "QObject*");
+ prop.setWritable(false);
+ } else {
+ QByteArray propType = type;
+ if (t >= QVariant::UserType || t == QVariant::Invalid) {
+ QByteArray scope;
+ QByteArray name;
+ int scopeIdx = propType.lastIndexOf("::");
+ if (scopeIdx != -1) {
+ scope = propType.left(scopeIdx);
+ name = propType.mid(scopeIdx + 2);
+ } else {
+ name = propType;
+ }
+ const QMetaObject *meta;
+ if (scope == "Qt")
+ meta = &QObject::staticQtMetaObject;
+ else
+ meta = parent->parent()->metaObject(); //### assumes parent->parent()
+ for (int i = meta->enumeratorCount() - 1; i >= 0; --i) {
+ QMetaEnum m = meta->enumerator(i);
+ if ((m.name() == name) && (scope.isEmpty() || (m.scope() == scope))) {
+ t = QVariant::Int;
+ propType = "int";
+ break;
+ }
+ }
+ }
+ types[ii] = t;
+ QMetaPropertyBuilder prop = mob.addProperty(name, propType);
+ prop.setWritable(false);
+ }
+ }
+ myMetaObject = mob.toMetaObject();
+ *static_cast<QMetaObject *>(mo) = *myMetaObject;
+
+ d_ptr->metaObject = mo;
+}
+
+QQmlBoundSignalParameters::~QQmlBoundSignalParameters()
+{
+ delete [] types;
+ free(myMetaObject);
+}
+
+void QQmlBoundSignalParameters::setValues(void **v)
+{
+ values = v;
+}
+
+void QQmlBoundSignalParameters::clearValues()
+{
+ values = 0;
+}
+
+int QQmlBoundSignalParameters::metaCall(QMetaObject::Call c, int id, void **a)
+{
+ if (!values)
+ return -1;
+
+ if (c == QMetaObject::ReadProperty && id >= 1) {
+ int t = types[id - 1];
+ void *p = a[0];
+ QMetaType::destruct(t, p);
+ QMetaType::construct(t, p, values[id]);
+ return -1;
+ } else {
+ return qt_metacall(c, id, a);
+ }
+}
+
+QT_END_NAMESPACE
+
+#include <qqmlboundsignal.moc>
diff --git a/src/qml/qml/qqmlboundsignal_p.h b/src/qml/qml/qqmlboundsignal_p.h
new file mode 100644
index 0000000000..11386159cb
--- /dev/null
+++ b/src/qml/qml/qqmlboundsignal_p.h
@@ -0,0 +1,103 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLBOUNDSIGNAL_P_H
+#define QQMLBOUNDSIGNAL_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 "qqmlexpression.h"
+
+#include <QtCore/qmetaobject.h>
+
+#include <private/qobject_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q_QML_EXPORT QQmlAbstractBoundSignal : public QObject
+{
+ Q_OBJECT
+public:
+ QQmlAbstractBoundSignal(QObject *parent = 0);
+ virtual ~QQmlAbstractBoundSignal() = 0;
+};
+
+class QQmlBoundSignalParameters;
+class Q_QML_EXPORT QQmlBoundSignal : public QQmlAbstractBoundSignal
+{
+public:
+ QQmlBoundSignal(QObject *scope, const QMetaMethod &signal, QObject *parent);
+ QQmlBoundSignal(QQmlContext *ctxt, const QString &val, QObject *scope,
+ const QMetaMethod &signal, QObject *parent);
+ virtual ~QQmlBoundSignal();
+
+ int index() const;
+
+ QQmlExpression *expression() const;
+ QQmlExpression *setExpression(QQmlExpression *);
+
+ bool isEvaluating() const { return m_isEvaluating; }
+
+ static QQmlBoundSignal *cast(QObject *);
+
+protected:
+ virtual int qt_metacall(QMetaObject::Call c, int id, void **a);
+
+private:
+ QQmlExpression *m_expression;
+ QMetaMethod m_signal;
+ bool m_paramsValid : 1;
+ bool m_isEvaluating : 1;
+ QQmlBoundSignalParameters *m_params;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQMLBOUNDSIGNAL_P_H
diff --git a/src/qml/qml/qqmlcleanup.cpp b/src/qml/qml/qqmlcleanup.cpp
new file mode 100644
index 0000000000..21ea02ee17
--- /dev/null
+++ b/src/qml/qml/qqmlcleanup.cpp
@@ -0,0 +1,118 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qqmlcleanup_p.h"
+
+#include "qqmlengine_p.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+\internal
+\class QQmlCleanup
+\brief The QQmlCleanup provides a callback when a QQmlEngine is deleted.
+
+Any object that needs cleanup to occur before the QQmlEngine's V8 engine is
+destroyed should inherit from QQmlCleanup. The clear() virtual method will be
+called by QQmlEngine just before it destroys the context.
+*/
+
+
+/*
+Create a QQmlCleanup that is not associated with any engine.
+*/
+QQmlCleanup::QQmlCleanup()
+: prev(0), next(0), engine(0)
+{
+}
+
+/*!
+Create a QQmlCleanup for \a engine
+*/
+QQmlCleanup::QQmlCleanup(QQmlEngine *engine)
+: prev(0), next(0), engine(0)
+{
+ if (!engine)
+ return;
+
+ addToEngine(engine);
+}
+
+/*!
+Adds this object to \a engine's cleanup list. hasEngine() must be false
+before calling this method.
+*/
+void QQmlCleanup::addToEngine(QQmlEngine *engine)
+{
+ Q_ASSERT(engine);
+ Q_ASSERT(QQmlEnginePrivate::isEngineThread(engine));
+
+ this->engine = engine;
+
+ QQmlEnginePrivate *p = QQmlEnginePrivate::get(engine);
+
+ if (p->cleanup) next = p->cleanup;
+ p->cleanup = this;
+ prev = &p->cleanup;
+ if (next) next->prev = &next;
+}
+
+/*!
+\fn bool QQmlCleanup::hasEngine() const
+
+Returns true if this QQmlCleanup is associated with an engine, otherwise false.
+*/
+
+/*!
+\internal
+*/
+QQmlCleanup::~QQmlCleanup()
+{
+ Q_ASSERT(!prev || engine);
+ Q_ASSERT(!prev || QQmlEnginePrivate::isEngineThread(engine));
+
+ if (prev) *prev = next;
+ if (next) next->prev = prev;
+ prev = 0;
+ next = 0;
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlcleanup_p.h b/src/qml/qml/qqmlcleanup_p.h
new file mode 100644
index 0000000000..2b7747d630
--- /dev/null
+++ b/src/qml/qml/qqmlcleanup_p.h
@@ -0,0 +1,87 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLCLEANUP_P_H
+#define QQMLCLEANUP_P_H
+
+#include <QtQml/qtqmlglobal.h>
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+QT_BEGIN_NAMESPACE
+
+class QQmlEngine;
+
+// Exported for QtQuick1
+class Q_QML_EXPORT QQmlCleanup
+{
+public:
+ QQmlCleanup();
+ QQmlCleanup(QQmlEngine *);
+ virtual ~QQmlCleanup();
+
+ bool hasEngine() const { return prev != 0; }
+ void addToEngine(QQmlEngine *);
+protected:
+ virtual void clear() = 0;
+
+private:
+ friend class QQmlEnginePrivate;
+ QQmlCleanup **prev;
+ QQmlCleanup *next;
+
+ // Only used for asserts
+ QQmlEngine *engine;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQMLCLEANUP_P_H
+
diff --git a/src/qml/qml/qqmlcompileddata.cpp b/src/qml/qml/qqmlcompileddata.cpp
new file mode 100644
index 0000000000..6a68784219
--- /dev/null
+++ b/src/qml/qml/qqmlcompileddata.cpp
@@ -0,0 +1,261 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qqmlcompiler_p.h"
+#include "qqmlengine.h"
+#include "qqmlcomponent.h"
+#include "qqmlcomponent_p.h"
+#include "qqmlcontext.h"
+#include "qqmlcontext_p.h"
+#ifdef QML_THREADED_VME_INTERPRETER
+#include "qqmlvme_p.h"
+#endif
+
+#include <QtCore/qdebug.h>
+
+#include <private/qobject_p.h>
+
+QT_BEGIN_NAMESPACE
+
+int QQmlCompiledData::pack(const char *data, size_t size)
+{
+ const char *p = packData.constData();
+ unsigned int ps = packData.size();
+
+ for (unsigned int ii = 0; (ii + size) <= ps; ii += sizeof(int)) {
+ if (0 == ::memcmp(p + ii, data, size))
+ return ii;
+ }
+
+ int rv = packData.size();
+ packData.append(data, size);
+ return rv;
+}
+
+int QQmlCompiledData::indexForString(const QString &data)
+{
+ int idx = primitives.indexOf(data);
+ if (idx == -1) {
+ idx = primitives.count();
+ primitives << data;
+ }
+ return idx;
+}
+
+int QQmlCompiledData::indexForByteArray(const QByteArray &data)
+{
+ int idx = datas.indexOf(data);
+ if (idx == -1) {
+ idx = datas.count();
+ datas << data;
+ }
+ return idx;
+}
+
+int QQmlCompiledData::indexForUrl(const QUrl &data)
+{
+ int idx = urls.indexOf(data);
+ if (idx == -1) {
+ idx = urls.count();
+ urls << data;
+ }
+ return idx;
+}
+
+QQmlCompiledData::QQmlCompiledData(QQmlEngine *engine)
+: engine(engine), importCache(0), root(0), rootPropertyCache(0)
+{
+ Q_ASSERT(engine);
+
+ bytecode.reserve(1024);
+}
+
+void QQmlCompiledData::destroy()
+{
+ if (engine && hasEngine())
+ QQmlEnginePrivate::deleteInEngineThread(engine, this);
+ else
+ delete this;
+}
+
+QQmlCompiledData::~QQmlCompiledData()
+{
+ clear();
+
+ for (int ii = 0; ii < types.count(); ++ii) {
+ if (types.at(ii).component)
+ types.at(ii).component->release();
+ if (types.at(ii).typePropertyCache)
+ types.at(ii).typePropertyCache->release();
+ }
+
+ for (int ii = 0; ii < propertyCaches.count(); ++ii)
+ propertyCaches.at(ii)->release();
+
+ for (int ii = 0; ii < contextCaches.count(); ++ii)
+ contextCaches.at(ii)->release();
+
+ for (int ii = 0; ii < scripts.count(); ++ii)
+ scripts.at(ii)->release();
+
+ if (importCache)
+ importCache->release();
+
+ if (rootPropertyCache)
+ rootPropertyCache->release();
+}
+
+void QQmlCompiledData::clear()
+{
+ for (int ii = 0; ii < programs.count(); ++ii)
+ qPersistentDispose(programs[ii].bindings);
+}
+
+const QMetaObject *QQmlCompiledData::TypeReference::metaObject() const
+{
+ if (type) {
+ return type->metaObject();
+ } else {
+ Q_ASSERT(component);
+ return component->root;
+ }
+}
+
+/*!
+Returns the property cache, if one alread exists. The cache is not referenced.
+*/
+QQmlPropertyCache *QQmlCompiledData::TypeReference::propertyCache() const
+{
+ if (type)
+ return typePropertyCache;
+ else
+ return component->rootPropertyCache;
+}
+
+/*!
+Returns the property cache, creating one if it doesn't already exist. The cache is not referenced.
+*/
+QQmlPropertyCache *QQmlCompiledData::TypeReference::createPropertyCache(QQmlEngine *engine)
+{
+ if (typePropertyCache) {
+ return typePropertyCache;
+ } else if (type) {
+ typePropertyCache = QQmlEnginePrivate::get(engine)->cache(type->metaObject());
+ typePropertyCache->addref();
+ return typePropertyCache;
+ } else {
+ return component->rootPropertyCache;
+ }
+}
+
+
+void QQmlCompiledData::dumpInstructions()
+{
+ if (!name.isEmpty())
+ qWarning() << name;
+ qWarning().nospace() << "Index\tOperation\t\tData1\tData2\tData3\tComments";
+ qWarning().nospace() << "-------------------------------------------------------------------------------";
+
+ const char *instructionStream = bytecode.constData();
+ const char *endInstructionStream = bytecode.constData() + bytecode.size();
+
+ int instructionCount = 0;
+ while (instructionStream < endInstructionStream) {
+ QQmlInstruction *instr = (QQmlInstruction *)instructionStream;
+ dump(instr, instructionCount);
+ instructionStream += QQmlInstruction::size(instructionType(instr));
+ instructionCount++;
+ }
+
+ qWarning().nospace() << "-------------------------------------------------------------------------------";
+}
+
+int QQmlCompiledData::addInstructionHelper(QQmlInstruction::Type type, QQmlInstruction &instr)
+{
+#ifdef QML_THREADED_VME_INTERPRETER
+ instr.common.code = QQmlVME::instructionJumpTable()[static_cast<int>(type)];
+#else
+ instr.common.instructionType = type;
+#endif
+ int ptrOffset = bytecode.size();
+ int size = QQmlInstruction::size(type);
+ if (bytecode.capacity() <= bytecode.size() + size)
+ bytecode.reserve(bytecode.size() + size + 512);
+ bytecode.append(reinterpret_cast<const char *>(&instr), size);
+ return ptrOffset;
+}
+
+int QQmlCompiledData::nextInstructionIndex()
+{
+ return bytecode.size();
+}
+
+QQmlInstruction *QQmlCompiledData::instruction(int index)
+{
+ return (QQmlInstruction *)(bytecode.constData() + index);
+}
+
+QQmlInstruction::Type QQmlCompiledData::instructionType(const QQmlInstruction *instr)
+{
+#ifdef QML_THREADED_VME_INTERPRETER
+ void **jumpTable = QQmlVME::instructionJumpTable();
+ void *code = instr->common.code;
+
+# define QML_CHECK_INSTR_CODE(I, FMT) \
+ if (jumpTable[static_cast<int>(QQmlInstruction::I)] == code) \
+ return QQmlInstruction::I;
+
+ FOR_EACH_QML_INSTR(QML_CHECK_INSTR_CODE)
+ Q_ASSERT_X(false, Q_FUNC_INFO, "Invalid instruction address");
+ return static_cast<QQmlInstruction::Type>(0);
+# undef QML_CHECK_INSTR_CODE
+#else
+ return static_cast<QQmlInstruction::Type>(instr->common.instructionType);
+#endif
+}
+
+void QQmlCompiledData::initialize(QQmlEngine *engine)
+{
+ Q_ASSERT(!hasEngine());
+ QQmlCleanup::addToEngine(engine);
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlcompiler.cpp b/src/qml/qml/qqmlcompiler.cpp
new file mode 100644
index 0000000000..65247e1e80
--- /dev/null
+++ b/src/qml/qml/qqmlcompiler.cpp
@@ -0,0 +1,3882 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qqmlcompiler_p.h"
+
+#include "qqmlpropertyvaluesource.h"
+#include "qqmlcomponent.h"
+#include <private/qmetaobjectbuilder_p.h>
+#include <private/qfastmetabuilder_p.h>
+#include "qqmlstringconverters_p.h"
+#include "qqmlengine_p.h"
+#include "qqmlengine.h"
+#include "qqmlcontext.h"
+#include "qqmlmetatype_p.h"
+#include "qqmlcustomparser_p_p.h"
+#include "qqmlcontext_p.h"
+#include "qqmlcomponent_p.h"
+#include <private/qqmljsast_p.h>
+#include "qqmlvmemetaobject_p.h"
+#include "qqmlexpression_p.h"
+#include "qqmlproperty_p.h"
+#include "qqmlrewrite_p.h"
+#include "qqmlscriptstring.h"
+#include "qqmlglobal_p.h"
+#include "qqmlbinding_p.h"
+#include <private/qv4compiler_p.h>
+
+#include <QColor>
+#include <QDebug>
+#include <QPointF>
+#include <QSizeF>
+#include <QRectF>
+#include <QAtomicInt>
+#include <QtCore/qdebug.h>
+#include <QtCore/qdatetime.h>
+
+Q_DECLARE_METATYPE(QList<int>)
+Q_DECLARE_METATYPE(QList<qreal>)
+Q_DECLARE_METATYPE(QList<bool>)
+Q_DECLARE_METATYPE(QList<QString>)
+Q_DECLARE_METATYPE(QList<QUrl>)
+
+QT_BEGIN_NAMESPACE
+
+DEFINE_BOOL_CONFIG_OPTION(compilerDump, QML_COMPILER_DUMP);
+DEFINE_BOOL_CONFIG_OPTION(compilerStatDump, QML_COMPILER_STATS);
+
+using namespace QQmlJS;
+using namespace QQmlScript;
+using namespace QQmlCompilerTypes;
+
+static QString id_string(QLatin1String("id"));
+static QString on_string(QLatin1String("on"));
+static QString Changed_string(QLatin1String("Changed"));
+static QString Component_string(QLatin1String("Component"));
+static QString Component_import_string(QLatin1String("QML/Component"));
+static QString qsTr_string(QLatin1String("qsTr"));
+static QString qsTrId_string(QLatin1String("qsTrId"));
+
+/*!
+ Instantiate a new QQmlCompiler.
+*/
+QQmlCompiler::QQmlCompiler(QQmlPool *pool)
+: pool(pool), output(0), engine(0), unitRoot(0), unit(0), cachedComponentTypeRef(-1),
+ cachedTranslationContextIndex(-1), componentStats(0)
+{
+ if (compilerStatDump())
+ componentStats = pool->New<ComponentStats>();
+}
+
+/*!
+ Returns true if the last call to compile() caused errors.
+
+ \sa errors()
+*/
+bool QQmlCompiler::isError() const
+{
+ return !exceptions.isEmpty();
+}
+
+/*!
+ Return the list of errors from the last call to compile(), or an empty list
+ if there were no errors.
+*/
+QList<QQmlError> QQmlCompiler::errors() const
+{
+ return exceptions;
+}
+
+/*!
+ Returns true if \a name refers to an attached property, false otherwise.
+
+ Attached property names are those that start with a capital letter.
+*/
+bool QQmlCompiler::isAttachedPropertyName(const QString &name)
+{
+ return isAttachedPropertyName(QHashedStringRef(&name));
+}
+
+bool QQmlCompiler::isAttachedPropertyName(const QHashedStringRef &name)
+{
+ return !name.isEmpty() && name.at(0).isUpper();
+}
+
+/*!
+ Returns true if \a name refers to a signal property, false otherwise.
+
+ Signal property names are those that start with "on", followed by a first
+ character which is either a capital letter or one or more underscores followed
+ by a capital letter, which is then followed by other allowed characters.
+
+ Note that although ECMA-262r3 supports dollarsigns and escaped unicode
+ character codes in property names, for simplicity and performance reasons
+ QML only supports letters, numbers and underscores.
+*/
+bool QQmlCompiler::isSignalPropertyName(const QString &name)
+{
+ return isSignalPropertyName(QStringRef(&name));
+}
+
+bool QQmlCompiler::isSignalPropertyName(const QHashedStringRef &name)
+{
+ if (name.length() < 3) return false;
+ if (!name.startsWith(on_string)) return false;
+ int ns = name.length();
+ for (int i = 2; i < ns; ++i) {
+ const QChar curr = name.at(i);
+ if (curr.unicode() == '_') continue;
+ if (curr.isUpper()) return true;
+ return false;
+ }
+ return false; // consists solely of underscores - invalid.
+}
+
+/*!
+ \macro COMPILE_EXCEPTION
+ \internal
+ Inserts an error into the QQmlCompiler error list, and returns false
+ (failure).
+
+ \a token is used to source the error line and column, and \a desc is the
+ error itself. \a desc can be an expression that can be piped into QDebug.
+
+ For example:
+
+ \code
+ COMPILE_EXCEPTION(property, tr("Error for property \"%1\"").arg(property->name));
+ \endcode
+*/
+#define COMPILE_EXCEPTION_LOCATION(line, column, desc) \
+ { \
+ QQmlError error; \
+ error.setUrl(output->url); \
+ error.setLine(line); \
+ error.setColumn(column); \
+ error.setDescription(desc.trimmed()); \
+ exceptions << error; \
+ return false; \
+ }
+
+#define COMPILE_EXCEPTION(token, desc) \
+ COMPILE_EXCEPTION_LOCATION((token)->location.start.line, (token)->location.start.column, desc)
+
+/*!
+ \macro COMPILE_CHECK
+ \internal
+ Returns false if \a is false, otherwise does nothing.
+*/
+#define COMPILE_CHECK(a) \
+ { \
+ if (!a) return false; \
+ }
+
+/*!
+ Returns true if literal \a v can be assigned to property \a prop, otherwise
+ false.
+
+ This test corresponds to action taken by genLiteralAssignment(). Any change
+ made here, must have a corresponding action in genLiteralAssigment().
+*/
+bool QQmlCompiler::testLiteralAssignment(QQmlScript::Property *prop,
+ QQmlScript::Value *v)
+{
+ const QQmlScript::Variant &value = v->value;
+
+ if (!prop->core.isWritable() && !prop->isReadOnlyDeclaration)
+ COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
+
+ if (prop->core.isEnum()) {
+ QMetaProperty p = prop->parent->metaObject()->property(prop->index);
+ int enumValue;
+ bool ok;
+ if (p.isFlagType()) {
+ enumValue = p.enumerator().keysToValue(value.asString().toUtf8().constData(), &ok);
+ } else
+ enumValue = p.enumerator().keyToValue(value.asString().toUtf8().constData(), &ok);
+
+ if (!ok)
+ COMPILE_EXCEPTION(v, tr("Invalid property assignment: unknown enumeration"));
+
+ v->value = QQmlScript::Variant((double)enumValue);
+ return true;
+ }
+
+ int type = prop->type;
+
+ switch(type) {
+ case QMetaType::QVariant:
+ break;
+ case QVariant::String:
+ if (!v->value.isString()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: string expected"));
+ break;
+ case QVariant::StringList: // we expect a string literal. A string list is not a literal assignment.
+ if (!v->value.isString()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: string or string list expected"));
+ break;
+ case QVariant::ByteArray:
+ if (!v->value.isString()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: byte array expected"));
+ break;
+ case QVariant::Url:
+ if (!v->value.isString()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: url expected"));
+ break;
+ case QVariant::RegExp:
+ COMPILE_EXCEPTION(v, tr("Invalid property assignment: regular expression expected; use /pattern/ syntax"));
+ break;
+ case QVariant::UInt:
+ {
+ bool ok = v->value.isNumber();
+ if (ok) {
+ double n = v->value.asNumber();
+ if (double(uint(n)) != n)
+ ok = false;
+ }
+ if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: unsigned int expected"));
+ }
+ break;
+ case QVariant::Int:
+ {
+ bool ok = v->value.isNumber();
+ if (ok) {
+ double n = v->value.asNumber();
+ if (double(int(n)) != n)
+ ok = false;
+ }
+ if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: int expected"));
+ }
+ break;
+ case QMetaType::Float:
+ if (!v->value.isNumber()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: number expected"));
+ break;
+ case QVariant::Double:
+ if (!v->value.isNumber()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: number expected"));
+ break;
+ case QVariant::Color:
+ {
+ bool ok;
+ QQmlStringConverters::colorFromString(value.asString(), &ok);
+ if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: color expected"));
+ }
+ break;
+#ifndef QT_NO_DATESTRING
+ case QVariant::Date:
+ {
+ bool ok;
+ QQmlStringConverters::dateFromString(value.asString(), &ok);
+ if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: date expected"));
+ }
+ break;
+ case QVariant::Time:
+ {
+ bool ok;
+ QQmlStringConverters::timeFromString(value.asString(), &ok);
+ if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: time expected"));
+ }
+ break;
+ case QVariant::DateTime:
+ {
+ bool ok;
+ QQmlStringConverters::dateTimeFromString(value.asString(), &ok);
+ if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: datetime expected"));
+ }
+ break;
+#endif // QT_NO_DATESTRING
+ case QVariant::Point:
+ case QVariant::PointF:
+ {
+ bool ok;
+ QQmlStringConverters::pointFFromString(value.asString(), &ok);
+ if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: point expected"));
+ }
+ break;
+ case QVariant::Size:
+ case QVariant::SizeF:
+ {
+ bool ok;
+ QQmlStringConverters::sizeFFromString(value.asString(), &ok);
+ if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: size expected"));
+ }
+ break;
+ case QVariant::Rect:
+ case QVariant::RectF:
+ {
+ bool ok;
+ QQmlStringConverters::rectFFromString(value.asString(), &ok);
+ if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: rect expected"));
+ }
+ break;
+ case QVariant::Bool:
+ {
+ if (!v->value.isBoolean()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: boolean expected"));
+ }
+ break;
+ case QVariant::Vector3D:
+ {
+ bool ok;
+ QQmlStringConverters::vector3DFromString(value.asString(), &ok);
+ if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: 3D vector expected"));
+ }
+ break;
+ case QVariant::Vector4D:
+ {
+ bool ok;
+ QQmlStringConverters::vector4DFromString(value.asString(), &ok);
+ if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: 4D vector expected"));
+ }
+ break;
+ default:
+ {
+ // check if assigning a literal value to a list property.
+ // in each case, check the singular, since an Array of the specified type
+ // will not go via this literal assignment codepath.
+ if (type == qMetaTypeId<QList<qreal> >()) {
+ if (!v->value.isNumber()) {
+ COMPILE_EXCEPTION(v, tr("Invalid property assignment: real or array of reals expected"));
+ }
+ break;
+ } else if (type == qMetaTypeId<QList<int> >()) {
+ bool ok = v->value.isNumber();
+ if (ok) {
+ double n = v->value.asNumber();
+ if (double(int(n)) != n)
+ ok = false;
+ }
+ if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: int or array of ints expected"));
+ break;
+ } else if (type == qMetaTypeId<QList<bool> >()) {
+ if (!v->value.isBoolean()) {
+ COMPILE_EXCEPTION(v, tr("Invalid property assignment: bool or array of bools expected"));
+ }
+ break;
+ } else if (type == qMetaTypeId<QList<QString> >()) { // we expect a string literal. A string list is not a literal assignment.
+ if (!v->value.isString()) {
+ COMPILE_EXCEPTION(v, tr("Invalid property assignment: string or array of strings expected"));
+ }
+ break;
+ } else if (type == qMetaTypeId<QList<QUrl> >()) {
+ if (!v->value.isString()) {
+ COMPILE_EXCEPTION(v, tr("Invalid property assignment: url or array of urls expected"));
+ }
+ break;
+ }
+
+ // otherwise, check for existence of string converter to custom type
+ QQmlMetaType::StringConverter converter = QQmlMetaType::customStringConverter(type);
+ if (!converter)
+ COMPILE_EXCEPTION(v, tr("Invalid property assignment: unsupported type \"%1\"").arg(QString::fromLatin1(QVariant::typeToName((QVariant::Type)type))));
+ }
+ break;
+ }
+ return true;
+}
+
+static QUrl urlFromUserString(const QString &data)
+{
+ QUrl u;
+ // Preserve any valid percent-encoded octets supplied by the source
+ u.setEncodedUrl(data.toUtf8(), QUrl::TolerantMode);
+ return u;
+}
+
+/*!
+ Generate a store instruction for assigning literal \a v to property \a prop.
+
+ Any literal assignment that is approved in testLiteralAssignment() must have
+ a corresponding action in this method.
+*/
+void QQmlCompiler::genLiteralAssignment(QQmlScript::Property *prop,
+ QQmlScript::Value *v)
+{
+ if (prop->core.isEnum()) {
+ Q_ASSERT(v->value.isNumber());
+ // Preresolved value
+ int value = (int)v->value.asNumber();
+
+ Instruction::StoreInteger instr;
+ instr.propertyIndex = prop->index;
+ instr.value = value;
+ output->addInstruction(instr);
+ return;
+ }
+
+ int type = prop->type;
+ switch(type) {
+ case QMetaType::QVariant:
+ {
+ if (v->value.isNumber()) {
+ double n = v->value.asNumber();
+ if (double(int(n)) == n) {
+ if (prop->core.isVMEProperty()) {
+ Instruction::StoreVarInteger instr;
+ instr.propertyIndex = prop->index;
+ instr.value = int(n);
+ output->addInstruction(instr);
+ } else {
+ Instruction::StoreVariantInteger instr;
+ instr.propertyIndex = prop->index;
+ instr.value = int(n);
+ output->addInstruction(instr);
+ }
+ } else {
+ if (prop->core.isVMEProperty()) {
+ Instruction::StoreVarDouble instr;
+ instr.propertyIndex = prop->index;
+ instr.value = n;
+ output->addInstruction(instr);
+ } else {
+ Instruction::StoreVariantDouble instr;
+ instr.propertyIndex = prop->index;
+ instr.value = n;
+ output->addInstruction(instr);
+ }
+ }
+ } else if (v->value.isBoolean()) {
+ if (prop->core.isVMEProperty()) {
+ Instruction::StoreVarBool instr;
+ instr.propertyIndex = prop->index;
+ instr.value = v->value.asBoolean();
+ output->addInstruction(instr);
+ } else {
+ Instruction::StoreVariantBool instr;
+ instr.propertyIndex = prop->index;
+ instr.value = v->value.asBoolean();
+ output->addInstruction(instr);
+ }
+ } else {
+ if (prop->core.isVMEProperty()) {
+ Instruction::StoreVar instr;
+ instr.propertyIndex = prop->index;
+ instr.value = output->indexForString(v->value.asString());
+ output->addInstruction(instr);
+ } else {
+ Instruction::StoreVariant instr;
+ instr.propertyIndex = prop->index;
+ instr.value = output->indexForString(v->value.asString());
+ output->addInstruction(instr);
+ }
+ }
+ }
+ break;
+ case QVariant::String:
+ {
+ Instruction::StoreString instr;
+ instr.propertyIndex = prop->index;
+ instr.value = output->indexForString(v->value.asString());
+ output->addInstruction(instr);
+ }
+ break;
+ case QVariant::StringList:
+ {
+ Instruction::StoreStringList instr;
+ instr.propertyIndex = prop->index;
+ instr.value = output->indexForString(v->value.asString());
+ output->addInstruction(instr);
+ }
+ break;
+ case QVariant::ByteArray:
+ {
+ Instruction::StoreByteArray instr;
+ instr.propertyIndex = prop->index;
+ instr.value = output->indexForByteArray(v->value.asString().toLatin1());
+ output->addInstruction(instr);
+ }
+ break;
+ case QVariant::Url:
+ {
+ Instruction::StoreUrl instr;
+ QString string = v->value.asString();
+ QUrl u = string.isEmpty() ? QUrl() : output->url.resolved(urlFromUserString(string));
+ instr.propertyIndex = prop->index;
+ instr.value = output->indexForUrl(u);
+ output->addInstruction(instr);
+ }
+ break;
+ case QVariant::UInt:
+ {
+ Instruction::StoreInteger instr;
+ instr.propertyIndex = prop->index;
+ instr.value = uint(v->value.asNumber());
+ output->addInstruction(instr);
+ }
+ break;
+ case QVariant::Int:
+ {
+ Instruction::StoreInteger instr;
+ instr.propertyIndex = prop->index;
+ instr.value = int(v->value.asNumber());
+ output->addInstruction(instr);
+ }
+ break;
+ case QMetaType::Float:
+ {
+ Instruction::StoreFloat instr;
+ instr.propertyIndex = prop->index;
+ instr.value = float(v->value.asNumber());
+ output->addInstruction(instr);
+ }
+ break;
+ case QVariant::Double:
+ {
+ Instruction::StoreDouble instr;
+ instr.propertyIndex = prop->index;
+ instr.value = v->value.asNumber();
+ output->addInstruction(instr);
+ }
+ break;
+ case QVariant::Color:
+ {
+ Instruction::StoreColor instr;
+ QColor c = QQmlStringConverters::colorFromString(v->value.asString());
+ instr.propertyIndex = prop->index;
+ instr.value = c.rgba();
+ output->addInstruction(instr);
+ }
+ break;
+#ifndef QT_NO_DATESTRING
+ case QVariant::Date:
+ {
+ Instruction::StoreDate instr;
+ QDate d = QQmlStringConverters::dateFromString(v->value.asString());
+ instr.propertyIndex = prop->index;
+ instr.value = d.toJulianDay();
+ output->addInstruction(instr);
+ }
+ break;
+ case QVariant::Time:
+ {
+ 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));
+ output->addInstruction(instr);
+ }
+ break;
+ case QVariant::DateTime:
+ {
+ Instruction::StoreDateTime instr;
+ QDateTime dateTime = QQmlStringConverters::dateTimeFromString(v->value.asString());
+ 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));
+ output->addInstruction(instr);
+ }
+ break;
+#endif // QT_NO_DATESTRING
+ case QVariant::Point:
+ {
+ Instruction::StorePoint instr;
+ bool ok;
+ QPoint point = QQmlStringConverters::pointFFromString(v->value.asString(), &ok).toPoint();
+ instr.propertyIndex = prop->index;
+ instr.point.xp = point.x();
+ instr.point.yp = point.y();
+ output->addInstruction(instr);
+ }
+ break;
+ case QVariant::PointF:
+ {
+ Instruction::StorePointF instr;
+ bool ok;
+ QPointF point = QQmlStringConverters::pointFFromString(v->value.asString(), &ok);
+ instr.propertyIndex = prop->index;
+ instr.point.xp = point.x();
+ instr.point.yp = point.y();
+ output->addInstruction(instr);
+ }
+ break;
+ case QVariant::Size:
+ {
+ Instruction::StoreSize instr;
+ bool ok;
+ QSize size = QQmlStringConverters::sizeFFromString(v->value.asString(), &ok).toSize();
+ instr.propertyIndex = prop->index;
+ instr.size.wd = size.width();
+ instr.size.ht = size.height();
+ output->addInstruction(instr);
+ }
+ break;
+ case QVariant::SizeF:
+ {
+ Instruction::StoreSizeF instr;
+ bool ok;
+ QSizeF size = QQmlStringConverters::sizeFFromString(v->value.asString(), &ok);
+ instr.propertyIndex = prop->index;
+ instr.size.wd = size.width();
+ instr.size.ht = size.height();
+ output->addInstruction(instr);
+ }
+ break;
+ case QVariant::Rect:
+ {
+ Instruction::StoreRect instr;
+ bool ok;
+ QRect rect = QQmlStringConverters::rectFFromString(v->value.asString(), &ok).toRect();
+ instr.propertyIndex = prop->index;
+ instr.rect.x1 = rect.left();
+ instr.rect.y1 = rect.top();
+ instr.rect.x2 = rect.right();
+ instr.rect.y2 = rect.bottom();
+ output->addInstruction(instr);
+ }
+ break;
+ case QVariant::RectF:
+ {
+ Instruction::StoreRectF instr;
+ bool ok;
+ QRectF rect = QQmlStringConverters::rectFFromString(v->value.asString(), &ok);
+ instr.propertyIndex = prop->index;
+ instr.rect.xp = rect.left();
+ instr.rect.yp = rect.top();
+ instr.rect.w = rect.width();
+ instr.rect.h = rect.height();
+ output->addInstruction(instr);
+ }
+ break;
+ case QVariant::Bool:
+ {
+ Instruction::StoreBool instr;
+ bool b = v->value.asBoolean();
+ instr.propertyIndex = prop->index;
+ instr.value = b;
+ output->addInstruction(instr);
+ }
+ break;
+ case QVariant::Vector3D:
+ {
+ Instruction::StoreVector3D instr;
+ bool ok;
+ QVector3D vector = QQmlStringConverters::vector3DFromString(v->value.asString(), &ok);
+ instr.propertyIndex = prop->index;
+ instr.vector.xp = vector.x();
+ instr.vector.yp = vector.y();
+ instr.vector.zp = vector.z();
+ output->addInstruction(instr);
+ }
+ break;
+ case QVariant::Vector4D:
+ {
+ Instruction::StoreVector4D instr;
+ bool ok;
+ QVector4D vector = QQmlStringConverters::vector4DFromString(v->value.asString(), &ok);
+ instr.propertyIndex = prop->index;
+ instr.vector.xp = vector.x();
+ instr.vector.yp = vector.y();
+ instr.vector.zp = vector.z();
+ instr.vector.wp = vector.w();
+ output->addInstruction(instr);
+ }
+ break;
+ default:
+ {
+ // generate single literal value assignment to a list property if required
+ if (type == qMetaTypeId<QList<qreal> >()) {
+ Instruction::StoreDoubleQList instr;
+ instr.propertyIndex = prop->index;
+ instr.value = v->value.asNumber();
+ output->addInstruction(instr);
+ break;
+ } else if (type == qMetaTypeId<QList<int> >()) {
+ Instruction::StoreIntegerQList instr;
+ instr.propertyIndex = prop->index;
+ instr.value = int(v->value.asNumber());
+ output->addInstruction(instr);
+ break;
+ } else if (type == qMetaTypeId<QList<bool> >()) {
+ Instruction::StoreBoolQList instr;
+ bool b = v->value.asBoolean();
+ instr.propertyIndex = prop->index;
+ instr.value = b;
+ output->addInstruction(instr);
+ break;
+ } else if (type == qMetaTypeId<QList<QUrl> >()) {
+ Instruction::StoreUrlQList instr;
+ QString string = v->value.asString();
+ QUrl u = string.isEmpty() ? QUrl() : output->url.resolved(urlFromUserString(string));
+ instr.propertyIndex = prop->index;
+ instr.value = output->indexForUrl(u);
+ output->addInstruction(instr);
+ break;
+ } else if (type == qMetaTypeId<QList<QString> >()) {
+ Instruction::StoreStringQList instr;
+ instr.propertyIndex = prop->index;
+ instr.value = output->indexForString(v->value.asString());
+ output->addInstruction(instr);
+ break;
+ }
+
+ // otherwise, generate custom type literal assignment
+ Instruction::AssignCustomType instr;
+ instr.propertyIndex = prop->index;
+ instr.primitive = output->indexForString(v->value.asString());
+ instr.type = type;
+ output->addInstruction(instr);
+ }
+ break;
+ }
+}
+
+/*!
+ Resets data by clearing the lists that the QQmlCompiler modifies.
+*/
+void QQmlCompiler::reset(QQmlCompiledData *data)
+{
+ data->types.clear();
+ data->primitives.clear();
+ data->datas.clear();
+ data->bytecode.resize(0);
+}
+
+/*!
+ Compile \a unit, and store the output in \a out. \a engine is the QQmlEngine
+ with which the QQmlCompiledData will be associated.
+
+ Returns true on success, false on failure. On failure, the compile errors
+ are available from errors().
+
+ If the environment variant QML_COMPILER_DUMP is set
+ (eg. QML_COMPILER_DUMP=1) the compiled instructions will be dumped to stderr
+ on a successful compiler.
+*/
+bool QQmlCompiler::compile(QQmlEngine *engine,
+ QQmlTypeData *unit,
+ QQmlCompiledData *out)
+{
+ exceptions.clear();
+
+ Q_ASSERT(out);
+ reset(out);
+
+ QQmlScript::Object *root = unit->parser().tree();
+ Q_ASSERT(root);
+
+ this->engine = engine;
+ this->enginePrivate = QQmlEnginePrivate::get(engine);
+ this->unit = unit;
+ this->unitRoot = root;
+ this->output = out;
+
+ // Compile types
+ const QList<QQmlTypeData::TypeReference> &resolvedTypes = unit->resolvedTypes();
+ QList<QQmlScript::TypeReference *> referencedTypes = unit->parser().referencedTypes();
+
+ for (int ii = 0; ii < resolvedTypes.count(); ++ii) {
+ QQmlCompiledData::TypeReference ref;
+
+ const QQmlTypeData::TypeReference &tref = resolvedTypes.at(ii);
+ QQmlScript::TypeReference *parserRef = referencedTypes.at(ii);
+
+ if (tref.type) {
+ ref.type = tref.type;
+ if (!ref.type->isCreatable()) {
+ QString err = ref.type->noCreationReason();
+ if (err.isEmpty())
+ err = tr( "Element is not creatable.");
+ COMPILE_EXCEPTION(parserRef->refObjects.first(), err);
+ }
+
+ if (ref.type->containsRevisionedAttributes()) {
+ QQmlError cacheError;
+ ref.typePropertyCache = enginePrivate->cache(ref.type, resolvedTypes.at(ii).minorVersion,
+ cacheError);
+ if (!ref.typePropertyCache)
+ COMPILE_EXCEPTION(parserRef->refObjects.first(), cacheError.description());
+ ref.typePropertyCache->addref();
+ }
+
+ } else if (tref.typeData) {
+ ref.component = tref.typeData->compiledData();
+ }
+ ref.className = parserRef->name;
+ out->types << ref;
+ }
+
+ compileTree(root);
+
+ if (!isError()) {
+ if (compilerDump())
+ out->dumpInstructions();
+ if (componentStats)
+ dumpStats();
+ Q_ASSERT(out->rootPropertyCache);
+ } else {
+ reset(out);
+ }
+
+ compileState = 0;
+ output = 0;
+ this->engine = 0;
+ this->enginePrivate = 0;
+ this->unit = 0;
+ this->cachedComponentTypeRef = -1;
+ this->cachedTranslationContextIndex = -1;
+ this->unitRoot = 0;
+
+ return !isError();
+}
+
+void QQmlCompiler::compileTree(QQmlScript::Object *tree)
+{
+ compileState = pool->New<ComponentCompileState>();
+
+ compileState->root = tree;
+ if (componentStats)
+ componentStats->componentStat.lineNumber = tree->location.start.line;
+
+ // We generate the importCache before we build the tree so that
+ // it can be used in the binding compiler. Given we "expect" the
+ // QML compilation to succeed, this isn't a waste.
+ output->importCache = new QQmlTypeNameCache();
+ foreach (const QString &ns, unit->namespaces()) {
+ output->importCache->add(ns);
+ }
+
+ int scriptIndex = 0;
+ foreach (const QQmlTypeData::ScriptReference &script, unit->resolvedScripts()) {
+ QString qualifier = script.qualifier;
+ QString enclosingNamespace;
+
+ const int lastDotIndex = qualifier.lastIndexOf(QLatin1Char('.'));
+ if (lastDotIndex != -1) {
+ enclosingNamespace = qualifier.left(lastDotIndex);
+ qualifier = qualifier.mid(lastDotIndex+1);
+ }
+
+ output->importCache->add(qualifier, scriptIndex++, enclosingNamespace);
+ }
+
+ unit->imports().populateCache(output->importCache, engine);
+
+ if (!buildObject(tree, BindingContext()) || !completeComponentBuild())
+ return;
+
+ Instruction::Init init;
+ init.bindingsSize = compileState->totalBindingsCount;
+ init.parserStatusSize = compileState->parserStatusCount;
+ init.contextCache = genContextCache();
+ init.objectStackSize = compileState->objectDepth.maxDepth();
+ init.listStackSize = compileState->listDepth.maxDepth();
+ if (compileState->compiledBindingData.isEmpty())
+ init.compiledBinding = -1;
+ else
+ init.compiledBinding = output->indexForByteArray(compileState->compiledBindingData);
+ output->addInstruction(init);
+
+ foreach (const QQmlTypeData::ScriptReference &script, unit->resolvedScripts()) {
+ Instruction::StoreImportedScript import;
+ import.value = output->scripts.count();
+
+ QQmlScriptData *scriptData = script.script->scriptData();
+ scriptData->addref();
+ output->scripts << scriptData;
+ output->addInstruction(import);
+ }
+
+ if (!compileState->v8BindingProgram.isEmpty()) {
+ Instruction::InitV8Bindings bindings;
+ int index = output->programs.count();
+
+ typedef QQmlCompiledData::V8Program V8Program;
+ output->programs.append(V8Program(compileState->v8BindingProgram, output));
+
+ bindings.programIndex = index;
+ bindings.line = compileState->v8BindingProgramLine;
+ output->addInstruction(bindings);
+ }
+
+ genObject(tree);
+
+ Instruction::SetDefault def;
+ output->addInstruction(def);
+
+ Instruction::Done done;
+ output->addInstruction(done);
+
+ Q_ASSERT(tree->metatype);
+
+ if (tree->metadata.isEmpty()) {
+ output->root = tree->metatype;
+ } else {
+ static_cast<QMetaObject &>(output->rootData) = *tree->metaObject();
+ output->root = &output->rootData;
+ }
+ if (!tree->metadata.isEmpty())
+ enginePrivate->registerCompositeType(output);
+}
+
+static bool QStringList_contains(const QStringList &list, const QHashedStringRef &string)
+{
+ for (int ii = 0; ii < list.count(); ++ii)
+ if (string == list.at(ii))
+ return true;
+
+ return false;
+}
+
+bool QQmlCompiler::buildObject(QQmlScript::Object *obj, const BindingContext &ctxt)
+{
+ if (componentStats)
+ componentStats->componentStat.objects++;
+
+ Q_ASSERT (obj->type != -1);
+ const QQmlCompiledData::TypeReference &tr = output->types.at(obj->type);
+ obj->metatype = tr.metaObject();
+
+ if (tr.type)
+ obj->typeName = tr.type->qmlTypeName();
+
+ // This object is a "Component" element
+ if (tr.type && obj->metatype == &QQmlComponent::staticMetaObject) {
+ COMPILE_CHECK(buildComponent(obj, ctxt));
+ return true;
+ }
+
+ if (tr.component) {
+ typedef QQmlInstruction I;
+ const I *init = ((const I *)tr.component->bytecode.constData());
+ Q_ASSERT(init && tr.component->instructionType(init) == QQmlInstruction::Init);
+
+ // Adjust stack depths to include nested components
+ compileState->objectDepth.pushPop(init->init.objectStackSize);
+ compileState->listDepth.pushPop(init->init.listStackSize);
+ compileState->parserStatusCount += init->init.parserStatusSize;
+ compileState->totalBindingsCount += init->init.bindingsSize;
+ }
+
+ compileState->objectDepth.push();
+
+ // Object instantiations reset the binding context
+ BindingContext objCtxt(obj);
+
+ // Create the synthesized meta object, ignoring aliases
+ COMPILE_CHECK(checkDynamicMeta(obj));
+ COMPILE_CHECK(mergeDynamicMetaProperties(obj));
+ COMPILE_CHECK(buildDynamicMeta(obj, IgnoreAliases));
+
+ // Find the native type and check for the QQmlParserStatus interface
+ QQmlType *type = toQmlType(obj);
+ Q_ASSERT(type);
+ obj->parserStatusCast = type->parserStatusCast();
+ if (obj->parserStatusCast != -1)
+ compileState->parserStatusCount++;
+
+ // Check if this is a custom parser type. Custom parser types allow
+ // assignments to non-existent properties. These assignments are then
+ // compiled by the type.
+ bool isCustomParser = output->types.at(obj->type).type &&
+ output->types.at(obj->type).type->customParser() != 0;
+ QList<QQmlCustomParserProperty> customProps;
+
+ // Fetch the list of deferred properties
+ QStringList deferredList = deferredProperties(obj);
+
+ // Must do id property first. This is to ensure that the id given to any
+ // id reference created matches the order in which the objects are
+ // instantiated
+ for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) {
+ if (prop->name() == id_string) {
+ COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
+ break;
+ }
+ }
+
+ // Merge
+ Property *defaultProperty = 0;
+ Property *skipProperty = 0;
+ if (obj->defaultProperty) {
+ defaultProperty = obj->defaultProperty;
+
+ Property *explicitProperty = 0;
+
+ const QMetaObject *mo = obj->metatype;
+ int idx = mo->indexOfClassInfo("DefaultProperty");
+ if (idx != -1) {
+ QMetaClassInfo info = mo->classInfo(idx);
+ const char *p = info.value();
+ if (p) {
+ int plen = 0;
+ char ord = 0;
+ while (char c = p[plen++]) { ord |= c; };
+ --plen;
+
+ if (ord & 0x80) {
+ // Utf8 - unoptimal, but seldom hit
+ QString *s = pool->NewString(QString::fromUtf8(p, plen));
+ QHashedStringRef r(*s);
+
+ if (obj->propertiesHashField.test(r.hash())) {
+ for (Property *ep = obj->properties.first(); ep; ep = obj->properties.next(ep)) {
+ if (ep->name() == r) {
+ explicitProperty = ep;
+ break;
+ }
+ }
+ }
+
+ if (!explicitProperty)
+ defaultProperty->setName(r);
+
+ } else {
+ QHashedCStringRef r(p, plen);
+
+ if (obj->propertiesHashField.test(r.hash())) {
+ for (Property *ep = obj->properties.first(); ep; ep = obj->properties.next(ep)) {
+ if (ep->name() == r) {
+ explicitProperty = ep;
+ break;
+ }
+ }
+ }
+
+ if (!explicitProperty) {
+ // Set the default property name
+ QChar *buffer = pool->NewRawArray<QChar>(r.length());
+ r.writeUtf16(buffer);
+ defaultProperty->setName(QHashedStringRef(buffer, r.length(), r.hash()));
+ }
+ }
+ }
+ }
+
+ if (explicitProperty && !explicitProperty->value && !explicitProperty->values.isEmpty()) {
+
+ skipProperty = explicitProperty; // We merge the values into defaultProperty
+
+ // Find the correct insertion point
+ Value *insertPos = 0;
+
+ for (Value *v = defaultProperty->values.first(); v; v = Property::ValueList::next(v)) {
+ if (!(v->location.start < explicitProperty->values.first()->location.start))
+ break;
+ insertPos = v;
+ }
+
+ defaultProperty->values.insertAfter(insertPos, explicitProperty->values);
+ }
+ }
+
+ QQmlCustomParser *cp = 0;
+ if (isCustomParser)
+ cp = output->types.at(obj->type).type->customParser();
+
+ // Build all explicit properties specified
+ for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) {
+
+ if (prop == skipProperty)
+ continue;
+ if (prop->name() == id_string)
+ continue;
+
+ bool canDefer = false;
+ if (isCustomParser) {
+ if (doesPropertyExist(prop, obj) &&
+ (!(cp->flags() & QQmlCustomParser::AcceptsAttachedProperties) ||
+ !isAttachedPropertyName(prop->name()))) {
+ int ids = compileState->ids.count();
+ COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
+ canDefer = ids == compileState->ids.count();
+ } else if (isSignalPropertyName(prop->name()) &&
+ (cp->flags() & QQmlCustomParser::AcceptsSignalHandlers)) {
+ COMPILE_CHECK(buildSignal(prop,obj,objCtxt));
+ } else {
+ customProps << QQmlCustomParserNodePrivate::fromProperty(prop);
+ }
+ } else {
+ if (isSignalPropertyName(prop->name())) {
+ COMPILE_CHECK(buildSignal(prop,obj,objCtxt));
+ } else {
+ int ids = compileState->ids.count();
+ COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
+ canDefer = ids == compileState->ids.count();
+ }
+ }
+
+ if (canDefer && !deferredList.isEmpty() && QStringList_contains(deferredList, prop->name()))
+ prop->isDeferred = true;
+
+ }
+
+ // Build the default property
+ if (defaultProperty) {
+ Property *prop = defaultProperty;
+
+ bool canDefer = false;
+ if (isCustomParser) {
+ if (doesPropertyExist(prop, obj)) {
+ int ids = compileState->ids.count();
+ COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
+ canDefer = ids == compileState->ids.count();
+ } else {
+ customProps << QQmlCustomParserNodePrivate::fromProperty(prop);
+ }
+ } else {
+ int ids = compileState->ids.count();
+ COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
+ canDefer = ids == compileState->ids.count();
+ }
+
+ if (canDefer && !deferredList.isEmpty() && QStringList_contains(deferredList, prop->name()))
+ prop->isDeferred = true;
+ }
+
+ // Compile custom parser parts
+ if (isCustomParser && !customProps.isEmpty()) {
+ cp->clearErrors();
+ cp->compiler = this;
+ cp->object = obj;
+ obj->custom = cp->compile(customProps);
+ cp->compiler = 0;
+ cp->object = 0;
+ foreach (QQmlError err, cp->errors()) {
+ err.setUrl(output->url);
+ exceptions << err;
+ }
+ }
+
+ compileState->objectDepth.pop();
+
+ return true;
+}
+
+void QQmlCompiler::genObject(QQmlScript::Object *obj)
+{
+ QQmlCompiledData::TypeReference &tr = output->types[obj->type];
+ if (tr.type && obj->metatype == &QQmlComponent::staticMetaObject) {
+ genComponent(obj);
+ return;
+ }
+
+ // Create the object
+ if (obj->custom.isEmpty() && output->types.at(obj->type).type &&
+ !output->types.at(obj->type).type->isExtendedType() && obj != compileState->root) {
+
+ Instruction::CreateSimpleObject create;
+ create.create = output->types.at(obj->type).type->createFunction();
+ create.typeSize = output->types.at(obj->type).type->createSize();
+ create.type = obj->type;
+ create.line = obj->location.start.line;
+ create.column = obj->location.start.column;
+ output->addInstruction(create);
+
+ } else {
+
+ if (output->types.at(obj->type).type) {
+ Instruction::CreateCppObject create;
+ create.line = obj->location.start.line;
+ create.column = obj->location.start.column;
+ create.data = -1;
+ if (!obj->custom.isEmpty())
+ create.data = output->indexForByteArray(obj->custom);
+ create.type = obj->type;
+ create.isRoot = (compileState->root == obj);
+ output->addInstruction(create);
+ } else {
+ Instruction::CreateQMLObject create;
+ create.type = obj->type;
+ create.isRoot = (compileState->root == obj);
+
+ if (!obj->bindingBitmask.isEmpty()) {
+ Q_ASSERT(obj->bindingBitmask.size() % 4 == 0);
+ create.bindingBits = output->indexForByteArray(obj->bindingBitmask);
+ } else {
+ create.bindingBits = -1;
+ }
+ output->addInstruction(create);
+
+ Instruction::CompleteQMLObject complete;
+ complete.line = obj->location.start.line;
+ complete.column = obj->location.start.column;
+ complete.isRoot = (compileState->root == obj);
+ output->addInstruction(complete);
+ }
+ }
+
+ // Setup the synthesized meta object if necessary
+ if (!obj->metadata.isEmpty()) {
+ Instruction::StoreMetaObject meta;
+ meta.data = output->indexForByteArray(obj->metadata);
+ meta.aliasData = output->indexForByteArray(obj->synthdata);
+ meta.propertyCache = output->propertyCaches.count();
+
+ QQmlPropertyCache *propertyCache = obj->synthCache;
+ Q_ASSERT(propertyCache);
+ propertyCache->addref();
+
+ // Add flag for alias properties
+ if (!obj->synthdata.isEmpty()) {
+ const QQmlVMEMetaData *vmeMetaData =
+ reinterpret_cast<const QQmlVMEMetaData *>(obj->synthdata.constData());
+ for (int ii = 0; ii < vmeMetaData->aliasCount; ++ii) {
+ int index = obj->metaObject()->propertyOffset() + vmeMetaData->propertyCount + ii;
+ QQmlPropertyData *data = propertyCache->property(index);
+ data->setFlags(data->getFlags() | QQmlPropertyData::IsAlias);
+ }
+ }
+
+ if (obj == unitRoot) {
+ propertyCache->addref();
+ output->rootPropertyCache = propertyCache;
+ }
+
+ output->propertyCaches << propertyCache;
+ output->addInstruction(meta);
+ } else if (obj == unitRoot) {
+ output->rootPropertyCache = tr.createPropertyCache(engine);
+ output->rootPropertyCache->addref();
+ }
+
+ // Set the object id
+ if (!obj->id.isEmpty()) {
+ Instruction::SetId id;
+ id.value = output->indexForString(obj->id);
+ id.index = obj->idIndex;
+ output->addInstruction(id);
+ }
+
+ // Begin the class
+ if (tr.type && obj->parserStatusCast != -1) {
+ Instruction::BeginObject begin;
+ begin.castValue = obj->parserStatusCast;
+ output->addInstruction(begin);
+ }
+
+ genObjectBody(obj);
+}
+
+void QQmlCompiler::genObjectBody(QQmlScript::Object *obj)
+{
+ for (Property *prop = obj->scriptStringProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
+ Q_ASSERT(prop->scriptStringScope != -1);
+ const QString &script = prop->values.first()->value.asScript();
+ Instruction::StoreScriptString ss;
+ ss.propertyIndex = prop->index;
+ ss.value = output->indexForString(script);
+ ss.scope = prop->scriptStringScope;
+// ss.bindingId = rewriteBinding(script, prop->name());
+ ss.bindingId = rewriteBinding(prop->values.first()->value, QString()); // XXX
+ ss.line = prop->location.start.line;
+ ss.column = prop->location.start.column;
+ output->addInstruction(ss);
+ }
+
+ bool seenDefer = false;
+ for (Property *prop = obj->valueProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
+ if (prop->isDeferred) {
+ seenDefer = true;
+ continue;
+ }
+ if (!prop->isAlias)
+ genValueProperty(prop, obj);
+ }
+ if (seenDefer) {
+ Instruction::Defer defer;
+ defer.deferCount = 0;
+ int deferIdx = output->addInstruction(defer);
+ int nextInstructionIndex = output->nextInstructionIndex();
+
+ Instruction::DeferInit dinit;
+ // XXX - these are now massive over allocations
+ dinit.bindingsSize = compileState->totalBindingsCount;
+ dinit.parserStatusSize = compileState->parserStatusCount;
+ dinit.objectStackSize = compileState->objectDepth.maxDepth();
+ dinit.listStackSize = compileState->listDepth.maxDepth();
+ output->addInstruction(dinit);
+
+ for (Property *prop = obj->valueProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
+ if (!prop->isDeferred)
+ continue;
+ genValueProperty(prop, obj);
+ }
+
+ Instruction::Done done;
+ output->addInstruction(done);
+
+ output->instruction(deferIdx)->defer.deferCount = output->nextInstructionIndex() - nextInstructionIndex;
+ }
+
+ for (Property *prop = obj->signalProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
+
+ QQmlScript::Value *v = prop->values.first();
+
+ if (v->type == Value::SignalObject) {
+
+ genObject(v->object);
+
+ Instruction::AssignSignalObject assign;
+ assign.line = v->location.start.line;
+ assign.signal = output->indexForString(prop->name().toString());
+ output->addInstruction(assign);
+
+ } else if (v->type == Value::SignalExpression) {
+
+ Instruction::StoreSignal store;
+ store.signalIndex = prop->index;
+ const QString &rewrite = rewriteSignalHandler(v->value, prop->name().toString());
+ store.value = output->indexForByteArray(rewrite.toUtf8());
+ store.context = v->signalExpressionContextStack;
+ store.line = v->location.start.line;
+ store.column = v->location.start.column;
+ output->addInstruction(store);
+
+ }
+
+ }
+
+ for (Property *prop = obj->attachedProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
+ Instruction::FetchAttached fetch;
+ fetch.id = prop->index;
+ fetch.line = prop->location.start.line;
+ output->addInstruction(fetch);
+
+ genObjectBody(prop->value);
+
+ Instruction::PopFetchedObject pop;
+ output->addInstruction(pop);
+ }
+
+ for (Property *prop = obj->groupedProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
+ Instruction::FetchObject fetch;
+ fetch.property = prop->index;
+ fetch.line = prop->location.start.line;
+ output->addInstruction(fetch);
+
+ if (!prop->value->metadata.isEmpty()) {
+ Instruction::StoreMetaObject meta;
+ meta.data = output->indexForByteArray(prop->value->metadata);
+ meta.aliasData = output->indexForByteArray(prop->value->synthdata);
+ meta.propertyCache = -1;
+ output->addInstruction(meta);
+ }
+
+ genObjectBody(prop->value);
+
+ Instruction::PopFetchedObject pop;
+ output->addInstruction(pop);
+ }
+
+ for (Property *prop = obj->valueTypeProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
+ if (!prop->isAlias)
+ genValueTypeProperty(obj, prop);
+ }
+
+ for (Property *prop = obj->valueProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
+ if (prop->isDeferred)
+ continue;
+ if (prop->isAlias)
+ genValueProperty(prop, obj);
+ }
+
+ for (Property *prop = obj->valueTypeProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
+ if (prop->isAlias)
+ genValueTypeProperty(obj, prop);
+ }
+}
+
+void QQmlCompiler::genValueTypeProperty(QQmlScript::Object *obj,QQmlScript::Property *prop)
+{
+ Instruction::FetchValueType fetch;
+ fetch.property = prop->index;
+ fetch.type = prop->type;
+ fetch.bindingSkipList = 0;
+
+ if (obj->type == -1 || output->types.at(obj->type).component) {
+ // We only have to do this if this is a composite type. If it is a builtin
+ // type it can't possibly already have bindings that need to be cleared.
+ for (Property *vprop = prop->value->valueProperties.first(); vprop; vprop = Object::PropertyList::next(vprop)) {
+ if (!vprop->values.isEmpty()) {
+ Q_ASSERT(vprop->index >= 0 && vprop->index < 32);
+ fetch.bindingSkipList |= (1 << vprop->index);
+ }
+ }
+ }
+
+ output->addInstruction(fetch);
+
+ for (Property *vprop = prop->value->valueProperties.first(); vprop; vprop = Object::PropertyList::next(vprop)) {
+ genPropertyAssignment(vprop, prop->value, prop);
+ }
+
+ Instruction::PopValueType pop;
+ pop.property = prop->index;
+ pop.type = prop->type;
+ pop.bindingSkipList = 0;
+ output->addInstruction(pop);
+}
+
+void QQmlCompiler::genComponent(QQmlScript::Object *obj)
+{
+ QQmlScript::Object *root = obj->defaultProperty->values.first()->object;
+ Q_ASSERT(root);
+
+ Instruction::CreateComponent create;
+ create.line = root->location.start.line;
+ create.column = root->location.start.column;
+ create.endLine = root->location.end.line;
+ create.isRoot = (compileState->root == obj);
+ int createInstruction = output->addInstruction(create);
+ int nextInstructionIndex = output->nextInstructionIndex();
+
+ ComponentCompileState *oldCompileState = compileState;
+ compileState = componentState(root);
+
+ Instruction::Init init;
+ init.bindingsSize = compileState->totalBindingsCount;
+ init.parserStatusSize = compileState->parserStatusCount;
+ init.contextCache = genContextCache();
+ init.objectStackSize = compileState->objectDepth.maxDepth();
+ init.listStackSize = compileState->listDepth.maxDepth();
+ if (compileState->compiledBindingData.isEmpty())
+ init.compiledBinding = -1;
+ else
+ init.compiledBinding = output->indexForByteArray(compileState->compiledBindingData);
+ output->addInstruction(init);
+
+ if (!compileState->v8BindingProgram.isEmpty()) {
+ Instruction::InitV8Bindings bindings;
+ int index = output->programs.count();
+
+ typedef QQmlCompiledData::V8Program V8Program;
+ output->programs.append(V8Program(compileState->v8BindingProgram, output));
+
+ bindings.programIndex = index;
+ bindings.line = compileState->v8BindingProgramLine;
+ output->addInstruction(bindings);
+ }
+
+ genObject(root);
+
+ Instruction::SetDefault def;
+ output->addInstruction(def);
+
+ Instruction::Done done;
+ output->addInstruction(done);
+
+ output->instruction(createInstruction)->createComponent.count =
+ output->nextInstructionIndex() - nextInstructionIndex;
+
+ compileState = oldCompileState;
+
+ if (!obj->id.isEmpty()) {
+ Instruction::SetId id;
+ id.value = output->indexForString(obj->id);
+ id.index = obj->idIndex;
+ output->addInstruction(id);
+ }
+
+ if (obj == unitRoot) {
+ output->rootPropertyCache = output->types[obj->type].createPropertyCache(engine);
+ output->rootPropertyCache->addref();
+ }
+}
+
+bool QQmlCompiler::buildComponent(QQmlScript::Object *obj,
+ const BindingContext &ctxt)
+{
+ // The special "Component" element can only have the id property and a
+ // default property, that actually defines the component's tree
+
+ compileState->objectDepth.push();
+
+ // Find, check and set the "id" property (if any)
+ Property *idProp = 0;
+ if (obj->properties.isMany() ||
+ (obj->properties.isOne() && obj->properties.first()->name() != id_string))
+ COMPILE_EXCEPTION(obj->properties.first(), tr("Component elements may not contain properties other than id"));
+
+ if (!obj->properties.isEmpty())
+ idProp = obj->properties.first();
+
+ if (idProp) {
+ if (idProp->value || idProp->values.isMany() || idProp->values.first()->object)
+ COMPILE_EXCEPTION(idProp, tr("Invalid component id specification"));
+ COMPILE_CHECK(checkValidId(idProp->values.first(), idProp->values.first()->primitive()))
+
+ QString idVal = idProp->values.first()->primitive();
+
+ if (compileState->ids.value(idVal))
+ COMPILE_EXCEPTION(idProp, tr("id is not unique"));
+
+ obj->id = idVal;
+ addId(idVal, obj);
+ }
+
+ // Check the Component tree is well formed
+ if (obj->defaultProperty &&
+ (obj->defaultProperty->value || obj->defaultProperty->values.isMany() ||
+ (obj->defaultProperty->values.isOne() && !obj->defaultProperty->values.first()->object)))
+ COMPILE_EXCEPTION(obj, tr("Invalid component body specification"));
+
+ if (!obj->dynamicProperties.isEmpty())
+ COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new properties."));
+ if (!obj->dynamicSignals.isEmpty())
+ COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new signals."));
+ if (!obj->dynamicSlots.isEmpty())
+ COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new functions."));
+
+ QQmlScript::Object *root = 0;
+ if (obj->defaultProperty && !obj->defaultProperty->values.isEmpty())
+ root = obj->defaultProperty->values.first()->object;
+
+ if (!root)
+ COMPILE_EXCEPTION(obj, tr("Cannot create empty component specification"));
+
+ // Build the component tree
+ COMPILE_CHECK(buildComponentFromRoot(root, ctxt));
+
+ compileState->objectDepth.pop();
+
+ return true;
+}
+
+bool QQmlCompiler::buildComponentFromRoot(QQmlScript::Object *obj,
+ const BindingContext &ctxt)
+{
+ ComponentCompileState *oldComponentCompileState = compileState;
+ compileState = pool->New<ComponentCompileState>();
+ compileState->root = obj;
+ compileState->nested = true;
+
+ if (componentStats) {
+ ComponentStat oldComponentStat = componentStats->componentStat;
+
+ componentStats->componentStat = ComponentStat();
+ componentStats->componentStat.lineNumber = obj->location.start.line;
+
+ if (obj)
+ COMPILE_CHECK(buildObject(obj, ctxt));
+
+ COMPILE_CHECK(completeComponentBuild());
+
+ componentStats->componentStat = oldComponentStat;
+ } else {
+ if (obj)
+ COMPILE_CHECK(buildObject(obj, ctxt));
+
+ COMPILE_CHECK(completeComponentBuild());
+ }
+
+ compileState = oldComponentCompileState;
+
+ return true;
+}
+
+
+// Build a sub-object. A sub-object is one that was not created directly by
+// QML - such as a grouped property object, or an attached object. Sub-object's
+// can't have an id, involve a custom parser, have attached properties etc.
+bool QQmlCompiler::buildSubObject(QQmlScript::Object *obj, const BindingContext &ctxt)
+{
+ Q_ASSERT(obj->metatype);
+ Q_ASSERT(!obj->defaultProperty);
+ Q_ASSERT(ctxt.isSubContext()); // sub-objects must always be in a binding
+ // sub-context
+
+ for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) {
+ if (isSignalPropertyName(prop->name())) {
+ COMPILE_CHECK(buildSignal(prop, obj, ctxt));
+ } else {
+ COMPILE_CHECK(buildProperty(prop, obj, ctxt));
+ }
+ }
+
+ return true;
+}
+
+int QQmlCompiler::componentTypeRef()
+{
+ if (cachedComponentTypeRef == -1) {
+ QQmlType *t = QQmlMetaType::qmlType(Component_import_string,1,0);
+ for (int ii = output->types.count() - 1; ii >= 0; --ii) {
+ if (output->types.at(ii).type == t) {
+ cachedComponentTypeRef = ii;
+ return ii;
+ }
+ }
+ QQmlCompiledData::TypeReference ref;
+ ref.className = Component_string;
+ ref.type = t;
+ output->types << ref;
+ cachedComponentTypeRef = output->types.count() - 1;
+ }
+ return cachedComponentTypeRef;
+}
+
+int QQmlCompiler::translationContextIndex()
+{
+ if (cachedTranslationContextIndex == -1) {
+ // This code must match that in the qsTr() implementation
+ const QString &path = output->name;
+ int lastSlash = path.lastIndexOf(QLatin1Char('/'));
+ QString context = (lastSlash > -1) ? path.mid(lastSlash + 1, path.length()-lastSlash-5) :
+ QString();
+ QByteArray contextUtf8 = context.toUtf8();
+ cachedTranslationContextIndex = output->indexForByteArray(contextUtf8);
+ }
+ return cachedTranslationContextIndex;
+}
+
+bool QQmlCompiler::buildSignal(QQmlScript::Property *prop, QQmlScript::Object *obj,
+ const BindingContext &ctxt)
+{
+ Q_ASSERT(obj->metaObject());
+
+ const QHashedStringRef &propName = prop->name();
+
+ Q_ASSERT(propName.startsWith(on_string));
+ QString name = propName.mid(2, -1).toString();
+
+ // Note that the property name could start with any alpha or '_' or '$' character,
+ // so we need to do the lower-casing of the first alpha character.
+ for (int firstAlphaIndex = 0; firstAlphaIndex < name.size(); ++firstAlphaIndex) {
+ if (name.at(firstAlphaIndex).isUpper()) {
+ name[firstAlphaIndex] = name.at(firstAlphaIndex).toLower();
+ break;
+ }
+ }
+
+ bool notInRevision = false;
+
+ QQmlPropertyData *sig = signal(obj, QStringRef(&name), &notInRevision);
+
+ if (sig == 0) {
+
+ if (notInRevision && 0 == property(obj, propName, 0)) {
+ Q_ASSERT(obj->type != -1);
+ const QList<QQmlTypeData::TypeReference> &resolvedTypes = unit->resolvedTypes();
+ const QQmlTypeData::TypeReference &type = resolvedTypes.at(obj->type);
+ if (type.type) {
+ COMPILE_EXCEPTION(prop, tr("\"%1.%2\" is not available in %3 %4.%5.").arg(elementName(obj)).arg(prop->name().toString()).arg(type.type->module()).arg(type.majorVersion).arg(type.minorVersion));
+ } else {
+ COMPILE_EXCEPTION(prop, tr("\"%1.%2\" is not available due to component versioning.").arg(elementName(obj)).arg(prop->name().toString()));
+ }
+ }
+
+ // If the "on<Signal>" name doesn't resolve into a signal, try it as a
+ // property.
+ COMPILE_CHECK(buildProperty(prop, obj, ctxt));
+
+ } else {
+
+ if (prop->value || !prop->values.isOne())
+ COMPILE_EXCEPTION(prop, tr("Incorrectly specified signal assignment"));
+
+ prop->index = sig->coreIndex;
+ prop->core = *sig;
+
+ obj->addSignalProperty(prop);
+
+ if (prop->values.first()->object) {
+ COMPILE_CHECK(buildObject(prop->values.first()->object, ctxt));
+ prop->values.first()->type = Value::SignalObject;
+ } else {
+ prop->values.first()->type = Value::SignalExpression;
+
+ if (!prop->values.first()->value.isScript())
+ COMPILE_EXCEPTION(prop, tr("Cannot assign a value to a signal (expecting a script to be run)"));
+
+ QString script = prop->values.first()->value.asScript().trimmed();
+ if (script.isEmpty())
+ COMPILE_EXCEPTION(prop, tr("Empty signal assignment"));
+
+ prop->values.first()->signalExpressionContextStack = ctxt.stack;
+ }
+ }
+
+ return true;
+}
+
+
+/*!
+ Returns true if (value) property \a prop exists on obj, false otherwise.
+*/
+bool QQmlCompiler::doesPropertyExist(QQmlScript::Property *prop,
+ QQmlScript::Object *obj)
+{
+ if (prop->name().isEmpty())
+ return false;
+ if(isAttachedPropertyName(prop->name()) || prop->name() == id_string)
+ return true;
+
+ return property(obj, prop->name()) != 0;
+}
+
+bool QQmlCompiler::buildProperty(QQmlScript::Property *prop,
+ QQmlScript::Object *obj,
+ const BindingContext &ctxt)
+{
+ if (prop->isEmpty())
+ COMPILE_EXCEPTION(prop, tr("Empty property assignment"));
+
+ const QMetaObject *metaObject = obj->metaObject();
+ Q_ASSERT(metaObject);
+
+ if (isAttachedPropertyName(prop->name())) {
+ // Setup attached property data
+
+ if (ctxt.isSubContext()) {
+ // Attached properties cannot be used on sub-objects. Sub-objects
+ // always exist in a binding sub-context, which is what we test
+ // for here.
+ COMPILE_EXCEPTION(prop, tr("Attached properties cannot be used here"));
+ }
+
+ QQmlType *type = 0;
+ QQmlImportedNamespace *typeNamespace = 0;
+ unit->imports().resolveType(prop->name().toString(), &type, 0, 0, 0, &typeNamespace);
+
+ if (typeNamespace) {
+ COMPILE_CHECK(buildPropertyInNamespace(typeNamespace, prop, obj,
+ ctxt));
+ return true;
+ } else if (!type || !type->attachedPropertiesType()) {
+ COMPILE_EXCEPTION(prop, tr("Non-existent attached object"));
+ }
+
+ if (!prop->value)
+ COMPILE_EXCEPTION(prop, tr("Invalid attached object assignment"));
+
+ Q_ASSERT(type->attachedPropertiesFunction());
+ prop->index = type->attachedPropertiesId();
+ prop->value->metatype = type->attachedPropertiesType();
+ } else {
+ // Setup regular property data
+ bool notInRevision = false;
+ QQmlPropertyData *d =
+ prop->name().isEmpty()?0:property(obj, prop->name(), &notInRevision);
+
+ if (d == 0 && notInRevision) {
+ const QList<QQmlTypeData::TypeReference> &resolvedTypes = unit->resolvedTypes();
+ const QQmlTypeData::TypeReference &type = resolvedTypes.at(obj->type);
+ if (type.type) {
+ COMPILE_EXCEPTION(prop, tr("\"%1.%2\" is not available in %3 %4.%5.").arg(elementName(obj)).arg(prop->name().toString()).arg(type.type->module()).arg(type.majorVersion).arg(type.minorVersion));
+ } else {
+ COMPILE_EXCEPTION(prop, tr("\"%1.%2\" is not available due to component versioning.").arg(elementName(obj)).arg(prop->name().toString()));
+ }
+ } else if (d) {
+ prop->index = d->coreIndex;
+ prop->core = *d;
+ } else if (prop->isDefault) {
+ QMetaProperty p = QQmlMetaType::defaultProperty(metaObject);
+ QQmlPropertyData defaultPropertyData;
+ defaultPropertyData.load(p, engine);
+ if (p.name())
+ prop->setName(QLatin1String(p.name()));
+ prop->core = defaultPropertyData;
+ prop->index = prop->core.coreIndex;
+ }
+
+ // We can't error here as the "id" property does not require a
+ // successful index resolution
+ if (prop->index != -1)
+ prop->type = prop->core.propType;
+
+ // Check if this is an alias
+ if (prop->index != -1 &&
+ prop->parent &&
+ prop->parent->type != -1 &&
+ output->types.at(prop->parent->type).component) {
+
+ QQmlPropertyCache *cache = output->types.at(prop->parent->type).component->rootPropertyCache;
+ if (cache && cache->property(prop->index) && cache->property(prop->index)->isAlias())
+ prop->isAlias = true;
+ }
+
+ if (prop->index != -1 && !prop->values.isEmpty())
+ prop->parent->setBindingBit(prop->index);
+ }
+
+ if (!prop->isDefault && prop->name() == id_string && !ctxt.isSubContext()) {
+
+ // The magic "id" behavior doesn't apply when "id" is resolved as a
+ // default property or to sub-objects (which are always in binding
+ // sub-contexts)
+ COMPILE_CHECK(buildIdProperty(prop, obj));
+ if (prop->type == QVariant::String &&
+ prop->values.first()->value.isString())
+ COMPILE_CHECK(buildPropertyAssignment(prop, obj, ctxt));
+
+ } else if (isAttachedPropertyName(prop->name())) {
+
+ COMPILE_CHECK(buildAttachedProperty(prop, obj, ctxt));
+
+ } else if (prop->index == -1) {
+
+ if (prop->isDefault) {
+ COMPILE_EXCEPTION(prop->values.first(), tr("Cannot assign to non-existent default property"));
+ } else {
+ COMPILE_EXCEPTION(prop, tr("Cannot assign to non-existent property \"%1\"").arg(prop->name().toString()));
+ }
+
+ } else if (prop->value) {
+
+ COMPILE_CHECK(buildGroupedProperty(prop, obj, ctxt));
+
+ } else if (prop->core.isQList()) {
+
+ COMPILE_CHECK(buildListProperty(prop, obj, ctxt));
+
+ } else if (prop->type == qMetaTypeId<QQmlScriptString>()) {
+
+ COMPILE_CHECK(buildScriptStringProperty(prop, obj, ctxt));
+
+ } else {
+
+ COMPILE_CHECK(buildPropertyAssignment(prop, obj, ctxt));
+
+ }
+
+ return true;
+}
+
+bool QQmlCompiler::buildPropertyInNamespace(QQmlImportedNamespace *ns,
+ QQmlScript::Property *nsProp,
+ QQmlScript::Object *obj,
+ const BindingContext &ctxt)
+{
+ if (!nsProp->value)
+ COMPILE_EXCEPTION(nsProp, tr("Invalid use of namespace"));
+
+ for (Property *prop = nsProp->value->properties.first(); prop; prop = nsProp->value->properties.next(prop)) {
+
+ if (!isAttachedPropertyName(prop->name()))
+ COMPILE_EXCEPTION(prop, tr("Not an attached property name"));
+
+ // Setup attached property data
+
+ QQmlType *type = 0;
+ unit->imports().resolveType(ns, prop->name().toString(), &type, 0, 0, 0);
+
+ if (!type || !type->attachedPropertiesType())
+ COMPILE_EXCEPTION(prop, tr("Non-existent attached object"));
+
+ if (!prop->value)
+ COMPILE_EXCEPTION(prop, tr("Invalid attached object assignment"));
+
+ Q_ASSERT(type->attachedPropertiesFunction());
+ prop->index = type->index();
+ prop->value->metatype = type->attachedPropertiesType();
+
+ COMPILE_CHECK(buildAttachedProperty(prop, obj, ctxt));
+ }
+
+ return true;
+}
+
+void QQmlCompiler::genValueProperty(QQmlScript::Property *prop,
+ QQmlScript::Object *obj)
+{
+ if (prop->core.isQList()) {
+ genListProperty(prop, obj);
+ } else {
+ genPropertyAssignment(prop, obj);
+ }
+}
+
+void QQmlCompiler::genListProperty(QQmlScript::Property *prop,
+ QQmlScript::Object *obj)
+{
+ int listType = enginePrivate->listType(prop->type);
+
+ Instruction::FetchQList fetch;
+ fetch.property = prop->index;
+ bool listTypeIsInterface = QQmlMetaType::isInterface(listType);
+ fetch.type = listType;
+ output->addInstruction(fetch);
+
+ for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
+
+ if (v->type == Value::CreatedObject) {
+
+ genObject(v->object);
+ if (listTypeIsInterface) {
+ Instruction::AssignObjectList assign;
+ assign.line = prop->location.start.line;
+ output->addInstruction(assign);
+ } else {
+ Instruction::StoreObjectQList store;
+ output->addInstruction(store);
+ }
+
+ } else if (v->type == Value::PropertyBinding) {
+
+ genBindingAssignment(v, prop, obj);
+
+ }
+
+ }
+
+ Instruction::PopQList pop;
+ output->addInstruction(pop);
+}
+
+void QQmlCompiler::genPropertyAssignment(QQmlScript::Property *prop,
+ QQmlScript::Object *obj,
+ QQmlScript::Property *valueTypeProperty)
+{
+ for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
+
+ Q_ASSERT(v->type == Value::CreatedObject ||
+ v->type == Value::PropertyBinding ||
+ v->type == Value::Literal);
+
+ if (v->type == Value::CreatedObject) {
+
+ genObject(v->object);
+
+ if (QQmlMetaType::isInterface(prop->type)) {
+
+ Instruction::StoreInterface store;
+ store.line = v->object->location.start.line;
+ store.propertyIndex = prop->index;
+ output->addInstruction(store);
+
+ } else if (prop->type == QMetaType::QVariant) {
+
+ if (prop->core.isVMEProperty()) {
+ Instruction::StoreVarObject store;
+ store.line = v->object->location.start.line;
+ store.propertyIndex = prop->index;
+ output->addInstruction(store);
+ } else {
+ Instruction::StoreVariantObject store;
+ store.line = v->object->location.start.line;
+ store.propertyIndex = prop->index;
+ output->addInstruction(store);
+ }
+
+
+ } else {
+
+ Instruction::StoreObject store;
+ store.line = v->object->location.start.line;
+ store.propertyIndex = prop->index;
+ output->addInstruction(store);
+
+ }
+ } else if (v->type == Value::PropertyBinding) {
+
+ genBindingAssignment(v, prop, obj, valueTypeProperty);
+
+ } else if (v->type == Value::Literal) {
+
+ genLiteralAssignment(prop, v);
+
+ }
+
+ }
+
+ for (Value *v = prop->onValues.first(); v; v = Property::ValueList::next(v)) {
+
+ Q_ASSERT(v->type == Value::ValueSource ||
+ v->type == Value::ValueInterceptor);
+
+ if (v->type == Value::ValueSource) {
+ genObject(v->object);
+
+ Instruction::StoreValueSource store;
+ if (valueTypeProperty) {
+ store.property = genValueTypeData(prop, valueTypeProperty);
+ store.owner = 1;
+ } else {
+ store.property = prop->core;
+ store.owner = 0;
+ }
+ QQmlType *valueType = toQmlType(v->object);
+ store.castValue = valueType->propertyValueSourceCast();
+ output->addInstruction(store);
+
+ } else if (v->type == Value::ValueInterceptor) {
+ genObject(v->object);
+
+ Instruction::StoreValueInterceptor store;
+ if (valueTypeProperty) {
+ store.property = genValueTypeData(prop, valueTypeProperty);
+ store.owner = 1;
+ } else {
+ store.property = prop->core;
+ store.owner = 0;
+ }
+ QQmlType *valueType = toQmlType(v->object);
+ store.castValue = valueType->propertyValueInterceptorCast();
+ output->addInstruction(store);
+ }
+
+ }
+}
+
+bool QQmlCompiler::buildIdProperty(QQmlScript::Property *prop,
+ QQmlScript::Object *obj)
+{
+ if (prop->value ||
+ prop->values.isMany() ||
+ prop->values.first()->object)
+ COMPILE_EXCEPTION(prop, tr("Invalid use of id property"));
+
+ QQmlScript::Value *idValue = prop->values.first();
+ QString val = idValue->primitive();
+
+ COMPILE_CHECK(checkValidId(idValue, val));
+
+ if (compileState->ids.value(val))
+ COMPILE_EXCEPTION(prop, tr("id is not unique"));
+
+ prop->values.first()->type = Value::Id;
+
+ obj->id = val;
+ addId(val, obj);
+
+ return true;
+}
+
+void QQmlCompiler::addId(const QString &id, QQmlScript::Object *obj)
+{
+ Q_UNUSED(id);
+ Q_ASSERT(!compileState->ids.value(id));
+ Q_ASSERT(obj->id == id);
+ obj->idIndex = compileState->ids.count();
+ compileState->ids.append(obj);
+}
+
+void QQmlCompiler::addBindingReference(JSBindingReference *ref)
+{
+ Q_ASSERT(ref->value && !ref->value->bindingReference);
+ ref->value->bindingReference = ref;
+ compileState->totalBindingsCount++;
+ compileState->bindings.prepend(ref);
+}
+
+void QQmlCompiler::saveComponentState()
+{
+ Q_ASSERT(compileState->root);
+ Q_ASSERT(compileState->root->componentCompileState == 0);
+
+ compileState->root->componentCompileState = compileState;
+
+ if (componentStats)
+ componentStats->savedComponentStats.append(componentStats->componentStat);
+}
+
+QQmlCompilerTypes::ComponentCompileState *
+QQmlCompiler::componentState(QQmlScript::Object *obj)
+{
+ Q_ASSERT(obj->componentCompileState);
+ return obj->componentCompileState;
+}
+
+// Build attached property object. In this example,
+// Text {
+// GridView.row: 10
+// }
+// GridView is an attached property object.
+bool QQmlCompiler::buildAttachedProperty(QQmlScript::Property *prop,
+ QQmlScript::Object *obj,
+ const BindingContext &ctxt)
+{
+ Q_ASSERT(prop->value);
+ Q_ASSERT(prop->index != -1); // This is set in buildProperty()
+
+ compileState->objectDepth.push();
+
+ obj->addAttachedProperty(prop);
+
+ COMPILE_CHECK(buildSubObject(prop->value, ctxt.incr()));
+
+ compileState->objectDepth.pop();
+
+ return true;
+}
+
+
+// Build "grouped" properties. In this example:
+// Text {
+// font.pointSize: 12
+// font.family: "Helvetica"
+// }
+// font is a nested property. pointSize and family are not.
+bool QQmlCompiler::buildGroupedProperty(QQmlScript::Property *prop,
+ QQmlScript::Object *obj,
+ const BindingContext &ctxt)
+{
+ Q_ASSERT(prop->type != 0);
+ Q_ASSERT(prop->index != -1);
+
+ if (QQmlValueTypeFactory::isValueType(prop->type)) {
+ if (prop->type >= 0 && enginePrivate->valueTypes[prop->type]) {
+
+ if (!prop->values.isEmpty()) {
+ if (prop->values.first()->location < prop->value->location) {
+ COMPILE_EXCEPTION(prop->value, tr( "Property has already been assigned a value"));
+ } else {
+ COMPILE_EXCEPTION(prop->values.first(), tr( "Property has already been assigned a value"));
+ }
+ }
+
+ if (!prop->core.isWritable() && !prop->isReadOnlyDeclaration) {
+ COMPILE_EXCEPTION(prop, tr( "Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
+ }
+
+
+ if (prop->isAlias) {
+ for (Property *vtProp = prop->value->properties.first(); vtProp; vtProp = prop->value->properties.next(vtProp)) {
+ vtProp->isAlias = true;
+ }
+ }
+
+ COMPILE_CHECK(buildValueTypeProperty(enginePrivate->valueTypes[prop->type],
+ prop->value, obj, ctxt.incr()));
+ obj->addValueTypeProperty(prop);
+ } else {
+ COMPILE_EXCEPTION(prop, tr("Invalid grouped property access"));
+ }
+
+ } else {
+ // Load the nested property's meta type
+ prop->value->metatype = enginePrivate->metaObjectForType(prop->type);
+ if (!prop->value->metatype)
+ COMPILE_EXCEPTION(prop, tr("Invalid grouped property access"));
+
+ if (!prop->values.isEmpty())
+ COMPILE_EXCEPTION(prop->values.first(), tr( "Cannot assign a value directly to a grouped property"));
+
+ obj->addGroupedProperty(prop);
+
+ compileState->objectDepth.push();
+
+ COMPILE_CHECK(buildSubObject(prop->value, ctxt.incr()));
+
+ compileState->objectDepth.pop();
+ }
+
+ return true;
+}
+
+bool QQmlCompiler::buildValueTypeProperty(QObject *type,
+ QQmlScript::Object *obj,
+ QQmlScript::Object *baseObj,
+ const BindingContext &ctxt)
+{
+ compileState->objectDepth.push();
+
+ if (obj->defaultProperty)
+ COMPILE_EXCEPTION(obj, tr("Invalid property use"));
+ obj->metatype = type->metaObject();
+
+ for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) {
+
+ QQmlPropertyData *d = property(obj, prop->name());
+ if (d == 0)
+ COMPILE_EXCEPTION(prop, tr("Cannot assign to non-existent property \"%1\"").arg(prop->name().toString()));
+
+ prop->index = d->coreIndex;
+ prop->type = d->propType;
+ prop->core = *d;
+ prop->isValueTypeSubProperty = true;
+
+ if (prop->value)
+ COMPILE_EXCEPTION(prop, tr("Property assignment expected"));
+
+ if (prop->values.isMany()) {
+ COMPILE_EXCEPTION(prop, tr("Single property assignment expected"));
+ } else if (!prop->values.isEmpty()) {
+ QQmlScript::Value *value = prop->values.first();
+
+ if (value->object) {
+ COMPILE_EXCEPTION(prop, tr("Unexpected object assignment"));
+ } else if (value->value.isScript()) {
+ // ### Check for writability
+
+ //optimization for <Type>.<EnumValue> enum assignments
+ bool isEnumAssignment = false;
+
+ if (prop->core.isEnum())
+ COMPILE_CHECK(testQualifiedEnumAssignment(prop, obj, value, &isEnumAssignment));
+
+ if (isEnumAssignment) {
+ value->type = Value::Literal;
+ } else {
+ JSBindingReference *reference = pool->New<JSBindingReference>();
+ reference->expression = value->value;
+ reference->property = prop;
+ reference->value = value;
+ reference->bindingContext = ctxt;
+ reference->bindingContext.owner++;
+ addBindingReference(reference);
+ value->type = Value::PropertyBinding;
+ }
+ } else {
+ COMPILE_CHECK(testLiteralAssignment(prop, value));
+ value->type = Value::Literal;
+ }
+ }
+
+ for (Value *v = prop->onValues.first(); v; v = Property::ValueList::next(v)) {
+ Q_ASSERT(v->object);
+
+ COMPILE_CHECK(buildPropertyOnAssignment(prop, obj, baseObj, v, ctxt));
+ }
+
+ obj->addValueProperty(prop);
+ }
+
+ compileState->objectDepth.pop();
+
+ return true;
+}
+
+// Build assignments to QML lists. QML lists are properties of type
+// QQmlListProperty<T>. List properties can accept a list of
+// objects, or a single binding.
+bool QQmlCompiler::buildListProperty(QQmlScript::Property *prop,
+ QQmlScript::Object *obj,
+ const BindingContext &ctxt)
+{
+ Q_ASSERT(prop->core.isQList());
+
+ compileState->listDepth.push();
+
+ int t = prop->type;
+
+ obj->addValueProperty(prop);
+
+ int listType = enginePrivate->listType(t);
+ bool listTypeIsInterface = QQmlMetaType::isInterface(listType);
+
+ bool assignedBinding = false;
+ for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
+ if (v->object) {
+ v->type = Value::CreatedObject;
+ COMPILE_CHECK(buildObject(v->object, ctxt));
+
+ // We check object coercian here. We check interface assignment
+ // at runtime.
+ if (!listTypeIsInterface) {
+ if (!canCoerce(listType, v->object)) {
+ COMPILE_EXCEPTION(v, tr("Cannot assign object to list"));
+ }
+ }
+
+ } else if (v->value.isScript()) {
+ if (assignedBinding)
+ COMPILE_EXCEPTION(v, tr("Can only assign one binding to lists"));
+
+ assignedBinding = true;
+ COMPILE_CHECK(buildBinding(v, prop, ctxt));
+ v->type = Value::PropertyBinding;
+ } else {
+ COMPILE_EXCEPTION(v, tr("Cannot assign primitives to lists"));
+ }
+ }
+
+ compileState->listDepth.pop();
+
+ return true;
+}
+
+// Compiles an assignment to a QQmlScriptString property
+bool QQmlCompiler::buildScriptStringProperty(QQmlScript::Property *prop,
+ QQmlScript::Object *obj,
+ const BindingContext &ctxt)
+{
+ if (prop->values.isMany())
+ COMPILE_EXCEPTION(prop->values.first()->nextValue, tr( "Cannot assign multiple values to a script property"));
+
+ if (prop->values.first()->object)
+ COMPILE_EXCEPTION(prop->values.first(), tr( "Invalid property assignment: script expected"));
+
+ prop->scriptStringScope = ctxt.stack;
+ obj->addScriptStringProperty(prop);
+
+ return true;
+}
+
+// Compile regular property assignments of the form "property: <value>"
+bool QQmlCompiler::buildPropertyAssignment(QQmlScript::Property *prop,
+ QQmlScript::Object *obj,
+ const BindingContext &ctxt)
+{
+ obj->addValueProperty(prop);
+
+ if (prop->values.isMany())
+ COMPILE_EXCEPTION(prop->values.first(), tr( "Cannot assign multiple values to a singular property") );
+
+ for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
+ if (v->object) {
+
+ COMPILE_CHECK(buildPropertyObjectAssignment(prop, obj, v, ctxt));
+
+ } else {
+
+ COMPILE_CHECK(buildPropertyLiteralAssignment(prop, obj, v, ctxt));
+
+ }
+ }
+
+ for (Value *v = prop->onValues.first(); v; v = Property::ValueList::next(v)) {
+ Q_ASSERT(v->object);
+ COMPILE_CHECK(buildPropertyOnAssignment(prop, obj, obj, v, ctxt));
+ }
+
+ return true;
+}
+
+// Compile assigning a single object instance to a regular property
+bool QQmlCompiler::buildPropertyObjectAssignment(QQmlScript::Property *prop,
+ QQmlScript::Object *obj,
+ QQmlScript::Value *v,
+ const BindingContext &ctxt)
+{
+ Q_ASSERT(prop->index != -1);
+ Q_ASSERT(v->object->type != -1);
+
+ if (!prop->core.isWritable() && !prop->isReadOnlyDeclaration)
+ COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
+
+ if (QQmlMetaType::isInterface(prop->type)) {
+
+ // Assigning an object to an interface ptr property
+ COMPILE_CHECK(buildObject(v->object, ctxt));
+
+ v->type = Value::CreatedObject;
+
+ } else if (prop->type == QMetaType::QVariant) {
+
+ // Assigning an object to a QVariant
+ COMPILE_CHECK(buildObject(v->object, ctxt));
+
+ v->type = Value::CreatedObject;
+ } else {
+ // Normally buildObject() will set this up, but we need the static
+ // meta object earlier to test for assignability. It doesn't matter
+ // that there may still be outstanding synthesized meta object changes
+ // on this type, as they are not relevant for assignability testing
+ v->object->metatype = output->types.at(v->object->type).metaObject();
+ Q_ASSERT(v->object->metaObject());
+
+ // We want to raw metaObject here as the raw metaobject is the
+ // actual property type before we applied any extensions that might
+ // effect the properties on the type, but don't effect assignability
+ const QMetaObject *propertyMetaObject = enginePrivate->rawMetaObjectForType(prop->type);
+
+ // Will be true if the assgned type inherits propertyMetaObject
+ bool isAssignable = false;
+ // Determine isAssignable value
+ if (propertyMetaObject) {
+ const QMetaObject *c = v->object->metatype;
+ while(c) {
+ isAssignable |= (QQmlPropertyPrivate::equal(c, propertyMetaObject));
+ c = c->superClass();
+ }
+ }
+
+ if (isAssignable) {
+ // Simple assignment
+ COMPILE_CHECK(buildObject(v->object, ctxt));
+
+ v->type = Value::CreatedObject;
+ } else if (propertyMetaObject == &QQmlComponent::staticMetaObject) {
+ // Automatic "Component" insertion
+ QQmlScript::Object *root = v->object;
+ QQmlScript::Object *component = pool->New<Object>();
+ component->type = componentTypeRef();
+ component->typeName = QStringLiteral("Qt/Component");
+ component->metatype = &QQmlComponent::staticMetaObject;
+ component->location = root->location;
+ QQmlScript::Value *componentValue = pool->New<Value>();
+ componentValue->object = root;
+ component->getDefaultProperty()->addValue(componentValue);
+ v->object = component;
+ COMPILE_CHECK(buildPropertyObjectAssignment(prop, obj, v, ctxt));
+ } else {
+ COMPILE_EXCEPTION(v->object, tr("Cannot assign object to property"));
+ }
+ }
+
+ return true;
+}
+
+// Compile assigning a single object instance to a regular property using the "on" syntax.
+//
+// For example:
+// Item {
+// NumberAnimation on x { }
+// }
+bool QQmlCompiler::buildPropertyOnAssignment(QQmlScript::Property *prop,
+ QQmlScript::Object *obj,
+ QQmlScript::Object *baseObj,
+ QQmlScript::Value *v,
+ const BindingContext &ctxt)
+{
+ Q_ASSERT(prop->index != -1);
+ Q_ASSERT(v->object->type != -1);
+
+ Q_UNUSED(obj);
+
+ if (!prop->core.isWritable())
+ COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
+
+
+ // Normally buildObject() will set this up, but we need the static
+ // meta object earlier to test for assignability. It doesn't matter
+ // that there may still be outstanding synthesized meta object changes
+ // on this type, as they are not relevant for assignability testing
+ v->object->metatype = output->types.at(v->object->type).metaObject();
+ Q_ASSERT(v->object->metaObject());
+
+ // Will be true if the assigned type inherits QQmlPropertyValueSource
+ bool isPropertyValue = false;
+ // Will be true if the assigned type inherits QQmlPropertyValueInterceptor
+ bool isPropertyInterceptor = false;
+ if (QQmlType *valueType = toQmlType(v->object)) {
+ isPropertyValue = valueType->propertyValueSourceCast() != -1;
+ isPropertyInterceptor = valueType->propertyValueInterceptorCast() != -1;
+ }
+
+ if (isPropertyValue || isPropertyInterceptor) {
+ // Assign as a property value source
+ COMPILE_CHECK(buildObject(v->object, ctxt));
+
+ if (isPropertyInterceptor && prop->parent->synthdata.isEmpty())
+ buildDynamicMeta(baseObj, ForceCreation);
+ v->type = isPropertyValue ? Value::ValueSource : Value::ValueInterceptor;
+ } else {
+ COMPILE_EXCEPTION(v, tr("\"%1\" cannot operate on \"%2\"").arg(v->object->typeName).arg(prop->name().toString()));
+ }
+
+ return true;
+}
+
+// Compile assigning a literal or binding to a regular property
+bool QQmlCompiler::buildPropertyLiteralAssignment(QQmlScript::Property *prop,
+ QQmlScript::Object *obj,
+ QQmlScript::Value *v,
+ const BindingContext &ctxt)
+{
+ Q_ASSERT(prop->index != -1);
+
+ if (v->value.isScript()) {
+
+ //optimization for <Type>.<EnumValue> enum assignments
+ if (prop->core.isEnum()) {
+ bool isEnumAssignment = false;
+ COMPILE_CHECK(testQualifiedEnumAssignment(prop, obj, v, &isEnumAssignment));
+ if (isEnumAssignment) {
+ v->type = Value::Literal;
+ return true;
+ }
+ }
+
+ // Test for other binding optimizations
+ if (!buildLiteralBinding(v, prop, ctxt))
+ COMPILE_CHECK(buildBinding(v, prop, ctxt));
+
+ v->type = Value::PropertyBinding;
+
+ } else {
+
+ COMPILE_CHECK(testLiteralAssignment(prop, v));
+
+ v->type = Value::Literal;
+ }
+
+ return true;
+}
+
+bool QQmlCompiler::testQualifiedEnumAssignment(QQmlScript::Property *prop,
+ QQmlScript::Object *obj,
+ QQmlScript::Value *v,
+ bool *isAssignment)
+{
+ *isAssignment = false;
+ if (!prop->core.isEnum())
+ return true;
+
+ QMetaProperty mprop = obj->metaObject()->property(prop->index);
+
+ if (!prop->core.isWritable() && !prop->isReadOnlyDeclaration)
+ COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
+
+ QString string = v->value.asString();
+ if (!string.at(0).isUpper())
+ return true;
+
+ QStringList parts = string.split(QLatin1Char('.'));
+ if (parts.count() != 2)
+ return true;
+
+ QString typeName = parts.at(0);
+ QQmlType *type = 0;
+ unit->imports().resolveType(typeName, &type, 0, 0, 0, 0);
+
+ //handle enums on value types (where obj->typeName is empty)
+ QString objTypeName = obj->typeName;
+ if (objTypeName.isEmpty()) {
+ QQmlType *objType = toQmlType(obj);
+ if (objType)
+ objTypeName = objType->qmlTypeName();
+ }
+
+ if (!type)
+ return true;
+
+ QString enumValue = parts.at(1);
+ int value;
+ bool ok;
+
+ if (objTypeName == type->qmlTypeName()) {
+ // When these two match, we can short cut the search
+ if (mprop.isFlagType()) {
+ value = mprop.enumerator().keysToValue(enumValue.toUtf8().constData(), &ok);
+ } else {
+ value = mprop.enumerator().keyToValue(enumValue.toUtf8().constData(), &ok);
+ }
+ } else {
+ // Otherwise we have to search the whole type
+ // This matches the logic in QV8TypeWrapper
+ QByteArray enumName = enumValue.toUtf8();
+ const QMetaObject *metaObject = type->baseMetaObject();
+ ok = false;
+ for (int ii = metaObject->enumeratorCount() - 1; !ok && ii >= 0; --ii) {
+ QMetaEnum e = metaObject->enumerator(ii);
+ value = e.keyToValue(enumName.constData(), &ok);
+ }
+ }
+
+ if (!ok)
+ return true;
+
+ v->type = Value::Literal;
+ v->value = QQmlScript::Variant((double)value);
+ *isAssignment = true;
+
+ return true;
+}
+
+struct StaticQtMetaObject : public QObject
+{
+ static const QMetaObject *get()
+ { return &static_cast<StaticQtMetaObject*> (0)->staticQtMetaObject; }
+};
+
+// Similar logic to above, but not knowing target property.
+int QQmlCompiler::evaluateEnum(const QByteArray& script) const
+{
+ int dot = script.indexOf('.');
+ if (dot > 0) {
+ const QByteArray &scope = script.left(dot);
+ QQmlType *type = 0;
+ unit->imports().resolveType(QString::fromUtf8(script.left(dot)), &type, 0, 0, 0, 0);
+ if (!type && scope != "Qt")
+ return -1;
+ const QMetaObject *mo = type ? type->metaObject() : StaticQtMetaObject::get();
+ const char *key = script.constData() + dot+1;
+ int i = mo->enumeratorCount();
+ while (i--) {
+ bool ok;
+ int v = mo->enumerator(i).keyToValue(key, &ok);
+ if (ok)
+ return v;
+ }
+ }
+ return -1;
+}
+
+const QMetaObject *QQmlCompiler::resolveType(const QString& name) const
+{
+ QQmlType *qmltype = 0;
+ if (!unit->imports().resolveType(name, &qmltype, 0, 0, 0, 0))
+ return 0;
+ if (!qmltype)
+ return 0;
+ return qmltype->metaObject();
+}
+
+// similar to logic of completeComponentBuild, but also sticks data
+// into primitives at the end
+int QQmlCompiler::rewriteBinding(const QQmlScript::Variant& value, const QString& name)
+{
+ QQmlRewrite::RewriteBinding rewriteBinding;
+ rewriteBinding.setName(QLatin1Char('$') + name.mid(name.lastIndexOf(QLatin1Char('.')) + 1));
+
+ QString rewrite = rewriteBinding(value.asAST(), value.asScript(), 0);
+
+ return output->indexForString(rewrite);
+}
+
+QString QQmlCompiler::rewriteSignalHandler(const QQmlScript::Variant& value, const QString &name)
+{
+ QQmlRewrite::RewriteSignalHandler rewriteSignalHandler;
+ return rewriteSignalHandler(value.asAST(), value.asScript(), name);
+}
+
+// Ensures that the dynamic meta specification on obj is valid
+bool QQmlCompiler::checkDynamicMeta(QQmlScript::Object *obj)
+{
+ bool seenDefaultProperty = false;
+
+ // We use a coarse grain, 31 bit hash to check if there are duplicates.
+ // Calculating the hash for the names is not a waste as we have to test
+ // them against the illegalNames set anyway.
+ QHashField propNames;
+ QHashField methodNames;
+
+ // Check properties
+ for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
+ const QQmlScript::Object::DynamicProperty &prop = *p;
+
+ if (prop.isDefaultProperty) {
+ if (seenDefaultProperty)
+ COMPILE_EXCEPTION(&prop, tr("Duplicate default property"));
+ seenDefaultProperty = true;
+ }
+
+ if (propNames.testAndSet(prop.name.hash())) {
+ for (Object::DynamicProperty *p2 = obj->dynamicProperties.first(); p2 != p;
+ p2 = obj->dynamicProperties.next(p2)) {
+ if (p2->name == prop.name) {
+ COMPILE_EXCEPTION_LOCATION(prop.nameLocation.line,
+ prop.nameLocation.column,
+ tr("Duplicate property name"));
+ }
+ }
+ }
+
+ if (prop.name.at(0).isUpper()) {
+ COMPILE_EXCEPTION_LOCATION(prop.nameLocation.line,
+ prop.nameLocation.column,
+ tr("Property names cannot begin with an upper case letter"));
+ }
+
+ if (enginePrivate->v8engine()->illegalNames().contains(prop.name)) {
+ COMPILE_EXCEPTION_LOCATION(prop.nameLocation.line,
+ prop.nameLocation.column,
+ tr("Illegal property name"));
+ }
+ }
+
+ for (Object::DynamicSignal *s = obj->dynamicSignals.first(); s; s = obj->dynamicSignals.next(s)) {
+ const QQmlScript::Object::DynamicSignal &currSig = *s;
+
+ if (methodNames.testAndSet(currSig.name.hash())) {
+ for (Object::DynamicSignal *s2 = obj->dynamicSignals.first(); s2 != s;
+ s2 = obj->dynamicSignals.next(s2)) {
+ if (s2->name == currSig.name)
+ COMPILE_EXCEPTION(&currSig, tr("Duplicate signal name"));
+ }
+ }
+
+ if (currSig.name.at(0).isUpper())
+ COMPILE_EXCEPTION(&currSig, tr("Signal names cannot begin with an upper case letter"));
+ if (enginePrivate->v8engine()->illegalNames().contains(currSig.name))
+ COMPILE_EXCEPTION(&currSig, tr("Illegal signal name"));
+ }
+
+ for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) {
+ const QQmlScript::Object::DynamicSlot &currSlot = *s;
+
+ if (methodNames.testAndSet(currSlot.name.hash())) {
+ for (Object::DynamicSignal *s2 = obj->dynamicSignals.first(); s2;
+ s2 = obj->dynamicSignals.next(s2)) {
+ if (s2->name == currSlot.name)
+ COMPILE_EXCEPTION(&currSlot, tr("Duplicate method name"));
+ }
+ for (Object::DynamicSlot *s2 = obj->dynamicSlots.first(); s2 != s;
+ s2 = obj->dynamicSlots.next(s2)) {
+ if (s2->name == currSlot.name)
+ COMPILE_EXCEPTION(&currSlot, tr("Duplicate method name"));
+ }
+ }
+
+ if (currSlot.name.at(0).isUpper())
+ COMPILE_EXCEPTION(&currSlot, tr("Method names cannot begin with an upper case letter"));
+ if (enginePrivate->v8engine()->illegalNames().contains(currSlot.name))
+ COMPILE_EXCEPTION(&currSlot, tr("Illegal method name"));
+ }
+
+ return true;
+}
+
+bool QQmlCompiler::mergeDynamicMetaProperties(QQmlScript::Object *obj)
+{
+ for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p;
+ p = obj->dynamicProperties.next(p)) {
+
+ if (!p->defaultValue || p->type == Object::DynamicProperty::Alias)
+ continue;
+
+ Property *property = 0;
+ if (p->isDefaultProperty) {
+ property = obj->getDefaultProperty();
+ } else {
+ property = obj->getProperty(p->name);
+ if (!property->values.isEmpty())
+ COMPILE_EXCEPTION(property, tr("Property value set multiple times"));
+ }
+
+ if (p->isReadOnly)
+ property->isReadOnlyDeclaration = true;
+
+ if (property->value)
+ COMPILE_EXCEPTION(property, tr("Invalid property nesting"));
+
+ property->values.append(p->defaultValue->values);
+ }
+ return true;
+}
+
+Q_GLOBAL_STATIC(QAtomicInt, classIndexCounter)
+
+bool QQmlCompiler::buildDynamicMeta(QQmlScript::Object *obj, DynamicMetaMode mode)
+{
+ Q_ASSERT(obj);
+ Q_ASSERT(obj->metatype);
+
+ if (mode != ForceCreation &&
+ obj->dynamicProperties.isEmpty() &&
+ obj->dynamicSignals.isEmpty() &&
+ obj->dynamicSlots.isEmpty())
+ return true;
+
+ bool resolveAlias = (mode == ResolveAliases);
+
+ const Object::DynamicProperty *defaultProperty = 0;
+ int aliasCount = 0;
+ int varPropCount = 0;
+ int totalPropCount = 0;
+ int firstPropertyVarIndex = 0;
+
+ for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
+
+ if (p->type == Object::DynamicProperty::Alias)
+ aliasCount++;
+ if (p->type == Object::DynamicProperty::Var)
+ varPropCount++;
+
+ if (p->isDefaultProperty &&
+ (resolveAlias || p->type != Object::DynamicProperty::Alias))
+ defaultProperty = p;
+
+ if (!resolveAlias) {
+ // No point doing this for both the alias and non alias cases
+ QQmlPropertyData *d = property(obj, p->name);
+ if (d && d->isFinal())
+ COMPILE_EXCEPTION(p, tr("Cannot override FINAL property"));
+ }
+ }
+
+ bool buildData = resolveAlias || aliasCount == 0;
+
+ QByteArray dynamicData;
+ if (buildData) {
+ typedef QQmlVMEMetaData VMD;
+
+ dynamicData = QByteArray(sizeof(QQmlVMEMetaData) +
+ (obj->dynamicProperties.count() - aliasCount) * sizeof(VMD::PropertyData) +
+ obj->dynamicSlots.count() * sizeof(VMD::MethodData) +
+ aliasCount * sizeof(VMD::AliasData), 0);
+ }
+
+ int uniqueClassId = classIndexCounter()->fetchAndAddRelaxed(1);
+
+ QByteArray newClassName = obj->metatype->className();
+ newClassName.append("_QML_");
+ newClassName.append(QByteArray::number(uniqueClassId));
+
+ if (compileState->root == obj && !compileState->nested) {
+ QString path = output->url.path();
+ int lastSlash = path.lastIndexOf(QLatin1Char('/'));
+ if (lastSlash > -1) {
+ QString nameBase = path.mid(lastSlash + 1, path.length()-lastSlash-5);
+ if (!nameBase.isEmpty() && nameBase.at(0).isUpper())
+ newClassName = nameBase.toUtf8() + "_QMLTYPE_" + QByteArray::number(uniqueClassId);
+ }
+ }
+
+ QFastMetaBuilder builder;
+ QFastMetaBuilder::StringRef classNameRef = builder.init(newClassName.length(),
+ obj->dynamicProperties.count() - (resolveAlias?0:aliasCount),
+ obj->dynamicSlots.count(),
+ obj->dynamicSignals.count() + obj->dynamicProperties.count(),
+ defaultProperty?1:0);
+
+ struct TypeData {
+ Object::DynamicProperty::Type dtype;
+ int metaType;
+ const char *cppType;
+ } builtinTypes[] = {
+ { Object::DynamicProperty::Var, QMetaType::QVariant, "QVariant" },
+ { Object::DynamicProperty::Variant, QMetaType::QVariant, "QVariant" },
+ { Object::DynamicProperty::Int, QMetaType::Int, "int" },
+ { Object::DynamicProperty::Bool, QMetaType::Bool, "bool" },
+ { Object::DynamicProperty::Real, QMetaType::Double, "double" },
+ { Object::DynamicProperty::String, QMetaType::QString, "QString" },
+ { Object::DynamicProperty::Url, QMetaType::QUrl, "QUrl" },
+ { Object::DynamicProperty::Color, QMetaType::QColor, "QColor" },
+ { Object::DynamicProperty::Time, QMetaType::QTime, "QTime" },
+ { Object::DynamicProperty::Date, QMetaType::QDate, "QDate" },
+ { Object::DynamicProperty::DateTime, QMetaType::QDateTime, "QDateTime" },
+ };
+ static const int builtinTypeCount = sizeof(builtinTypes) / sizeof(TypeData);
+ QFastMetaBuilder::StringRef typeRefs[builtinTypeCount];
+
+ // Reserve dynamic properties
+ if (obj->dynamicProperties.count()) {
+ typedef QQmlVMEMetaData VMD;
+
+ int effectivePropertyIndex = 0;
+ for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
+
+ // Reserve space for name
+ p->nameRef = builder.newString(p->name.utf8length());
+
+ int propertyType = 0;
+ bool readonly = false;
+ QFastMetaBuilder::StringRef typeRef;
+
+ if (p->type == Object::DynamicProperty::Alias) {
+ continue;
+ } else if (p->type < builtinTypeCount) {
+ Q_ASSERT(builtinTypes[p->type].dtype == p->type);
+ propertyType = builtinTypes[p->type].metaType;
+ if (typeRefs[p->type].isEmpty())
+ typeRefs[p->type] = builder.newString(strlen(builtinTypes[p->type].cppType));
+ typeRef = typeRefs[p->type];
+
+ } else {
+ Q_ASSERT(p->type == Object::DynamicProperty::CustomList ||
+ p->type == Object::DynamicProperty::Custom);
+
+ // XXX don't double resolve this in the case of an alias run
+
+ QByteArray customTypeName;
+ QQmlType *qmltype = 0;
+ QString url;
+ if (!unit->imports().resolveType(p->customType.toString(), &qmltype, &url, 0, 0, 0))
+ COMPILE_EXCEPTION(p, tr("Invalid property type"));
+
+ if (!qmltype) {
+ QQmlTypeData *tdata = enginePrivate->typeLoader.get(QUrl(url));
+ Q_ASSERT(tdata);
+ Q_ASSERT(tdata->isComplete());
+
+ QQmlCompiledData *data = tdata->compiledData();
+ customTypeName = data->root->className();
+ data->release();
+ tdata->release();
+ } else {
+ customTypeName = qmltype->typeName();
+ }
+
+ if (p->type == Object::DynamicProperty::Custom) {
+ customTypeName += '*';
+ propertyType = QMetaType::QObjectStar;
+ } else {
+ readonly = true;
+ customTypeName = QByteArray("QQmlListProperty<") + customTypeName + QByteArray(">");
+ propertyType = qMetaTypeId<QQmlListProperty<QObject> >();
+ }
+
+ p->resolvedCustomTypeName = pool->NewByteArray(customTypeName);
+ p->typeRef = builder.newString(customTypeName.length());
+ typeRef = p->typeRef;
+ }
+
+ if (p->type == Object::DynamicProperty::Var)
+ continue;
+
+ if (p->isReadOnly)
+ readonly = true;
+
+ if (buildData) {
+ VMD *vmd = (QQmlVMEMetaData *)dynamicData.data();
+ vmd->propertyCount++;
+ (vmd->propertyData() + effectivePropertyIndex)->propertyType = propertyType;
+ }
+
+ if (p->type < builtinTypeCount)
+ builder.setProperty(effectivePropertyIndex, p->nameRef, typeRef, (QMetaType::Type)propertyType,
+ readonly?QFastMetaBuilder::None:QFastMetaBuilder::Writable,
+ effectivePropertyIndex);
+ else
+ builder.setProperty(effectivePropertyIndex, p->nameRef, typeRef,
+ readonly?QFastMetaBuilder::None:QFastMetaBuilder::Writable,
+ effectivePropertyIndex);
+
+ p->changedSignatureRef = builder.newString(p->name.utf8length() + strlen("Changed()"));
+ builder.setSignal(effectivePropertyIndex, p->changedSignatureRef);
+
+ effectivePropertyIndex++;
+ }
+
+ if (varPropCount) {
+ VMD *vmd = (QQmlVMEMetaData *)dynamicData.data();
+ if (buildData)
+ vmd->varPropertyCount = varPropCount;
+ firstPropertyVarIndex = effectivePropertyIndex;
+ totalPropCount = varPropCount + effectivePropertyIndex;
+ for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
+ if (p->type == Object::DynamicProperty::Var) {
+ QFastMetaBuilder::StringRef typeRef = typeRefs[p->type];
+ if (buildData) {
+ vmd->propertyCount++;
+ (vmd->propertyData() + effectivePropertyIndex)->propertyType = QMetaType::QVariant;
+ }
+
+ builder.setProperty(effectivePropertyIndex, p->nameRef, typeRef,
+ QMetaType::QVariant,
+ p->isReadOnly?QFastMetaBuilder::None:QFastMetaBuilder::Writable,
+ effectivePropertyIndex);
+
+ p->changedSignatureRef = builder.newString(p->name.utf8length() + strlen("Changed()"));
+ builder.setSignal(effectivePropertyIndex, p->changedSignatureRef);
+
+ effectivePropertyIndex++;
+ }
+ }
+ }
+
+ if (aliasCount) {
+ int aliasIndex = 0;
+ for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
+ if (p->type == Object::DynamicProperty::Alias) {
+ if (resolveAlias) {
+ Q_ASSERT(buildData);
+ ((QQmlVMEMetaData *)dynamicData.data())->aliasCount++;
+ COMPILE_CHECK(compileAlias(builder, dynamicData, obj, effectivePropertyIndex,
+ aliasIndex, *p));
+ }
+ // Even if we aren't resolving the alias, we need a fake signal so that the
+ // metaobject remains consistent across the resolve and non-resolve alias runs
+ p->changedSignatureRef = builder.newString(p->name.utf8length() + strlen("Changed()"));
+ builder.setSignal(effectivePropertyIndex, p->changedSignatureRef);
+ effectivePropertyIndex++;
+ aliasIndex++;
+ }
+ }
+ }
+ }
+
+ // Reserve default property
+ QFastMetaBuilder::StringRef defPropRef;
+ if (defaultProperty) {
+ defPropRef = builder.newString(strlen("DefaultProperty"));
+ builder.setClassInfo(0, defPropRef, defaultProperty->nameRef);
+ }
+
+ // Reserve dynamic signals
+ int signalIndex = 0;
+ for (Object::DynamicSignal *s = obj->dynamicSignals.first(); s; s = obj->dynamicSignals.next(s)) {
+
+ int paramCount = s->parameterNames.count();
+
+ int signatureSize = s->name.utf8length() + 2 /* paren */;
+ int namesSize = 0;
+ if (paramCount) signatureSize += s->parameterTypesLength() + (paramCount - 1) /* commas */;
+ if (paramCount) namesSize += s->parameterNamesLength() + (paramCount - 1) /* commas */;
+
+ s->signatureRef = builder.newString(signatureSize);
+ if (namesSize) s->parameterNamesRef = builder.newString(namesSize);
+
+ if (buildData)
+ ((QQmlVMEMetaData *)dynamicData.data())->signalCount++;
+
+ builder.setSignal(signalIndex + obj->dynamicProperties.count(), s->signatureRef, s->parameterNamesRef);
+ ++signalIndex;
+ }
+
+ // Reserve dynamic slots
+ if (obj->dynamicSlots.count()) {
+
+ // Allocate QVariant string
+ if (typeRefs[0].isEmpty())
+ typeRefs[0] = builder.newString(strlen(builtinTypes[0].cppType));
+
+ typedef QQmlVMEMetaData VMD;
+
+ int methodIndex = 0;
+ for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) {
+ int paramCount = s->parameterNames.count();
+
+ int signatureSize = s->name.utf8length() + 2 /* paren */;
+ int namesSize = 0;
+ if (paramCount) signatureSize += (paramCount * strlen("QVariant") + (paramCount - 1));
+ if (paramCount) namesSize += s->parameterNamesLength() + (paramCount - 1 /* commas */);
+
+ s->signatureRef = builder.newString(signatureSize);
+ if (namesSize) s->parameterNamesRef = builder.newString(namesSize);
+
+ builder.setMethod(methodIndex, s->signatureRef, s->parameterNamesRef, typeRefs[0]);
+
+ if (buildData) {
+ QString funcScript;
+ funcScript.reserve(strlen("(function ") + s->name.length() + 1 /* lparen */ +
+ namesSize + 1 /* rparen */ + s->body.length() + 1 /* rparen */);
+ funcScript = QLatin1String("(function ") + s->name.toString() + QLatin1Char('(');
+ for (int jj = 0; jj < paramCount; ++jj) {
+ if (jj) funcScript.append(QLatin1Char(','));
+ funcScript.append(QLatin1String(s->parameterNames.at(jj)));
+ }
+ funcScript += QLatin1Char(')') + s->body + QLatin1Char(')');
+
+ QByteArray utf8 = funcScript.toUtf8();
+ VMD::MethodData methodData = { s->parameterNames.count(), 0,
+ utf8.length(),
+ s->location.start.line };
+
+ VMD *vmd = (QQmlVMEMetaData *)dynamicData.data();
+ vmd->methodCount++;
+
+ VMD::MethodData &md = *(vmd->methodData() + methodIndex);
+ md = methodData;
+ md.bodyOffset = dynamicData.size();
+
+ dynamicData.append((const char *)utf8.constData(), utf8.length());
+ }
+
+
+ methodIndex++;
+ }
+ }
+
+ // Now allocate used builtin types
+ for (int ii = 0; ii < builtinTypeCount; ++ii) {
+ if (!typeRefs[ii].isEmpty())
+ typeRefs[ii].load(builtinTypes[ii].cppType);
+ }
+
+ // Now allocate properties
+ for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
+
+ char *d = p->changedSignatureRef.data();
+ p->name.writeUtf8(d);
+ strcpy(d + p->name.utf8length(), "Changed()");
+
+ if (p->type == Object::DynamicProperty::Alias && !resolveAlias)
+ continue;
+
+ p->nameRef.load(p->name);
+
+ if (p->type >= builtinTypeCount) {
+ Q_ASSERT(p->resolvedCustomTypeName);
+ p->typeRef.load(*p->resolvedCustomTypeName);
+ }
+ }
+
+ // Allocate default property if necessary
+ if (defaultProperty)
+ strcpy(defPropRef.data(), "DefaultProperty");
+
+ // Now allocate signals
+ for (Object::DynamicSignal *s = obj->dynamicSignals.first(); s; s = obj->dynamicSignals.next(s)) {
+
+ char *d = s->signatureRef.data();
+ char *d2 = s->parameterNamesRef.isEmpty()?0:s->parameterNamesRef.data();
+ s->name.writeUtf8(d); d += s->name.utf8length();
+ *d++ = '(';
+
+ for (int jj = 0; jj < s->parameterNames.count(); ++jj) {
+ if (jj != 0) { *d++ = ','; *d2++ = ','; }
+ strcpy(d, s->parameterTypes.at(jj).constData());
+ d += s->parameterTypes.at(jj).length();
+ s->parameterNames.at(jj).writeUtf8(d2);
+ d2 += s->parameterNames.at(jj).utf8length();
+ }
+ *d++ = ')';
+ *d = 0;
+ if (d2) *d2 = 0;
+ }
+
+ // Now allocate methods
+ for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) {
+ char *d = s->signatureRef.data();
+ char *d2 = s->parameterNamesRef.isEmpty()?0:s->parameterNamesRef.data();
+ s->name.writeUtf8(d); d += s->name.utf8length();
+ *d++ = '(';
+ for (int jj = 0; jj < s->parameterNames.count(); ++jj) {
+ if (jj != 0) { *d++ = ','; *d2++ = ','; }
+ strcpy(d, "QVariant");
+ d += strlen("QVariant");
+ strcpy(d2, s->parameterNames.at(jj).constData());
+ d2 += s->parameterNames.at(jj).length();
+ }
+ *d++ = ')';
+ *d = 0;
+ if (d2) *d2 = 0;
+ }
+
+ // Now allocate class name
+ classNameRef.load(newClassName);
+
+ obj->metadata = builder.toData();
+ builder.fromData(&obj->extObject, obj->metatype, obj->metadata);
+
+ if (mode == IgnoreAliases && aliasCount)
+ compileState->aliasingObjects.append(obj);
+
+ obj->synthdata = dynamicData;
+
+ if (obj->synthCache) {
+ obj->synthCache->release();
+ obj->synthCache = 0;
+ }
+
+ if (obj->type != -1) {
+ QQmlPropertyCache *superCache = output->types[obj->type].createPropertyCache(engine);
+ QQmlPropertyCache *cache =
+ superCache->copyAndAppend(engine, &obj->extObject,
+ QQmlPropertyData::NoFlags,
+ QQmlPropertyData::IsVMEFunction,
+ QQmlPropertyData::IsVMESignal);
+
+ // now we modify the flags appropriately for var properties.
+ int propertyOffset = obj->extObject.propertyOffset();
+ QQmlPropertyData *currPropData = 0;
+ for (int pvi = firstPropertyVarIndex; pvi < totalPropCount; ++pvi) {
+ currPropData = cache->property(pvi + propertyOffset);
+ currPropData->setFlags(currPropData->getFlags() | QQmlPropertyData::IsVMEProperty);
+ }
+
+ obj->synthCache = cache;
+ }
+
+ return true;
+}
+
+bool QQmlCompiler::checkValidId(QQmlScript::Value *v, const QString &val)
+{
+ if (val.isEmpty())
+ COMPILE_EXCEPTION(v, tr( "Invalid empty ID"));
+
+ QChar ch = val.at(0);
+ if (ch.isLetter() && !ch.isLower())
+ COMPILE_EXCEPTION(v, tr( "IDs cannot start with an uppercase letter"));
+
+ QChar u(QLatin1Char('_'));
+ if (!ch.isLetter() && ch != u)
+ COMPILE_EXCEPTION(v, tr( "IDs must start with a letter or underscore"));
+
+ for (int ii = 1; ii < val.count(); ++ii) {
+ ch = val.at(ii);
+ if (!ch.isLetterOrNumber() && ch != u)
+ COMPILE_EXCEPTION(v, tr( "IDs must contain only letters, numbers, and underscores"));
+ }
+
+ if (enginePrivate->v8engine()->illegalNames().contains(val))
+ COMPILE_EXCEPTION(v, tr( "ID illegally masks global JavaScript property"));
+
+ return true;
+}
+
+#include <private/qqmljsparser_p.h>
+
+static QStringList astNodeToStringList(QQmlJS::AST::Node *node)
+{
+ if (node->kind == QQmlJS::AST::Node::Kind_IdentifierExpression) {
+ QString name =
+ static_cast<QQmlJS::AST::IdentifierExpression *>(node)->name.toString();
+ return QStringList() << name;
+ } else if (node->kind == QQmlJS::AST::Node::Kind_FieldMemberExpression) {
+ QQmlJS::AST::FieldMemberExpression *expr = static_cast<QQmlJS::AST::FieldMemberExpression *>(node);
+
+ QStringList rv = astNodeToStringList(expr->base);
+ if (rv.isEmpty())
+ return rv;
+ rv.append(expr->name.toString());
+ return rv;
+ }
+ return QStringList();
+}
+
+bool QQmlCompiler::compileAlias(QFastMetaBuilder &builder,
+ QByteArray &data,
+ QQmlScript::Object *obj,
+ int propIndex, int aliasIndex,
+ Object::DynamicProperty &prop)
+{
+ if (!prop.defaultValue)
+ COMPILE_EXCEPTION(obj, tr("No property alias location"));
+
+ if (!prop.defaultValue->values.isOne() ||
+ prop.defaultValue->values.first()->object ||
+ !prop.defaultValue->values.first()->value.isScript())
+ COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
+
+ QQmlJS::AST::Node *node = prop.defaultValue->values.first()->value.asAST();
+ if (!node)
+ COMPILE_EXCEPTION(obj, tr("No property alias location")); // ### Can this happen?
+
+ QStringList alias = astNodeToStringList(node);
+
+ if (alias.count() < 1 || alias.count() > 3)
+ COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias reference. An alias reference must be specified as <id>, <id>.<property> or <id>.<value property>.<property>"));
+
+ QQmlScript::Object *idObject = compileState->ids.value(alias.at(0));
+ if (!idObject)
+ COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias reference. Unable to find id \"%1\"").arg(alias.at(0)));
+
+ QByteArray typeName;
+
+ int propIdx = -1;
+ int flags = 0;
+ int type = 0;
+ bool writable = false;
+ bool resettable = false;
+ if (alias.count() == 2 || alias.count() == 3) {
+ propIdx = indexOfProperty(idObject, alias.at(1));
+
+ if (-1 == propIdx) {
+ COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
+ } else if (propIdx > 0xFFFF) {
+ COMPILE_EXCEPTION(prop.defaultValue, tr("Alias property exceeds alias bounds"));
+ }
+
+ QMetaProperty aliasProperty = idObject->metaObject()->property(propIdx);
+ if (!aliasProperty.isScriptable())
+ COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
+
+ writable = aliasProperty.isWritable() && !prop.isReadOnly;
+ resettable = aliasProperty.isResettable() && !prop.isReadOnly;
+
+ if (aliasProperty.type() < QVariant::UserType
+ || uint(aliasProperty.type()) == QMetaType::QVariant)
+ type = aliasProperty.type();
+
+ if (alias.count() == 3) {
+ QQmlValueType *valueType = enginePrivate->valueTypes[aliasProperty.type()];
+ if (!valueType)
+ COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
+
+ propIdx |= ((unsigned int)aliasProperty.type()) << 24;
+
+ int valueTypeIndex = valueType->metaObject()->indexOfProperty(alias.at(2).toUtf8().constData());
+ if (valueTypeIndex == -1)
+ COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
+ Q_ASSERT(valueTypeIndex <= 0xFF);
+
+ aliasProperty = valueType->metaObject()->property(valueTypeIndex);
+ propIdx |= (valueTypeIndex << 16);
+
+ // update the property type
+ type = aliasProperty.type();
+ if (type >= (int)QVariant::UserType)
+ type = 0;
+ }
+
+ if (aliasProperty.isEnumType())
+ typeName = "int"; // Avoid introducing a dependency on the aliased metaobject
+ else
+ typeName = aliasProperty.typeName();
+ } else {
+ Q_ASSERT(idObject->type != -1); // How else did it get an id?
+
+ const QQmlCompiledData::TypeReference &ref = output->types.at(idObject->type);
+ if (ref.type)
+ typeName = ref.type->typeName();
+ else
+ typeName = ref.component->root->className();
+
+ typeName += '*';
+ }
+
+ if (typeName.endsWith('*'))
+ flags |= QML_ALIAS_FLAG_PTR;
+
+ QQmlVMEMetaData::AliasData aliasData = { idObject->idIndex, propIdx, flags };
+
+ typedef QQmlVMEMetaData VMD;
+ VMD *vmd = (QQmlVMEMetaData *)data.data();
+ *(vmd->aliasData() + aliasIndex) = aliasData;
+
+ prop.nameRef = builder.newString(prop.name.utf8length());
+ prop.resolvedCustomTypeName = pool->NewByteArray(typeName);
+ prop.typeRef = builder.newString(typeName.length());
+
+ int propertyFlags = 0;
+ if (writable)
+ propertyFlags |= QFastMetaBuilder::Writable;
+ if (resettable)
+ propertyFlags |= QFastMetaBuilder::Resettable;
+
+ builder.setProperty(propIndex, prop.nameRef, prop.typeRef, (QMetaType::Type)type,
+ (QFastMetaBuilder::PropertyFlag)propertyFlags,
+ propIndex);
+
+ return true;
+}
+
+bool QQmlCompiler::buildBinding(QQmlScript::Value *value,
+ QQmlScript::Property *prop,
+ const BindingContext &ctxt)
+{
+ Q_ASSERT(prop->index != -1);
+ Q_ASSERT(prop->parent);
+ Q_ASSERT(prop->parent->metaObject());
+
+ if (!prop->core.isWritable() && !prop->core.isQList() && !prop->isReadOnlyDeclaration)
+ COMPILE_EXCEPTION(prop, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
+
+ JSBindingReference *reference = pool->New<JSBindingReference>();
+ reference->expression = value->value;
+ reference->property = prop;
+ reference->value = value;
+ reference->bindingContext = ctxt;
+ addBindingReference(reference);
+
+ return true;
+}
+
+bool QQmlCompiler::buildLiteralBinding(QQmlScript::Value *v,
+ QQmlScript::Property *prop,
+ const QQmlCompilerTypes::BindingContext &)
+{
+ Q_ASSERT(v->value.isScript());
+
+ if (!prop->core.isWritable())
+ return false;
+
+ AST::Node *binding = v->value.asAST();
+
+ if (prop->type == QVariant::String) {
+ if (AST::CallExpression *e = AST::cast<AST::CallExpression *>(binding)) {
+ if (AST::IdentifierExpression *i = AST::cast<AST::IdentifierExpression *>(e->base)) {
+ if (i->name == qsTrId_string) {
+ AST::ArgumentList *arg1 = e->arguments?e->arguments:0;
+ AST::ArgumentList *arg2 = arg1?arg1->next:0;
+
+ if (arg1 && arg1->expression->kind == AST::Node::Kind_StringLiteral &&
+ (!arg2 || arg2->expression->kind == AST::Node::Kind_NumericLiteral) &&
+ (!arg2 || !arg2->next)) {
+
+ QStringRef text;
+ int n = -1;
+
+ text = AST::cast<AST::StringLiteral *>(arg1->expression)->value;
+ if (arg2) n = (int)AST::cast<AST::NumericLiteral *>(arg2->expression)->value;
+
+ TrBindingReference *reference = pool->New<TrBindingReference>();
+ reference->dataType = BindingReference::TrId;
+ reference->text = text;
+ reference->n = n;
+ v->bindingReference = reference;
+ return true;
+ }
+
+ } else if (i->name == qsTr_string) {
+
+ AST::ArgumentList *arg1 = e->arguments?e->arguments:0;
+ AST::ArgumentList *arg2 = arg1?arg1->next:0;
+ AST::ArgumentList *arg3 = arg2?arg2->next:0;
+
+ if (arg1 && arg1->expression->kind == AST::Node::Kind_StringLiteral &&
+ (!arg2 || arg2->expression->kind == AST::Node::Kind_StringLiteral) &&
+ (!arg3 || arg3->expression->kind == AST::Node::Kind_NumericLiteral) &&
+ (!arg3 || !arg3->next)) {
+
+ QStringRef text;
+ QStringRef comment;
+ int n = -1;
+
+ text = AST::cast<AST::StringLiteral *>(arg1->expression)->value;
+ if (arg2) comment = AST::cast<AST::StringLiteral *>(arg2->expression)->value;
+ if (arg3) n = (int)AST::cast<AST::NumericLiteral *>(arg3->expression)->value;
+
+ TrBindingReference *reference = pool->New<TrBindingReference>();
+ reference->dataType = BindingReference::Tr;
+ reference->text = text;
+ reference->comment = comment;
+ reference->n = n;
+ v->bindingReference = reference;
+ return true;
+ }
+
+ }
+ }
+ }
+
+ }
+
+ return false;
+}
+
+void QQmlCompiler::genBindingAssignment(QQmlScript::Value *binding,
+ QQmlScript::Property *prop,
+ QQmlScript::Object *obj,
+ QQmlScript::Property *valueTypeProperty)
+{
+ Q_UNUSED(obj);
+ Q_ASSERT(binding->bindingReference);
+
+ const BindingReference &ref = *binding->bindingReference;
+ if (ref.dataType == BindingReference::TrId) {
+ const TrBindingReference &tr = static_cast<const TrBindingReference &>(ref);
+
+ Instruction::StoreTrIdString store;
+ store.propertyIndex = prop->core.coreIndex;
+ store.text = output->indexForByteArray(tr.text.toUtf8());
+ store.n = tr.n;
+ output->addInstruction(store);
+ } else if (ref.dataType == BindingReference::Tr) {
+ const TrBindingReference &tr = static_cast<const TrBindingReference &>(ref);
+
+ Instruction::StoreTrString store;
+ store.propertyIndex = prop->core.coreIndex;
+ store.context = translationContextIndex();
+ store.text = output->indexForByteArray(tr.text.toUtf8());
+ store.comment = output->indexForByteArray(tr.comment.toUtf8());
+ store.n = tr.n;
+ output->addInstruction(store);
+ } else if (ref.dataType == BindingReference::V4) {
+ const JSBindingReference &js = static_cast<const JSBindingReference &>(ref);
+
+ Instruction::StoreV4Binding store;
+ store.value = js.compiledIndex;
+ store.context = js.bindingContext.stack;
+ store.owner = js.bindingContext.owner;
+ if (valueTypeProperty) {
+ store.property = (valueTypeProperty->index & 0xFFFF) |
+ ((valueTypeProperty->type & 0xFF)) << 16 |
+ ((prop->index & 0xFF) << 24);
+ store.isRoot = (compileState->root == valueTypeProperty->parent);
+ } else {
+ store.property = prop->index;
+ store.isRoot = (compileState->root == obj);
+ }
+ store.line = binding->location.start.line;
+ store.column = binding->location.start.column;
+ output->addInstruction(store);
+ } else if (ref.dataType == BindingReference::V8) {
+ const JSBindingReference &js = static_cast<const JSBindingReference &>(ref);
+
+ Instruction::StoreV8Binding store;
+ store.value = js.compiledIndex;
+ store.context = js.bindingContext.stack;
+ store.owner = js.bindingContext.owner;
+ if (valueTypeProperty) {
+ store.isRoot = (compileState->root == valueTypeProperty->parent);
+ } else {
+ store.isRoot = (compileState->root == obj);
+ }
+ store.line = binding->location.start.line;
+ store.column = binding->location.start.column;
+
+ Q_ASSERT(js.bindingContext.owner == 0 ||
+ (js.bindingContext.owner != 0 && valueTypeProperty));
+ if (js.bindingContext.owner) {
+ store.property = genValueTypeData(prop, valueTypeProperty);
+ } else {
+ store.property = prop->core;
+ }
+
+ output->addInstruction(store);
+ } else if (ref.dataType == BindingReference::QtScript) {
+ const JSBindingReference &js = static_cast<const JSBindingReference &>(ref);
+
+ QQmlInstruction store;
+ store.assignBinding.value = output->indexForString(js.rewrittenExpression);
+ store.assignBinding.context = js.bindingContext.stack;
+ store.assignBinding.owner = js.bindingContext.owner;
+ store.assignBinding.line = binding->location.start.line;
+ store.assignBinding.column = binding->location.start.column;
+
+ if (valueTypeProperty) {
+ store.assignBinding.isRoot = (compileState->root == valueTypeProperty->parent);
+ } else {
+ store.assignBinding.isRoot = (compileState->root == obj);
+ }
+
+ Q_ASSERT(js.bindingContext.owner == 0 ||
+ (js.bindingContext.owner != 0 && valueTypeProperty));
+ if (js.bindingContext.owner) {
+ store.assignBinding.property = genValueTypeData(prop, valueTypeProperty);
+ } else {
+ store.assignBinding.property = prop->core;
+ }
+ output->addInstructionHelper(
+ !prop->isAlias ? QQmlInstruction::StoreBinding
+ : QQmlInstruction::StoreBindingOnAlias
+ , store);
+ } else {
+ Q_ASSERT(!"Unhandled BindingReference::DataType type");
+ }
+}
+
+int QQmlCompiler::genContextCache()
+{
+ if (compileState->ids.count() == 0)
+ return -1;
+
+ QQmlIntegerCache *cache = new QQmlIntegerCache();
+ cache->reserve(compileState->ids.count());
+ for (Object *o = compileState->ids.first(); o; o = compileState->ids.next(o))
+ cache->add(o->id, o->idIndex);
+
+ output->contextCaches.append(cache);
+ return output->contextCaches.count() - 1;
+}
+
+QQmlPropertyData
+QQmlCompiler::genValueTypeData(QQmlScript::Property *valueTypeProp,
+ QQmlScript::Property *prop)
+{
+ typedef QQmlPropertyPrivate QDPP;
+ return QDPP::saveValueType(prop->parent->metaObject(), prop->index,
+ enginePrivate->valueTypes[prop->type]->metaObject(),
+ valueTypeProp->index, engine);
+}
+
+bool QQmlCompiler::completeComponentBuild()
+{
+ if (componentStats)
+ componentStats->componentStat.ids = compileState->ids.count();
+
+ for (Object *aliasObject = compileState->aliasingObjects.first(); aliasObject;
+ aliasObject = compileState->aliasingObjects.next(aliasObject))
+ COMPILE_CHECK(buildDynamicMeta(aliasObject, ResolveAliases));
+
+ QV4Compiler::Expression expr(unit->imports());
+ expr.component = compileState->root;
+ expr.ids = &compileState->ids;
+ expr.importCache = output->importCache;
+
+ QV4Compiler bindingCompiler;
+
+ QList<JSBindingReference*> sharedBindings;
+
+ for (JSBindingReference *b = compileState->bindings.first(); b; b = b->nextReference) {
+
+ JSBindingReference &binding = *b;
+
+ // ### We don't currently optimize for bindings on alias's - because
+ // of the solution to QTBUG-13719
+ if (!binding.property->isAlias) {
+ expr.context = binding.bindingContext.object;
+ expr.property = binding.property;
+ expr.expression = binding.expression;
+
+ int index = bindingCompiler.compile(expr, enginePrivate);
+ if (index != -1) {
+ binding.dataType = BindingReference::V4;
+ binding.compiledIndex = index;
+ if (componentStats)
+ componentStats->componentStat.optimizedBindings.append(b->value->location);
+ continue;
+ }
+ }
+
+ // Pre-rewrite the expression
+ QString expression = binding.expression.asScript();
+
+ QQmlRewrite::RewriteBinding rewriteBinding;
+ rewriteBinding.setName(QLatin1Char('$')+binding.property->name().toString());
+ bool isSharable = false;
+ binding.rewrittenExpression = rewriteBinding(binding.expression.asAST(), expression, &isSharable);
+
+ if (isSharable && !binding.property->isValueTypeSubProperty && !binding.property->isAlias /* See above re alias */ &&
+ binding.property->type != qMetaTypeId<QQmlBinding*>()) {
+ binding.dataType = BindingReference::V8;
+ sharedBindings.append(b);
+ } else {
+ binding.dataType = BindingReference::QtScript;
+ }
+
+ if (componentStats)
+ componentStats->componentStat.scriptBindings.append(b->value->location);
+ }
+
+ if (!sharedBindings.isEmpty()) {
+ struct Sort {
+ static bool lt(const JSBindingReference *lhs, const JSBindingReference *rhs)
+ {
+ return lhs->value->location.start.line < rhs->value->location.start.line;
+ }
+ };
+
+ qSort(sharedBindings.begin(), sharedBindings.end(), Sort::lt);
+
+ int startLineNumber = sharedBindings.at(0)->value->location.start.line;
+ int lineNumber = startLineNumber;
+
+ QByteArray functionArray("[", 1);
+ for (int ii = 0; ii < sharedBindings.count(); ++ii) {
+
+ JSBindingReference *reference = sharedBindings.at(ii);
+ QQmlScript::Value *value = reference->value;
+ const QString &expression = reference->rewrittenExpression;
+
+ if (ii != 0) functionArray.append(",", 1);
+
+ while (lineNumber < value->location.start.line) {
+ lineNumber++;
+ functionArray.append("\n", 1);
+ }
+
+ functionArray += expression.toUtf8();
+ lineNumber += expression.count(QLatin1Char('\n'));
+ reference->compiledIndex = ii;
+ }
+ functionArray.append("]", 1);
+
+ compileState->v8BindingProgram = functionArray;
+ compileState->v8BindingProgramLine = startLineNumber;
+ }
+
+ if (bindingCompiler.isValid())
+ compileState->compiledBindingData = bindingCompiler.program();
+
+ // Check pop()'s matched push()'s
+ Q_ASSERT(compileState->objectDepth.depth() == 0);
+ Q_ASSERT(compileState->listDepth.depth() == 0);
+
+ saveComponentState();
+
+ return true;
+}
+
+void QQmlCompiler::dumpStats()
+{
+ Q_ASSERT(componentStats);
+ qWarning().nospace() << "QML Document: " << output->url.toString();
+ for (int ii = 0; ii < componentStats->savedComponentStats.count(); ++ii) {
+ const ComponentStat &stat = componentStats->savedComponentStats.at(ii);
+ qWarning().nospace() << " Component Line " << stat.lineNumber;
+ qWarning().nospace() << " Total Objects: " << stat.objects;
+ qWarning().nospace() << " IDs Used: " << stat.ids;
+ qWarning().nospace() << " Optimized Bindings: " << stat.optimizedBindings.count();
+
+ {
+ QByteArray output;
+ for (int ii = 0; ii < stat.optimizedBindings.count(); ++ii) {
+ if (0 == (ii % 10)) {
+ if (ii) output.append("\n");
+ output.append(" ");
+ }
+
+ output.append("(");
+ output.append(QByteArray::number(stat.optimizedBindings.at(ii).start.line));
+ output.append(":");
+ output.append(QByteArray::number(stat.optimizedBindings.at(ii).start.column));
+ output.append(") ");
+ }
+ if (!output.isEmpty())
+ qWarning().nospace() << output.constData();
+ }
+
+ qWarning().nospace() << " QScript Bindings: " << stat.scriptBindings.count();
+ {
+ QByteArray output;
+ for (int ii = 0; ii < stat.scriptBindings.count(); ++ii) {
+ if (0 == (ii % 10)) {
+ if (ii) output.append("\n");
+ output.append(" ");
+ }
+
+ output.append("(");
+ output.append(QByteArray::number(stat.scriptBindings.at(ii).start.line));
+ output.append(":");
+ output.append(QByteArray::number(stat.scriptBindings.at(ii).start.column));
+ output.append(") ");
+ }
+ if (!output.isEmpty())
+ qWarning().nospace() << output.constData();
+ }
+ }
+}
+
+/*!
+ Returns true if from can be assigned to a (QObject) property of type
+ to.
+*/
+bool QQmlCompiler::canCoerce(int to, QQmlScript::Object *from)
+{
+ const QMetaObject *toMo = enginePrivate->rawMetaObjectForType(to);
+ const QMetaObject *fromMo = from->metaObject();
+
+ while (fromMo) {
+ if (QQmlPropertyPrivate::equal(fromMo, toMo))
+ return true;
+ fromMo = fromMo->superClass();
+ }
+ return false;
+}
+
+/*!
+ Returns the element name, as written in the QML file, for o.
+*/
+QString QQmlCompiler::elementName(QQmlScript::Object *o)
+{
+ Q_ASSERT(o);
+ if (o->type != -1) {
+ return output->types.at(o->type).className;
+ } else {
+ return QString();
+ }
+}
+
+QQmlType *QQmlCompiler::toQmlType(QQmlScript::Object *from)
+{
+ // ### Optimize
+ const QMetaObject *mo = from->metatype;
+ QQmlType *type = 0;
+ while (!type && mo) {
+ type = QQmlMetaType::qmlType(mo);
+ mo = mo->superClass();
+ }
+ return type;
+}
+
+QStringList QQmlCompiler::deferredProperties(QQmlScript::Object *obj)
+{
+ const QMetaObject *mo = obj->metatype;
+
+ int idx = mo->indexOfClassInfo("DeferredPropertyNames");
+ if (idx == -1)
+ return QStringList();
+
+ QMetaClassInfo classInfo = mo->classInfo(idx);
+ QStringList rv = QString::fromUtf8(classInfo.value()).split(QLatin1Char(','));
+ return rv;
+}
+
+QQmlPropertyData *
+QQmlCompiler::property(QQmlScript::Object *object, int index)
+{
+ QQmlPropertyCache *cache = 0;
+
+ if (object->synthCache)
+ cache = object->synthCache;
+ else if (object->type != -1)
+ cache = output->types[object->type].createPropertyCache(engine);
+ else
+ cache = QQmlEnginePrivate::get(engine)->cache(object->metaObject());
+
+ return cache->property(index);
+}
+
+QQmlPropertyData *
+QQmlCompiler::property(QQmlScript::Object *object, const QHashedStringRef &name, bool *notInRevision)
+{
+ if (notInRevision) *notInRevision = false;
+
+ QQmlPropertyCache *cache = 0;
+
+ if (object->synthCache)
+ cache = object->synthCache;
+ else if (object->type != -1)
+ cache = output->types[object->type].createPropertyCache(engine);
+ else
+ cache = QQmlEnginePrivate::get(engine)->cache(object->metaObject());
+
+ QQmlPropertyData *d = cache->property(name);
+
+ // Find the first property
+ while (d && d->isFunction())
+ d = cache->overrideData(d);
+
+ if (d && !cache->isAllowedInRevision(d)) {
+ if (notInRevision) *notInRevision = true;
+ return 0;
+ } else {
+ return d;
+ }
+}
+
+// This code must match the semantics of QQmlPropertyPrivate::findSignalByName
+QQmlPropertyData *
+QQmlCompiler::signal(QQmlScript::Object *object, const QHashedStringRef &name, bool *notInRevision)
+{
+ if (notInRevision) *notInRevision = false;
+
+ QQmlPropertyCache *cache = 0;
+
+ if (object->synthCache)
+ cache = object->synthCache;
+ else if (object->type != -1)
+ cache = output->types[object->type].createPropertyCache(engine);
+ else
+ cache = QQmlEnginePrivate::get(engine)->cache(object->metaObject());
+
+
+ QQmlPropertyData *d = cache->property(name);
+ if (notInRevision) *notInRevision = false;
+
+ while (d && !(d->isFunction()))
+ d = cache->overrideData(d);
+
+ if (d && !cache->isAllowedInRevision(d)) {
+ if (notInRevision) *notInRevision = true;
+ return 0;
+ } else if (d) {
+ return d;
+ }
+
+ if (name.endsWith(Changed_string)) {
+ QHashedStringRef propName = name.mid(0, name.length() - Changed_string.length());
+
+ d = property(object, propName, notInRevision);
+ if (d)
+ return cache->method(d->notifyIndex);
+ }
+
+ return 0;
+}
+
+// This code must match the semantics of QQmlPropertyPrivate::findSignalByName
+int QQmlCompiler::indexOfSignal(QQmlScript::Object *object, const QString &name,
+ bool *notInRevision)
+{
+ QQmlPropertyData *d = signal(object, QStringRef(&name), notInRevision);
+ return d?d->coreIndex:-1;
+}
+
+int QQmlCompiler::indexOfProperty(QQmlScript::Object *object, const QString &name,
+ bool *notInRevision)
+{
+ return indexOfProperty(object, QStringRef(&name), notInRevision);
+}
+
+int QQmlCompiler::indexOfProperty(QQmlScript::Object *object, const QHashedStringRef &name,
+ bool *notInRevision)
+{
+ QQmlPropertyData *d = property(object, name, notInRevision);
+ return d?d->coreIndex:-1;
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlcompiler_p.h b/src/qml/qml/qqmlcompiler_p.h
new file mode 100644
index 0000000000..9b13b7e63b
--- /dev/null
+++ b/src/qml/qml/qqmlcompiler_p.h
@@ -0,0 +1,466 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLCOMPILER_P_H
+#define QQMLCOMPILER_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qqml.h"
+#include "qqmlerror.h"
+#include <private/qv8_p.h>
+#include "qqmlinstruction_p.h"
+#include "qqmlscript_p.h"
+#include "qqmlengine_p.h"
+#include <private/qbitfield_p.h>
+#include "qqmlpropertycache_p.h"
+#include "qqmlintegercache_p.h"
+#include "qqmltypenamecache_p.h"
+#include "qqmltypeloader_p.h"
+
+#include <QtCore/qbytearray.h>
+#include <QtCore/qset.h>
+#include <QtCore/QCoreApplication>
+
+QT_BEGIN_NAMESPACE
+
+class QQmlEngine;
+class QQmlComponent;
+class QQmlContext;
+class QQmlContextData;
+
+class Q_AUTOTEST_EXPORT QQmlCompiledData : public QQmlRefCount,
+ public QQmlCleanup
+{
+public:
+ QQmlCompiledData(QQmlEngine *engine);
+ virtual ~QQmlCompiledData();
+
+ QQmlEngine *engine;
+
+ QString name;
+ QUrl url;
+ QQmlTypeNameCache *importCache;
+
+ struct TypeReference
+ {
+ TypeReference()
+ : type(0), typePropertyCache(0), component(0) {}
+
+ QString className;
+ QQmlType *type;
+ QQmlPropertyCache *typePropertyCache;
+ QQmlCompiledData *component;
+
+ const QMetaObject *metaObject() const;
+ QQmlPropertyCache *propertyCache() const;
+ QQmlPropertyCache *createPropertyCache(QQmlEngine *);
+ };
+ QList<TypeReference> types;
+
+ struct V8Program {
+ V8Program(const QByteArray &p, QQmlCompiledData *c)
+ : program(p), cdata(c) {}
+
+ QByteArray program;
+ v8::Persistent<v8::Array> bindings;
+ QQmlCompiledData *cdata;
+ };
+
+ QList<V8Program> programs;
+
+ const QMetaObject *root;
+ QAbstractDynamicMetaObject rootData;
+ QQmlPropertyCache *rootPropertyCache;
+ QList<QString> primitives;
+ QList<QByteArray> datas;
+ QByteArray bytecode;
+ QList<QQmlPropertyCache *> propertyCaches;
+ QList<QQmlIntegerCache *> contextCaches;
+ QList<QQmlScriptData *> scripts;
+ QList<QUrl> urls;
+
+ struct Instruction {
+#define QML_INSTR_DATA_TYPEDEF(I, FMT) typedef QQmlInstructionData<QQmlInstruction::I> I;
+ FOR_EACH_QML_INSTR(QML_INSTR_DATA_TYPEDEF)
+#undef QML_INSTR_DATA_TYPEDEF
+ private:
+ Instruction();
+ };
+
+ void dumpInstructions();
+
+ template <int Instr>
+ int addInstruction(const QQmlInstructionData<Instr> &data)
+ {
+ QQmlInstruction genericInstr;
+ QQmlInstructionMeta<Instr>::setData(genericInstr, data);
+ return addInstructionHelper(static_cast<QQmlInstruction::Type>(Instr), genericInstr);
+ }
+ int nextInstructionIndex();
+ QQmlInstruction *instruction(int index);
+ QQmlInstruction::Type instructionType(const QQmlInstruction *instr);
+
+ bool isInitialized() const { return hasEngine(); }
+ void initialize(QQmlEngine *);
+
+protected:
+ virtual void destroy(); // From QQmlRefCount
+ virtual void clear(); // From QQmlCleanup
+
+private:
+ friend class QQmlCompiler;
+
+ int addInstructionHelper(QQmlInstruction::Type type, QQmlInstruction &instr);
+ void dump(QQmlInstruction *, int idx = -1);
+ QQmlCompiledData(const QQmlCompiledData &other);
+ QQmlCompiledData &operator=(const QQmlCompiledData &other);
+ QByteArray packData;
+ int pack(const char *, size_t);
+
+ int indexForString(const QString &);
+ int indexForByteArray(const QByteArray &);
+ int indexForUrl(const QUrl &);
+};
+
+namespace QQmlCompilerTypes {
+ struct BindingContext
+ {
+ BindingContext()
+ : stack(0), owner(0), object(0) {}
+ BindingContext(QQmlScript::Object *o)
+ : stack(0), owner(0), object(o) {}
+ BindingContext incr() const {
+ BindingContext rv(object);
+ rv.stack = stack + 1;
+ return rv;
+ }
+ bool isSubContext() const { return stack != 0; }
+ int stack;
+ int owner;
+ QQmlScript::Object *object;
+ };
+
+ struct BindingReference
+ {
+ enum DataType { QtScript, V4, V8,
+ Tr, TrId };
+ DataType dataType;
+ };
+
+ struct JSBindingReference : public QQmlPool::Class,
+ public BindingReference
+ {
+ JSBindingReference() : nextReference(0) {}
+
+ QQmlScript::Variant expression;
+ QQmlScript::Property *property;
+ QQmlScript::Value *value;
+
+ int compiledIndex;
+
+ QString rewrittenExpression;
+ BindingContext bindingContext;
+
+ JSBindingReference *nextReference;
+ };
+
+ struct TrBindingReference : public QQmlPool::POD,
+ public BindingReference
+ {
+ QStringRef text;
+ QStringRef comment;
+ int n;
+ };
+
+ struct IdList : public QFieldList<QQmlScript::Object,
+ &QQmlScript::Object::nextIdObject>
+ {
+ QQmlScript::Object *value(const QString &id) const {
+ for (QQmlScript::Object *o = first(); o; o = next(o)) {
+ if (o->id == id)
+ return o;
+ }
+ return 0;
+ }
+ };
+
+ struct DepthStack {
+ DepthStack() : _depth(0), _maxDepth(0) {}
+ DepthStack(const DepthStack &o) : _depth(o._depth), _maxDepth(o._maxDepth) {}
+ DepthStack &operator=(const DepthStack &o) { _depth = o._depth; _maxDepth = o._maxDepth; return *this; }
+
+ int depth() const { return _depth; }
+ int maxDepth() const { return _maxDepth; }
+
+ void push() { ++_depth; _maxDepth = qMax(_depth, _maxDepth); }
+ void pop() { --_depth; Q_ASSERT(_depth >= 0); Q_ASSERT(_maxDepth > _depth); }
+
+ void pushPop(int count) { _maxDepth = qMax(_depth + count, _maxDepth); }
+ private:
+ int _depth;
+ int _maxDepth;
+ };
+
+ // Contains all the incremental compiler state about a component. As
+ // a single QML file can have multiple components defined, there may be
+ // more than one of these for each compile
+ struct ComponentCompileState : public QQmlPool::Class
+ {
+ ComponentCompileState()
+ : parserStatusCount(0), totalBindingsCount(0), pushedProperties(0), nested(false),
+ v8BindingProgramLine(-1), root(0) {}
+
+ IdList ids;
+ int parserStatusCount;
+ int totalBindingsCount;
+ int pushedProperties;
+ bool nested;
+
+ QByteArray compiledBindingData;
+ QByteArray v8BindingProgram;
+ int v8BindingProgramLine;
+
+ DepthStack objectDepth;
+ DepthStack listDepth;
+
+ typedef QQmlCompilerTypes::JSBindingReference B;
+ typedef QFieldList<B, &B::nextReference> JSBindingReferenceList;
+ JSBindingReferenceList bindings;
+ typedef QQmlScript::Object O;
+ typedef QFieldList<O, &O::nextAliasingObject> AliasingObjectsList;
+ AliasingObjectsList aliasingObjects;
+ QQmlScript::Object *root;
+ };
+};
+
+class QMetaObjectBuilder;
+class Q_AUTOTEST_EXPORT QQmlCompiler
+{
+ Q_DECLARE_TR_FUNCTIONS(QQmlCompiler)
+public:
+ QQmlCompiler(QQmlPool *);
+
+ bool compile(QQmlEngine *, QQmlTypeData *, QQmlCompiledData *);
+
+ bool isError() const;
+ QList<QQmlError> errors() const;
+
+ static bool isAttachedPropertyName(const QString &);
+ static bool isSignalPropertyName(const QString &);
+ static bool isAttachedPropertyName(const QHashedStringRef &);
+ static bool isSignalPropertyName(const QHashedStringRef &);
+
+ int evaluateEnum(const QByteArray& script) const; // for QQmlCustomParser::evaluateEnum
+ const QMetaObject *resolveType(const QString& name) const; // for QQmlCustomParser::resolveType
+ int rewriteBinding(const QQmlScript::Variant& value, const QString& name); // for QQmlCustomParser::rewriteBinding
+ QString rewriteSignalHandler(const QQmlScript::Variant& value, const QString &name); // for QQmlCustomParser::rewriteSignalHandler
+
+private:
+ typedef QQmlCompiledData::Instruction Instruction;
+
+ static void reset(QQmlCompiledData *);
+
+ void compileTree(QQmlScript::Object *tree);
+
+
+ bool buildObject(QQmlScript::Object *obj, const QQmlCompilerTypes::BindingContext &);
+ bool buildComponent(QQmlScript::Object *obj, const QQmlCompilerTypes::BindingContext &);
+ bool buildSubObject(QQmlScript::Object *obj, const QQmlCompilerTypes::BindingContext &);
+ bool buildSignal(QQmlScript::Property *prop, QQmlScript::Object *obj,
+ const QQmlCompilerTypes::BindingContext &);
+ bool buildProperty(QQmlScript::Property *prop, QQmlScript::Object *obj,
+ const QQmlCompilerTypes::BindingContext &);
+ bool buildPropertyInNamespace(QQmlImportedNamespace *ns,
+ QQmlScript::Property *prop,
+ QQmlScript::Object *obj,
+ const QQmlCompilerTypes::BindingContext &);
+ bool buildIdProperty(QQmlScript::Property *prop, QQmlScript::Object *obj);
+ bool buildAttachedProperty(QQmlScript::Property *prop,
+ QQmlScript::Object *obj,
+ const QQmlCompilerTypes::BindingContext &ctxt);
+ bool buildGroupedProperty(QQmlScript::Property *prop,
+ QQmlScript::Object *obj,
+ const QQmlCompilerTypes::BindingContext &ctxt);
+ bool buildValueTypeProperty(QObject *type,
+ QQmlScript::Object *obj,
+ QQmlScript::Object *baseObj,
+ const QQmlCompilerTypes::BindingContext &ctxt);
+ bool buildListProperty(QQmlScript::Property *prop,
+ QQmlScript::Object *obj,
+ const QQmlCompilerTypes::BindingContext &ctxt);
+ bool buildScriptStringProperty(QQmlScript::Property *prop,
+ QQmlScript::Object *obj,
+ const QQmlCompilerTypes::BindingContext &ctxt);
+ bool buildPropertyAssignment(QQmlScript::Property *prop,
+ QQmlScript::Object *obj,
+ const QQmlCompilerTypes::BindingContext &ctxt);
+ bool buildPropertyObjectAssignment(QQmlScript::Property *prop,
+ QQmlScript::Object *obj,
+ QQmlScript::Value *value,
+ const QQmlCompilerTypes::BindingContext &ctxt);
+ bool buildPropertyOnAssignment(QQmlScript::Property *prop,
+ QQmlScript::Object *obj,
+ QQmlScript::Object *baseObj,
+ QQmlScript::Value *value,
+ const QQmlCompilerTypes::BindingContext &ctxt);
+ bool buildPropertyLiteralAssignment(QQmlScript::Property *prop,
+ QQmlScript::Object *obj,
+ QQmlScript::Value *value,
+ const QQmlCompilerTypes::BindingContext &ctxt);
+ bool doesPropertyExist(QQmlScript::Property *prop, QQmlScript::Object *obj);
+ bool testLiteralAssignment(QQmlScript::Property *prop,
+ QQmlScript::Value *value);
+ bool testQualifiedEnumAssignment(QQmlScript::Property *prop,
+ QQmlScript::Object *obj,
+ QQmlScript::Value *value,
+ bool *isAssignment);
+ enum DynamicMetaMode { IgnoreAliases, ResolveAliases, ForceCreation };
+ bool mergeDynamicMetaProperties(QQmlScript::Object *obj);
+ bool buildDynamicMeta(QQmlScript::Object *obj, DynamicMetaMode mode);
+ bool checkDynamicMeta(QQmlScript::Object *obj);
+ bool buildBinding(QQmlScript::Value *, QQmlScript::Property *prop,
+ const QQmlCompilerTypes::BindingContext &ctxt);
+ bool buildLiteralBinding(QQmlScript::Value *, QQmlScript::Property *prop,
+ const QQmlCompilerTypes::BindingContext &ctxt);
+ bool buildComponentFromRoot(QQmlScript::Object *obj, const QQmlCompilerTypes::BindingContext &);
+ bool compileAlias(QFastMetaBuilder &,
+ QByteArray &data,
+ QQmlScript::Object *obj,
+ int propIndex, int aliasIndex,
+ QQmlScript::Object::DynamicProperty &);
+ bool completeComponentBuild();
+ bool checkValidId(QQmlScript::Value *, const QString &);
+
+
+ void genObject(QQmlScript::Object *obj);
+ void genObjectBody(QQmlScript::Object *obj);
+ void genValueTypeProperty(QQmlScript::Object *obj,QQmlScript::Property *);
+ void genComponent(QQmlScript::Object *obj);
+ void genValueProperty(QQmlScript::Property *prop, QQmlScript::Object *obj);
+ void genListProperty(QQmlScript::Property *prop, QQmlScript::Object *obj);
+ void genPropertyAssignment(QQmlScript::Property *prop,
+ QQmlScript::Object *obj,
+ QQmlScript::Property *valueTypeProperty = 0);
+ void genLiteralAssignment(QQmlScript::Property *prop,
+ QQmlScript::Value *value);
+ void genBindingAssignment(QQmlScript::Value *binding,
+ QQmlScript::Property *prop,
+ QQmlScript::Object *obj,
+ QQmlScript::Property *valueTypeProperty = 0);
+ int genContextCache();
+
+ QQmlPropertyData genValueTypeData(QQmlScript::Property *prop,
+ QQmlScript::Property *valueTypeProp);
+
+ int componentTypeRef();
+ int translationContextIndex();
+
+ static QQmlType *toQmlType(QQmlScript::Object *from);
+ bool canCoerce(int to, QQmlScript::Object *from);
+
+ QString elementName(QQmlScript::Object *);
+
+ QStringList deferredProperties(QQmlScript::Object *);
+
+ QQmlPropertyData *property(QQmlScript::Object *, int);
+ QQmlPropertyData *property(QQmlScript::Object *, const QHashedStringRef &,
+ bool *notInRevision = 0);
+ QQmlPropertyData *signal(QQmlScript::Object *, const QHashedStringRef &,
+ bool *notInRevision = 0);
+ int indexOfProperty(QQmlScript::Object *, const QHashedStringRef &, bool *notInRevision = 0);
+ int indexOfProperty(QQmlScript::Object *, const QString &, bool *notInRevision = 0);
+ int indexOfSignal(QQmlScript::Object *, const QString &, bool *notInRevision = 0);
+
+ void addId(const QString &, QQmlScript::Object *);
+
+ void dumpStats();
+
+ void addBindingReference(QQmlCompilerTypes::JSBindingReference *);
+
+ QQmlCompilerTypes::ComponentCompileState *compileState;
+
+ QQmlPool *pool;
+
+ QQmlCompilerTypes::ComponentCompileState *componentState(QQmlScript::Object *);
+ void saveComponentState();
+
+ QList<QQmlError> exceptions;
+ QQmlCompiledData *output;
+ QQmlEngine *engine;
+ QQmlEnginePrivate *enginePrivate;
+ QQmlScript::Object *unitRoot;
+ QQmlTypeData *unit;
+ int cachedComponentTypeRef;
+ int cachedTranslationContextIndex;
+
+ // Compiler component statistics. Only collected if QML_COMPILER_STATS=1
+ struct ComponentStat
+ {
+ ComponentStat() : ids(0), objects(0) {}
+
+ int lineNumber;
+
+ int ids;
+ QList<QQmlScript::LocationSpan> scriptBindings;
+ QList<QQmlScript::LocationSpan> optimizedBindings;
+ int objects;
+ };
+ struct ComponentStats : public QQmlPool::Class
+ {
+ ComponentStat componentStat;
+ QList<ComponentStat> savedComponentStats;
+ };
+ ComponentStats *componentStats;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQMLCOMPILER_P_H
diff --git a/src/qml/qml/qqmlcomponent.cpp b/src/qml/qml/qqmlcomponent.cpp
new file mode 100644
index 0000000000..e168f063c0
--- /dev/null
+++ b/src/qml/qml/qqmlcomponent.cpp
@@ -0,0 +1,1350 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qqmlcomponent.h"
+#include "qqmlcomponent_p.h"
+#include "qqmlcomponentattached_p.h"
+
+#include "qqmlcompiler_p.h"
+#include "qqmlcontext_p.h"
+#include "qqmlengine_p.h"
+#include "qqmlvme_p.h"
+#include "qqml.h"
+#include "qqmlengine.h"
+#include "qqmlbinding_p.h"
+#include "qqmlbinding_p_p.h"
+#include "qqmlscript_p.h"
+#include <private/qqmlprofilerservice_p.h>
+#include <private/qqmlenginedebugservice_p.h>
+#include "qqmlincubator.h"
+#include "qqmlincubator_p.h"
+
+#include <private/qv8engine_p.h>
+#include <private/qv8include_p.h>
+
+#include <QStack>
+#include <QStringList>
+#include <QtCore/qdebug.h>
+#include <qqmlinfo.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQmlComponentExtension : public QV8Engine::Deletable
+{
+public:
+ QQmlComponentExtension(QV8Engine *);
+ virtual ~QQmlComponentExtension();
+
+ v8::Persistent<v8::Function> incubationConstructor;
+ v8::Persistent<v8::Script> initialProperties;
+ v8::Persistent<v8::Function> forceCompletion;
+};
+V8_DEFINE_EXTENSION(QQmlComponentExtension, componentExtension);
+
+/*
+ Try to do what's necessary for a reasonable display of the type
+ name, but no more (just enough for the client to do more extensive cleanup).
+
+ Should only be called when debugging is enabled.
+*/
+static inline QString buildTypeNameForDebug(const QMetaObject *metaObject)
+{
+ static const QString qmlMarker(QLatin1String("_QML"));
+ static const QChar underscore(QLatin1Char('_'));
+ static const QChar asterisk(QLatin1Char('*'));
+ QQmlType *type = QQmlMetaType::qmlType(metaObject);
+ QString typeName = type ? type->qmlTypeName() : QString::fromUtf8(metaObject->className());
+ if (!type) {
+ //### optimize further?
+ int marker = typeName.indexOf(qmlMarker);
+ if (marker != -1 && marker < typeName.count() - 1) {
+ if (typeName[marker + 1] == underscore) {
+ const QString className = typeName.left(marker) + asterisk;
+ type = QQmlMetaType::qmlType(QMetaType::type(className.toUtf8()));
+ if (type)
+ typeName = type->qmlTypeName();
+ }
+ }
+ }
+ return typeName;
+}
+
+/*!
+ \class QQmlComponent
+ \since 4.7
+ \brief The QQmlComponent class encapsulates a QML component definition.
+ \mainclass
+
+ Components are reusable, encapsulated QML elements with well-defined interfaces.
+ They are often defined in \l {qdeclarativedocuments.html}{Component Files}.
+
+ A QQmlComponent instance can be created from a QML file.
+ For example, if there is a \c main.qml file like this:
+
+ \qml
+ import QtQuick 2.0
+
+ Item {
+ width: 200
+ height: 200
+ }
+ \endqml
+
+ The following code loads this QML file as a component, creates an instance of
+ this component using create(), and then queries the \l Item's \l {Item::}{width}
+ value:
+
+ \code
+ QQmlEngine *engine = new QQmlEngine;
+ QQmlComponent component(engine, QUrl::fromLocalFile("main.qml"));
+
+ QObject *myObject = component.create();
+ QQuickItem *item = qobject_cast<QQuickItem*>(myObject);
+ int width = item->width(); // width = 200
+ \endcode
+
+
+ \section2 Network Components
+
+ If the URL passed to QQmlComponent is a network resource, or if the QML document references a
+ network resource, the QQmlComponent has to fetch the network data before it is able to create
+ objects. In this case, the QQmlComponent will have a \l {QQmlComponent::Loading}{Loading}
+ \l {QQmlComponent::status()}{status}. An application will have to wait until the component
+ is \l {QQmlComponent::Ready}{Ready} before calling \l {QQmlComponent::create()}.
+
+ The following example shows how to load a QML file from a network resource. After creating
+ the QQmlComponent, it tests whether the component is loading. If it is, it connects to the
+ QQmlComponent::statusChanged() signal and otherwise calls the \c {continueLoading()} method
+ directly. Note that QQmlComponent::isLoading() may be false for a network component if the
+ component has been cached and is ready immediately.
+
+ \code
+ MyApplication::MyApplication()
+ {
+ // ...
+ component = new QQmlComponent(engine, QUrl("http://www.example.com/main.qml"));
+ if (component->isLoading())
+ QObject::connect(component, SIGNAL(statusChanged(QQmlComponent::Status)),
+ this, SLOT(continueLoading()));
+ else
+ continueLoading();
+ }
+
+ void MyApplication::continueLoading()
+ {
+ if (component->isError()) {
+ qWarning() << component->errors();
+ } else {
+ QObject *myObject = component->create();
+ }
+ }
+ \endcode
+
+ \sa {Using QML Bindings in C++ Applications}, {Integrating QML Code with Existing Qt UI Code}
+*/
+
+/*!
+ \qmlclass Component QQmlComponent
+ \ingroup qml-utility-elements
+ \since 4.7
+ \brief The Component element encapsulates a QML component definition.
+
+ Components are reusable, encapsulated QML elements with well-defined interfaces.
+
+ Components are often defined by \l {qdeclarativedocuments.html}{component files} -
+ that is, \c .qml files. The \e Component element essentially allows QML components
+ to be defined inline, within a \l {QML Document}{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.
+
+ For example, here is a component that is used by multiple \l Loader objects.
+ It contains a single item, a \l Rectangle:
+
+ \snippet doc/src/snippets/qml/component.qml 0
+
+ Notice that while a \l Rectangle by itself would be automatically
+ rendered and displayed, this is not the case for the above rectangle
+ because it is defined inside a \c Component. The component encapsulates the
+ QML elements within, as if they were defined in a separate QML
+ file, and is not loaded until requested (in this case, by the
+ two \l Loader objects).
+
+ Defining a \c Component is similar to defining a \l {QML Document}{QML document}.
+ A QML document has a single top-level item that defines the behaviors and
+ properties of that component, and cannot define properties or behaviors outside
+ of that top-level item. In the same way, a \c Component definition contains a single
+ top level item (which in the above example is a \l Rectangle) and cannot define any
+ data outside of this item, with the exception of an \e id (which in the above example
+ is \e redSquare).
+
+ The \c Component element is commonly used to provide graphical components
+ for views. For example, the ListView::delegate property requires a \c Component
+ to specify how each list item is to be displayed.
+
+ \c Component objects can also be created dynamically using
+ \l{QML:Qt::createComponent()}{Qt.createComponent()}.
+*/
+
+/*!
+ \qmlattachedsignal Component::onCompleted()
+
+ Emitted after component "startup" has completed. This can be used to
+ execute script code at startup, once the full QML environment has been
+ established.
+
+ The \c {Component::onCompleted} attached property can be applied to
+ any element. The order of running the \c onCompleted scripts is
+ undefined.
+
+ \qml
+ Rectangle {
+ Component.onCompleted: console.log("Completed Running!")
+ Rectangle {
+ Component.onCompleted: console.log("Nested Completed Running!")
+ }
+ }
+ \endqml
+*/
+
+/*!
+ \qmlattachedsignal Component::onDestruction()
+
+ Emitted as the component begins destruction. This can be used to undo
+ work done in the onCompleted signal, or other imperative code in your
+ application.
+
+ The \c {Component::onDestruction} attached property can be applied to
+ any element. However, it applies to the destruction of the component as
+ a whole, and not the destruction of the specific object. The order of
+ running the \c onDestruction scripts is undefined.
+
+ \qml
+ Rectangle {
+ Component.onDestruction: console.log("Destruction Beginning!")
+ Rectangle {
+ Component.onDestruction: console.log("Nested Destruction Beginning!")
+ }
+ }
+ \endqml
+
+ \sa QtQml
+*/
+
+/*!
+ \enum QQmlComponent::Status
+
+ Specifies the loading status of the QQmlComponent.
+
+ \value Null This QQmlComponent has no data. Call loadUrl() or setData() to add QML content.
+ \value Ready This QQmlComponent is ready and create() may be called.
+ \value Loading This QQmlComponent is loading network data.
+ \value Error An error has occurred. Call errors() to retrieve a list of \{QQmlError}{errors}.
+*/
+
+void QQmlComponentPrivate::typeDataReady(QQmlTypeData *)
+{
+ Q_Q(QQmlComponent);
+
+ Q_ASSERT(typeData);
+
+ fromTypeData(typeData);
+ typeData = 0;
+
+ emit q->statusChanged(q->status());
+}
+
+void QQmlComponentPrivate::typeDataProgress(QQmlTypeData *, qreal p)
+{
+ Q_Q(QQmlComponent);
+
+ progress = p;
+
+ emit q->progressChanged(p);
+}
+
+void QQmlComponentPrivate::fromTypeData(QQmlTypeData *data)
+{
+ url = data->finalUrl();
+ QQmlCompiledData *c = data->compiledData();
+
+ if (!c) {
+ Q_ASSERT(data->isError());
+ state.errors = data->errors();
+ } else {
+ cc = c;
+ }
+
+ data->release();
+}
+
+void QQmlComponentPrivate::clear()
+{
+ if (typeData) {
+ typeData->unregisterCallback(this);
+ typeData->release();
+ typeData = 0;
+ }
+
+ if (cc) {
+ cc->release();
+ cc = 0;
+ }
+}
+
+/*!
+ \internal
+*/
+QQmlComponent::QQmlComponent(QObject *parent)
+ : QObject(*(new QQmlComponentPrivate), parent)
+{
+}
+
+/*!
+ Destruct the QQmlComponent.
+*/
+QQmlComponent::~QQmlComponent()
+{
+ Q_D(QQmlComponent);
+
+ if (d->state.completePending) {
+ qWarning("QQmlComponent: Component destroyed while completion pending");
+ d->completeCreate();
+ }
+
+ if (d->typeData) {
+ d->typeData->unregisterCallback(d);
+ d->typeData->release();
+ }
+ if (d->cc)
+ d->cc->release();
+}
+
+/*!
+ \qmlproperty enumeration Component::status
+ This property holds the status of component loading. It can be one of:
+ \list
+ \o Component.Null - no data is available for the component
+ \o Component.Ready - the component has been loaded, and can be used to create instances.
+ \o Component.Loading - the component is currently being loaded
+ \o Component.Error - an error occurred while loading the component.
+ Calling errorString() will provide a human-readable description of any errors.
+ \endlist
+ */
+
+/*!
+ \property QQmlComponent::status
+ The component's current \l{QQmlComponent::Status} {status}.
+ */
+QQmlComponent::Status QQmlComponent::status() const
+{
+ Q_D(const QQmlComponent);
+
+ if (d->typeData)
+ return Loading;
+ else if (!d->state.errors.isEmpty())
+ return Error;
+ else if (d->engine && d->cc)
+ return Ready;
+ else
+ return Null;
+}
+
+/*!
+ Returns true if status() == QQmlComponent::Null.
+*/
+bool QQmlComponent::isNull() const
+{
+ return status() == Null;
+}
+
+/*!
+ Returns true if status() == QQmlComponent::Ready.
+*/
+bool QQmlComponent::isReady() const
+{
+ return status() == Ready;
+}
+
+/*!
+ Returns true if status() == QQmlComponent::Error.
+*/
+bool QQmlComponent::isError() const
+{
+ return status() == Error;
+}
+
+/*!
+ Returns true if status() == QQmlComponent::Loading.
+*/
+bool QQmlComponent::isLoading() const
+{
+ return status() == Loading;
+}
+
+/*!
+ \qmlproperty real Component::progress
+ The progress of loading the component, from 0.0 (nothing loaded)
+ to 1.0 (finished).
+*/
+
+/*!
+ \property QQmlComponent::progress
+ The progress of loading the component, from 0.0 (nothing loaded)
+ to 1.0 (finished).
+*/
+qreal QQmlComponent::progress() const
+{
+ Q_D(const QQmlComponent);
+ return d->progress;
+}
+
+/*!
+ \fn void QQmlComponent::progressChanged(qreal progress)
+
+ Emitted whenever the component's loading progress changes. \a progress will be the
+ current progress between 0.0 (nothing loaded) and 1.0 (finished).
+*/
+
+/*!
+ \fn void QQmlComponent::statusChanged(QQmlComponent::Status status)
+
+ Emitted whenever the component's status changes. \a status will be the
+ new status.
+*/
+
+/*!
+ Create a QQmlComponent with no data and give it the specified
+ \a engine and \a parent. Set the data with setData().
+*/
+QQmlComponent::QQmlComponent(QQmlEngine *engine, QObject *parent)
+ : QObject(*(new QQmlComponentPrivate), parent)
+{
+ Q_D(QQmlComponent);
+ d->engine = engine;
+}
+
+/*!
+ Create a QQmlComponent from the given \a url and give it the
+ specified \a parent and \a engine.
+
+ Ensure that the URL provided is full and correct, in particular, use
+ \l QUrl::fromLocalFile() when loading a file from the local filesystem.
+
+ \sa loadUrl()
+*/
+QQmlComponent::QQmlComponent(QQmlEngine *engine, const QUrl &url, QObject *parent)
+: QObject(*(new QQmlComponentPrivate), parent)
+{
+ Q_D(QQmlComponent);
+ d->engine = engine;
+ loadUrl(url);
+}
+
+/*!
+ Create a QQmlComponent from the given \a fileName and give it the specified
+ \a parent and \a engine.
+
+ \sa loadUrl()
+*/
+QQmlComponent::QQmlComponent(QQmlEngine *engine, const QString &fileName,
+ QObject *parent)
+: QObject(*(new QQmlComponentPrivate), parent)
+{
+ Q_D(QQmlComponent);
+ d->engine = engine;
+ loadUrl(d->engine->baseUrl().resolved(QUrl::fromLocalFile(fileName)));
+}
+
+/*!
+ \internal
+*/
+QQmlComponent::QQmlComponent(QQmlEngine *engine, QQmlCompiledData *cc, int start, QObject *parent)
+ : QObject(*(new QQmlComponentPrivate), parent)
+{
+ Q_D(QQmlComponent);
+ d->engine = engine;
+ d->cc = cc;
+ cc->addref();
+ d->start = start;
+ d->url = cc->url;
+ d->progress = 1.0;
+}
+
+/*!
+ Sets the QQmlComponent to use the given QML \a data. If \a url
+ is provided, it is used to set the component name and to provide
+ a base path for items resolved by this component.
+*/
+void QQmlComponent::setData(const QByteArray &data, const QUrl &url)
+{
+ Q_D(QQmlComponent);
+
+ d->clear();
+
+ d->url = url;
+
+ QQmlTypeData *typeData = QQmlEnginePrivate::get(d->engine)->typeLoader.get(data, url);
+
+ if (typeData->isCompleteOrError()) {
+ d->fromTypeData(typeData);
+ } else {
+ d->typeData = typeData;
+ d->typeData->registerCallback(d);
+ }
+
+ d->progress = 1.0;
+ emit statusChanged(status());
+ emit progressChanged(d->progress);
+}
+
+/*!
+Returns the QQmlContext the component was created in. This is only
+valid for components created directly from QML.
+*/
+QQmlContext *QQmlComponent::creationContext() const
+{
+ Q_D(const QQmlComponent);
+ if(d->creationContext)
+ return d->creationContext->asQQmlContext();
+
+ return qmlContext(this);
+}
+
+/*!
+ Load the QQmlComponent from the provided \a url.
+
+ Ensure that the URL provided is full and correct, in particular, use
+ \l QUrl::fromLocalFile() when loading a file from the local filesystem.
+*/
+void QQmlComponent::loadUrl(const QUrl &url)
+{
+ Q_D(QQmlComponent);
+
+ d->clear();
+
+ if ((url.isRelative() && !url.isEmpty())
+ || url.scheme() == QLatin1String("file")) // Workaround QTBUG-11929
+ d->url = d->engine->baseUrl().resolved(url);
+ else
+ d->url = url;
+
+ if (url.isEmpty()) {
+ QQmlError error;
+ error.setDescription(tr("Invalid empty URL"));
+ d->state.errors << error;
+ return;
+ }
+
+ QQmlTypeData *data = QQmlEnginePrivate::get(d->engine)->typeLoader.get(d->url);
+
+ if (data->isCompleteOrError()) {
+ d->fromTypeData(data);
+ d->progress = 1.0;
+ } else {
+ d->typeData = data;
+ d->typeData->registerCallback(d);
+ d->progress = data->progress();
+ }
+
+ emit statusChanged(status());
+ emit progressChanged(d->progress);
+}
+
+/*!
+ Return the list of errors that occurred during the last compile or create
+ operation. An empty list is returned if isError() is not set.
+*/
+QList<QQmlError> QQmlComponent::errors() const
+{
+ Q_D(const QQmlComponent);
+ if (isError())
+ return d->state.errors;
+ else
+ return QList<QQmlError>();
+}
+
+/*!
+ \qmlmethod string Component::errorString()
+
+ Returns a human-readable description of any errors.
+
+ The string includes the file, location, and description of each error.
+ If multiple errors are present they are separated by a newline character.
+
+ If no errors are present, an empty string is returned.
+*/
+
+/*!
+ \internal
+ errorString is only meant as a way to get the errors in script
+*/
+QString QQmlComponent::errorString() const
+{
+ Q_D(const QQmlComponent);
+ QString ret;
+ if(!isError())
+ return ret;
+ foreach(const QQmlError &e, d->state.errors) {
+ ret += e.url().toString() + QLatin1Char(':') +
+ QString::number(e.line()) + QLatin1Char(' ') +
+ e.description() + QLatin1Char('\n');
+ }
+ return ret;
+}
+
+/*!
+ \qmlproperty url Component::url
+ The component URL. This is the URL that was used to construct the component.
+*/
+
+/*!
+ \property QQmlComponent::url
+ The component URL. This is the URL passed to either the constructor,
+ or the loadUrl() or setData() methods.
+*/
+QUrl QQmlComponent::url() const
+{
+ Q_D(const QQmlComponent);
+ return d->url;
+}
+
+/*!
+ \internal
+*/
+QQmlComponent::QQmlComponent(QQmlComponentPrivate &dd, QObject *parent)
+ : QObject(dd, parent)
+{
+}
+
+/*!
+ Create an object instance from this component. Returns 0 if creation
+ failed. \a context specifies the context within which to create the object
+ instance.
+
+ If \a context is 0 (the default), it will create the instance in the
+ engine' s \l {QQmlEngine::rootContext()}{root context}.
+*/
+QObject *QQmlComponent::create(QQmlContext *context)
+{
+ Q_D(QQmlComponent);
+
+ if (!context)
+ context = d->engine->rootContext();
+
+ QObject *rv = beginCreate(context);
+ completeCreate();
+ return rv;
+}
+
+/*!
+ This method provides more advanced control over component instance creation.
+ In general, programmers should use QQmlComponent::create() to create a
+ component.
+
+ Create an object instance from this component. Returns 0 if creation
+ failed. \a publicContext specifies the context within which to create the object
+ instance.
+
+ When QQmlComponent constructs an instance, it occurs in three steps:
+ \list 1
+ \i The object hierarchy is created, and constant values are assigned.
+ \i Property bindings are evaluated for the the first time.
+ \i If applicable, QQmlParserStatus::componentComplete() is called on objects.
+ \endlist
+ QQmlComponent::beginCreate() differs from QQmlComponent::create() in that it
+ only performs step 1. QQmlComponent::completeCreate() must be called to
+ complete steps 2 and 3.
+
+ This breaking point is sometimes useful when using attached properties to
+ communicate information to an instantiated component, as it allows their
+ initial values to be configured before property bindings take effect.
+*/
+QObject *QQmlComponent::beginCreate(QQmlContext *publicContext)
+{
+ Q_D(QQmlComponent);
+
+ Q_ASSERT(publicContext);
+ QQmlContextData *context = QQmlContextData::get(publicContext);
+
+ return d->beginCreate(context);
+}
+
+QObject *
+QQmlComponentPrivate::beginCreate(QQmlContextData *context)
+{
+ Q_Q(QQmlComponent);
+ if (!context) {
+ qWarning("QQmlComponent: Cannot create a component in a null context");
+ return 0;
+ }
+
+ if (!context->isValid()) {
+ qWarning("QQmlComponent: Cannot create a component in an invalid context");
+ return 0;
+ }
+
+ if (context->engine != engine) {
+ qWarning("QQmlComponent: Must create component in context from the same QQmlEngine");
+ return 0;
+ }
+
+ if (state.completePending) {
+ qWarning("QQmlComponent: Cannot create new component instance before completing the previous");
+ return 0;
+ }
+
+ if (!q->isReady()) {
+ qWarning("QQmlComponent: Component is not ready");
+ return 0;
+ }
+
+ QQmlEnginePrivate *enginePriv = QQmlEnginePrivate::get(engine);
+
+ bool isRoot = enginePriv->inProgressCreations == 0;
+ enginePriv->inProgressCreations++;
+ state.errors.clear();
+ state.completePending = true;
+
+ if (isRoot)
+ QQmlProfilerService::startRange(QQmlProfilerService::Creating);
+
+ enginePriv->referenceScarceResources();
+ state.vme.init(context, cc, start, creationContext);
+ QObject *rv = state.vme.execute(&state.errors);
+ enginePriv->dereferenceScarceResources();
+
+ if (rv) {
+ QQmlData *ddata = QQmlData::get(rv);
+ Q_ASSERT(ddata);
+ ddata->indestructible = true;
+ }
+
+ if (enginePriv->isDebugging && rv) {
+ if (!context->isInternal)
+ context->asQQmlContextPrivate()->instances.append(rv);
+ QQmlEngineDebugService::instance()->objectCreated(engine, rv);
+ if (isRoot) {
+ QQmlProfilerService::rangeData(QQmlProfilerService::Creating,
+ buildTypeNameForDebug(rv->metaObject()));
+ QQmlData *data = QQmlData::get(rv);
+ Q_ASSERT(data);
+ QQmlProfilerService::rangeLocation(QQmlProfilerService::Creating,
+ cc->url, data->lineNumber, data->columnNumber);
+ }
+ }
+
+ return rv;
+}
+
+void QQmlComponentPrivate::beginDeferred(QQmlEnginePrivate *enginePriv,
+ QObject *object, ConstructionState *state)
+{
+ enginePriv->inProgressCreations++;
+ state->errors.clear();
+ state->completePending = true;
+
+ state->vme.initDeferred(object);
+ state->vme.execute(&state->errors);
+}
+
+void QQmlComponentPrivate::complete(QQmlEnginePrivate *enginePriv, ConstructionState *state)
+{
+ if (state->completePending) {
+ state->vme.complete();
+
+ state->completePending = false;
+
+ enginePriv->inProgressCreations--;
+
+ if (0 == enginePriv->inProgressCreations) {
+ while (enginePriv->erroredBindings) {
+ enginePriv->warning(enginePriv->erroredBindings->error);
+ enginePriv->erroredBindings->removeError();
+ }
+ }
+ }
+}
+
+/*!
+ This method provides more advanced control over component instance creation.
+ In general, programmers should use QQmlComponent::create() to create a
+ component.
+
+ Complete a component creation begin with QQmlComponent::beginCreate().
+*/
+void QQmlComponent::completeCreate()
+{
+ Q_D(QQmlComponent);
+
+ d->completeCreate();
+}
+
+void QQmlComponentPrivate::completeCreate()
+{
+ if (state.completePending) {
+ QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine);
+ complete(ep, &state);
+
+ QQmlProfilerService::endRange(QQmlProfilerService::Creating);
+ }
+}
+
+QQmlComponentAttached::QQmlComponentAttached(QObject *parent)
+: QObject(parent), prev(0), next(0)
+{
+}
+
+QQmlComponentAttached::~QQmlComponentAttached()
+{
+ if (prev) *prev = next;
+ if (next) next->prev = prev;
+ prev = 0;
+ next = 0;
+}
+
+/*!
+ \internal
+*/
+QQmlComponentAttached *QQmlComponent::qmlAttachedProperties(QObject *obj)
+{
+ QQmlComponentAttached *a = new QQmlComponentAttached(obj);
+
+ QQmlEngine *engine = qmlEngine(obj);
+ if (!engine)
+ return a;
+
+ if (QQmlEnginePrivate::get(engine)->activeVME) { // XXX should only be allowed during begin
+ QQmlEnginePrivate *p = QQmlEnginePrivate::get(engine);
+ a->add(&p->activeVME->componentAttached);
+ } else {
+ QQmlData *d = QQmlData::get(obj);
+ Q_ASSERT(d);
+ Q_ASSERT(d->context);
+ a->add(&d->context->componentAttached);
+ }
+
+ return a;
+}
+
+void QQmlComponent::create(QQmlIncubator &i, QQmlContext *context,
+ QQmlContext *forContext)
+{
+ Q_D(QQmlComponent);
+
+ if (!context)
+ context = d->engine->rootContext();
+
+ QQmlContextData *contextData = QQmlContextData::get(context);
+ QQmlContextData *forContextData = contextData;
+ if (forContext) forContextData = QQmlContextData::get(forContext);
+
+ if (!contextData->isValid()) {
+ qWarning("QQmlComponent: Cannot create a component in an invalid context");
+ return;
+ }
+
+ if (contextData->engine != d->engine) {
+ qWarning("QQmlComponent: Must create component in context from the same QQmlEngine");
+ return;
+ }
+
+ if (!isReady()) {
+ qWarning("QQmlComponent: Component is not ready");
+ return;
+ }
+
+ i.clear();
+ QQmlIncubatorPrivate *p = i.d;
+
+ QQmlEnginePrivate *enginePriv = QQmlEnginePrivate::get(d->engine);
+
+ p->component = d->cc; p->component->addref();
+ p->vme.init(contextData, d->cc, d->start, d->creationContext);
+
+ enginePriv->incubate(i, forContextData);
+}
+
+class QV8IncubatorResource : public QV8ObjectResource,
+ public QQmlIncubator
+{
+V8_RESOURCE_TYPE(IncubatorType)
+public:
+ QV8IncubatorResource(QV8Engine *engine, IncubationMode = Asynchronous);
+
+ static v8::Handle<v8::Value> StatusChangedGetter(v8::Local<v8::String>,
+ const v8::AccessorInfo& info);
+ static v8::Handle<v8::Value> StatusGetter(v8::Local<v8::String>,
+ const v8::AccessorInfo& info);
+ static v8::Handle<v8::Value> ObjectGetter(v8::Local<v8::String>,
+ const v8::AccessorInfo& info);
+ static v8::Handle<v8::Value> ForceCompletionGetter(v8::Local<v8::String>,
+ const v8::AccessorInfo& info);
+ static v8::Handle<v8::Value> ForceCompletion(const v8::Arguments &args);
+
+ static void StatusChangedSetter(v8::Local<v8::String>, v8::Local<v8::Value> value,
+ const v8::AccessorInfo& info);
+
+ void dispose();
+
+ v8::Persistent<v8::Object> me;
+ QQmlGuard<QObject> parent;
+ v8::Persistent<v8::Value> valuemap;
+ v8::Persistent<v8::Object> qmlGlobal;
+protected:
+ virtual void statusChanged(Status);
+ virtual void setInitialState(QObject *);
+};
+
+static void QQmlComponent_setQmlParent(QObject *me, QObject *parent)
+{
+ if (parent) {
+ me->setParent(parent);
+ typedef QQmlPrivate::AutoParentFunction APF;
+ QList<APF> functions = QQmlMetaType::parentFunctions();
+
+ bool needParent = false;
+ for (int ii = 0; ii < functions.count(); ++ii) {
+ QQmlPrivate::AutoParentResult res = functions.at(ii)(me, parent);
+ if (res == QQmlPrivate::Parented) {
+ needParent = false;
+ break;
+ } else if (res == QQmlPrivate::IncompatibleParent) {
+ needParent = true;
+ }
+ }
+ if (needParent)
+ qWarning("QQmlComponent: Created graphical object was not "
+ "placed in the graphics scene.");
+ }
+}
+
+/*!
+ \qmlmethod object Component::createObject(Item parent, object properties)
+
+ Creates and returns an object instance of this component that will have
+ the given \a parent and \a properties. The \a properties argument is optional.
+ Returns null if object creation fails.
+
+ The object will be created in the same context as the one in which the component
+ was created. This function will always return null when called on components
+ which were not created in QML.
+
+ If you wish to create an object without setting a parent, specify \c null for
+ the \a parent value. Note that if the returned object is to be displayed, you
+ must provide a valid \a parent value or set the returned object's \l{Item::parent}{parent}
+ property, or else the object will not be visible.
+
+ If a \a parent is not provided to createObject(), a reference to the returned object must be held so that
+ it is not destroyed by the garbage collector. This is true regardless of whether \l{Item::parent} is set afterwards,
+ since setting the Item parent does not change object ownership; only the graphical parent is changed.
+
+ As of QtQuick 1.1, this method accepts an optional \a properties argument that specifies a
+ map of initial property values for the created object. These values are applied before object
+ creation is finalized. (This is more efficient than setting property values after object creation,
+ particularly where large sets of property values are defined, and also allows property bindings
+ to be set up before the object is created.)
+
+ The \a properties argument is specified as a map of property-value items. For example, the code
+ below creates an object with initial \c x and \c y values of 100 and 200, respectively:
+
+ \js
+ var component = Qt.createComponent("Button.qml");
+ if (component.status == Component.Ready)
+ component.createObject(parent, {"x": 100, "y": 100});
+ \endjs
+
+ Dynamically created instances can be deleted with the \c destroy() method.
+ See \l {Dynamic Object Management in QML} for more information.
+*/
+void QQmlComponent::createObject(QQmlV8Function *args)
+{
+ Q_D(QQmlComponent);
+ Q_ASSERT(d->engine);
+ Q_ASSERT(args);
+
+ QObject *parent = 0;
+ v8::Local<v8::Object> valuemap;
+
+ if (args->Length() >= 1)
+ parent = args->engine()->toQObject((*args)[0]);
+
+ if (args->Length() >= 2) {
+ v8::Local<v8::Value> v = (*args)[1];
+ if (!v->IsObject() || v->IsArray()) {
+ qmlInfo(this) << tr("createObject: value is not an object");
+ args->returnValue(v8::Null());
+ return;
+ }
+ valuemap = v8::Local<v8::Object>::Cast(v);
+ }
+
+ QV8Engine *v8engine = args->engine();
+
+ QQmlContext *ctxt = creationContext();
+ if (!ctxt) ctxt = d->engine->rootContext();
+
+ QObject *rv = beginCreate(ctxt);
+
+ if (!rv) {
+ args->returnValue(v8::Null());
+ return;
+ }
+
+ QQmlComponent_setQmlParent(rv, parent);
+
+ v8::Handle<v8::Value> ov = v8engine->newQObject(rv);
+ Q_ASSERT(ov->IsObject());
+ v8::Handle<v8::Object> object = v8::Handle<v8::Object>::Cast(ov);
+
+ if (!valuemap.IsEmpty()) {
+ QQmlComponentExtension *e = componentExtension(v8engine);
+ // Try catch isn't needed as the function itself is loaded with try/catch
+ v8::Handle<v8::Value> function = e->initialProperties->Run(args->qmlGlobal());
+ v8::Handle<v8::Value> args[] = { object, valuemap };
+ v8::Handle<v8::Function>::Cast(function)->Call(v8engine->global(), 2, args);
+ }
+
+ d->completeCreate();
+
+ Q_ASSERT(QQmlData::get(rv));
+ QQmlData::get(rv)->setImplicitDestructible();
+
+ if (!rv)
+ args->returnValue(v8::Null());
+ else
+ args->returnValue(object);
+}
+
+/*!
+ \qmlmethod object Component::incubateObject(Item parent, object properties, enum mode)
+
+ Creates an incubator for instance of this component. Incubators allow new component
+ instances to be instantiated asynchronously and not cause freezes in the UI.
+
+ The \a parent argument specifies the parent the created instance will have. Omitting the
+ parameter or passing null will create anobject with no parent. In this case, a reference
+ to the created object must be maintained by the application of the object will eventually
+ be garbage collected.
+
+ The \a properties argument is specified as a map of property-value items which will be
+ set on the created object during its construction. \a mode may be Qt.Synchronous or
+ Qt.Asynchronous and controls whether the instance is created synchronously or asynchronously.
+ The default is asynchronously. In some circumstances, even if Qt.Synchronous is specified,
+ the incubator may create the object asynchronously. This happens if the component calling
+ incubateObject() is itself being created asynchronously.
+
+ All three arguments are optional.
+
+ If successful, the method returns an incubator, otherwise null. The incubator has the following
+ properties:
+
+ \list
+ \i status The status of the incubator. Valid values are Component.Ready, Component.Loading and
+ Component.Error.
+ \i object The created object instance. Will only be available once the incubator is in the
+ Ready status.
+ \i onStatusChanged Specifies a callback function to be invoked when the status changes. The
+ status is passed as a parameter to the callback.
+ \i forceCompletion() Call to complete incubation synchronously.
+ \endlist
+
+ The following example demonstrates how to use an incubator:
+
+ \js
+ var component = Qt.createComponent("Button.qml");
+
+ var incubator = component.incubateObject(parent, { x: 10, y: 10 });
+ if (incubator.status != Component.Ready) {
+ incubator.onStatusChanged = function(status) {
+ if (status == Component.Ready) {
+ print ("Object", incubator.object, "is now ready!");
+ }
+ }
+ } else {
+ print ("Object", incubator.object, "is ready immediately!");
+ }
+ \endjs
+*/
+
+void QQmlComponent::incubateObject(QQmlV8Function *args)
+{
+ Q_D(QQmlComponent);
+ Q_ASSERT(d->engine);
+ Q_UNUSED(d);
+ Q_ASSERT(args);
+
+ QObject *parent = 0;
+ v8::Local<v8::Object> valuemap;
+ QQmlIncubator::IncubationMode mode = QQmlIncubator::Asynchronous;
+
+ if (args->Length() >= 1)
+ parent = args->engine()->toQObject((*args)[0]);
+
+ if (args->Length() >= 2) {
+ v8::Local<v8::Value> v = (*args)[1];
+ if (v->IsNull()) {
+ } else if (!v->IsObject() || v->IsArray()) {
+ qmlInfo(this) << tr("createObject: value is not an object");
+ args->returnValue(v8::Null());
+ return;
+ } else {
+ valuemap = v8::Local<v8::Object>::Cast(v);
+ }
+ }
+
+ if (args->Length() >= 3) {
+ quint32 v = (*args)[2]->Uint32Value();
+ if (v == 0)
+ mode = QQmlIncubator::Asynchronous;
+ else if (v == 1)
+ mode = QQmlIncubator::AsynchronousIfNested;
+ }
+
+ QQmlComponentExtension *e = componentExtension(args->engine());
+
+ QV8IncubatorResource *r = new QV8IncubatorResource(args->engine(), mode);
+ v8::Local<v8::Object> o = e->incubationConstructor->NewInstance();
+ o->SetExternalResource(r);
+
+ if (!valuemap.IsEmpty()) {
+ r->valuemap = qPersistentNew(valuemap);
+ r->qmlGlobal = qPersistentNew(args->qmlGlobal());
+ }
+ r->parent = parent;
+ r->me = qPersistentNew(o);
+
+ create(*r, creationContext());
+
+ if (r->status() == QQmlIncubator::Null) {
+ r->dispose();
+ args->returnValue(v8::Null());
+ } else {
+ args->returnValue(o);
+ }
+}
+
+// XXX used by QSGLoader
+void QQmlComponentPrivate::initializeObjectWithInitialProperties(v8::Handle<v8::Object> qmlGlobal, v8::Handle<v8::Object> valuemap, QObject *toCreate)
+{
+ QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine);
+ QV8Engine *v8engine = ep->v8engine();
+
+ v8::HandleScope handle_scope;
+ v8::Context::Scope scope(v8engine->context());
+ v8::Handle<v8::Value> ov = v8engine->newQObject(toCreate);
+ Q_ASSERT(ov->IsObject());
+ v8::Handle<v8::Object> object = v8::Handle<v8::Object>::Cast(ov);
+
+ if (!valuemap.IsEmpty()) {
+ QQmlComponentExtension *e = componentExtension(v8engine);
+ // Try catch isn't needed as the function itself is loaded with try/catch
+ v8::Handle<v8::Value> function = e->initialProperties->Run(qmlGlobal);
+ v8::Handle<v8::Value> args[] = { object, valuemap };
+ v8::Handle<v8::Function>::Cast(function)->Call(v8engine->global(), 2, args);
+ }
+
+ QQmlData *ddata = QQmlData::get(toCreate);
+ Q_ASSERT(ddata);
+ ddata->setImplicitDestructible();
+}
+
+
+QQmlComponentExtension::QQmlComponentExtension(QV8Engine *engine)
+{
+ v8::HandleScope handle_scope;
+ v8::Context::Scope scope(engine->context());
+
+ forceCompletion = qPersistentNew(V8FUNCTION(QV8IncubatorResource::ForceCompletion, engine));
+
+ {
+ v8::Local<v8::FunctionTemplate> ft = v8::FunctionTemplate::New();
+ ft->InstanceTemplate()->SetHasExternalResource(true);
+ ft->InstanceTemplate()->SetInternalFieldCount(1);
+ ft->InstanceTemplate()->SetAccessor(v8::String::New("onStatusChanged"),
+ QV8IncubatorResource::StatusChangedGetter,
+ QV8IncubatorResource::StatusChangedSetter);
+ ft->InstanceTemplate()->SetAccessor(v8::String::New("status"),
+ QV8IncubatorResource::StatusGetter);
+ ft->InstanceTemplate()->SetAccessor(v8::String::New("object"),
+ QV8IncubatorResource::ObjectGetter);
+ ft->InstanceTemplate()->SetAccessor(v8::String::New("forceCompletion"),
+ QV8IncubatorResource::ForceCompletionGetter);
+ incubationConstructor = qPersistentNew(ft->GetFunction());
+ }
+
+ {
+#define INITIALPROPERTIES_SOURCE \
+ "(function(object, values) {"\
+ "try {"\
+ "for(var property in values) {" \
+ "try {"\
+ "var properties = property.split(\".\");"\
+ "var o = object;"\
+ "for (var ii = 0; ii < properties.length - 1; ++ii) {"\
+ "o = o[properties[ii]];"\
+ "}"\
+ "o[properties[properties.length - 1]] = values[property];"\
+ "} catch(e) {}"\
+ "}"\
+ "} catch(e) {}"\
+ "})"
+ initialProperties = qPersistentNew(engine->qmlModeCompile(QLatin1String(INITIALPROPERTIES_SOURCE)));
+#undef INITIALPROPERTIES_SOURCE
+ }
+}
+
+v8::Handle<v8::Value> QV8IncubatorResource::ObjectGetter(v8::Local<v8::String>,
+ const v8::AccessorInfo& info)
+{
+ QV8IncubatorResource *r = v8_resource_check<QV8IncubatorResource>(info.This());
+ return r->engine->newQObject(r->object());
+}
+
+v8::Handle<v8::Value> QV8IncubatorResource::ForceCompletionGetter(v8::Local<v8::String>,
+ const v8::AccessorInfo& info)
+{
+ QV8IncubatorResource *r = v8_resource_check<QV8IncubatorResource>(info.This());
+ return componentExtension(r->engine)->forceCompletion;
+}
+
+v8::Handle<v8::Value> QV8IncubatorResource::ForceCompletion(const v8::Arguments &args)
+{
+ QV8IncubatorResource *r = v8_resource_cast<QV8IncubatorResource>(args.This());
+ if (!r)
+ V8THROW_TYPE("Not an incubator object");
+
+ r->forceCompletion();
+
+ return v8::Undefined();
+}
+
+v8::Handle<v8::Value> QV8IncubatorResource::StatusGetter(v8::Local<v8::String>,
+ const v8::AccessorInfo& info)
+{
+ QV8IncubatorResource *r = v8_resource_check<QV8IncubatorResource>(info.This());
+ return v8::Integer::NewFromUnsigned(r->status());
+}
+
+v8::Handle<v8::Value> QV8IncubatorResource::StatusChangedGetter(v8::Local<v8::String>,
+ const v8::AccessorInfo& info)
+{
+ return info.This()->GetInternalField(0);
+}
+
+void QV8IncubatorResource::StatusChangedSetter(v8::Local<v8::String>, v8::Local<v8::Value> value,
+ const v8::AccessorInfo& info)
+{
+ info.This()->SetInternalField(0, value);
+}
+
+QQmlComponentExtension::~QQmlComponentExtension()
+{
+ qPersistentDispose(incubationConstructor);
+ qPersistentDispose(initialProperties);
+ qPersistentDispose(forceCompletion);
+}
+
+QV8IncubatorResource::QV8IncubatorResource(QV8Engine *engine, IncubationMode m)
+: QV8ObjectResource(engine), QQmlIncubator(m)
+{
+}
+
+void QV8IncubatorResource::setInitialState(QObject *o)
+{
+ QQmlComponent_setQmlParent(o, parent);
+
+ if (!valuemap.IsEmpty()) {
+ QQmlComponentExtension *e = componentExtension(engine);
+
+ v8::HandleScope handle_scope;
+ v8::Context::Scope scope(engine->context());
+
+ v8::Handle<v8::Value> function = e->initialProperties->Run(qmlGlobal);
+ v8::Handle<v8::Value> args[] = { engine->newQObject(o), valuemap };
+ v8::Handle<v8::Function>::Cast(function)->Call(engine->global(), 2, args);
+
+ qPersistentDispose(valuemap);
+ qPersistentDispose(qmlGlobal);
+ }
+}
+
+void QV8IncubatorResource::dispose()
+{
+ qPersistentDispose(valuemap);
+ qPersistentDispose(qmlGlobal);
+ // No further status changes are forthcoming, so we no long need a self reference
+ qPersistentDispose(me);
+}
+
+void QV8IncubatorResource::statusChanged(Status s)
+{
+ if (s == Ready) {
+ Q_ASSERT(QQmlData::get(object()));
+ QQmlData::get(object())->setImplicitDestructible();
+ }
+
+ if (!me.IsEmpty()) { // Will be false in synchronous mode
+ v8::HandleScope scope;
+ v8::Local<v8::Value> callback = me->GetInternalField(0);
+
+ if (!callback.IsEmpty() && !callback->IsUndefined()) {
+
+ if (callback->IsFunction()) {
+ v8::Context::Scope context_scope(engine->context());
+ v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(callback);
+ v8::Handle<v8::Value> args[] = { v8::Integer::NewFromUnsigned(s) };
+ v8::TryCatch tc;
+ f->Call(me, 1, args);
+ if (tc.HasCaught()) {
+ QQmlError error;
+ QQmlExpressionPrivate::exceptionToError(tc.Message(), error);
+ QQmlEnginePrivate::warning(QQmlEnginePrivate::get(engine->engine()),
+ error);
+ }
+ }
+ }
+ }
+
+ if (s == Ready || s == Error)
+ dispose();
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlcomponent.h b/src/qml/qml/qqmlcomponent.h
new file mode 100644
index 0000000000..1265fb1c7d
--- /dev/null
+++ b/src/qml/qml/qqmlcomponent.h
@@ -0,0 +1,138 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLCOMPONENT_H
+#define QQMLCOMPONENT_H
+
+#include <QtQml/qqml.h>
+#include <QtQml/qqmlerror.h>
+
+#include <QtCore/qobject.h>
+#include <QtCore/qstring.h>
+#include <QtQml/qjsvalue.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+
+class QByteArray;
+class QQmlEngine;
+class QQmlComponent;
+class QQmlIncubator;
+class QQmlV8Function;
+class QQmlCompiledData;
+class QQmlComponentPrivate;
+class QQmlComponentAttached;
+
+class Q_QML_EXPORT QQmlComponent : public QObject
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QQmlComponent)
+
+ Q_PROPERTY(qreal progress READ progress NOTIFY progressChanged)
+ Q_PROPERTY(Status status READ status NOTIFY statusChanged)
+ Q_PROPERTY(QUrl url READ url CONSTANT)
+
+public:
+ QQmlComponent(QObject *parent = 0);
+ QQmlComponent(QQmlEngine *, QObject *parent=0);
+ QQmlComponent(QQmlEngine *, const QString &fileName, QObject *parent = 0);
+ QQmlComponent(QQmlEngine *, const QUrl &url, QObject *parent = 0);
+ virtual ~QQmlComponent();
+
+ Q_ENUMS(Status)
+ enum Status { Null, Ready, Loading, Error };
+ Status status() const;
+
+ bool isNull() const;
+ bool isReady() const;
+ bool isError() const;
+ bool isLoading() const;
+
+ QList<QQmlError> errors() const;
+ Q_INVOKABLE QString errorString() const;
+
+ qreal progress() const;
+
+ QUrl url() const;
+
+ virtual QObject *create(QQmlContext *context = 0);
+ virtual QObject *beginCreate(QQmlContext *);
+ virtual void completeCreate();
+
+ void create(QQmlIncubator &, QQmlContext *context = 0,
+ QQmlContext *forContext = 0);
+
+ QQmlContext *creationContext() const;
+
+ static QQmlComponentAttached *qmlAttachedProperties(QObject *);
+
+public Q_SLOTS:
+ void loadUrl(const QUrl &url);
+ void setData(const QByteArray &, const QUrl &baseUrl);
+
+Q_SIGNALS:
+ void statusChanged(QQmlComponent::Status);
+ void progressChanged(qreal);
+
+protected:
+ QQmlComponent(QQmlComponentPrivate &dd, QObject* parent);
+ Q_INVOKABLE void createObject(QQmlV8Function *);
+ Q_INVOKABLE void incubateObject(QQmlV8Function *);
+
+private:
+ QQmlComponent(QQmlEngine *, QQmlCompiledData *, int, QObject *parent);
+
+ Q_DISABLE_COPY(QQmlComponent)
+ friend class QQmlVME;
+ friend class QQmlTypeData;
+};
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(QQmlComponent::Status)
+QML_DECLARE_TYPE(QQmlComponent)
+QML_DECLARE_TYPEINFO(QQmlComponent, QML_HAS_ATTACHED_PROPERTIES)
+
+QT_END_HEADER
+
+#endif // QQMLCOMPONENT_H
diff --git a/src/qml/qml/qqmlcomponent_p.h b/src/qml/qml/qqmlcomponent_p.h
new file mode 100644
index 0000000000..731fb6a8a7
--- /dev/null
+++ b/src/qml/qml/qqmlcomponent_p.h
@@ -0,0 +1,129 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLCOMPONENT_P_H
+#define QQMLCOMPONENT_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 "qqmlcomponent.h"
+
+#include <private/qv8_p.h>
+#include "qqmlengine_p.h"
+#include "qqmltypeloader_p.h"
+#include <private/qbitfield_p.h>
+#include "qqmlvme_p.h"
+#include "qqmlerror.h"
+#include "qqml.h"
+
+#include <QtCore/QString>
+#include <QtCore/QStringList>
+#include <QtCore/QList>
+
+#include <private/qobject_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QV8Engine;
+
+class QQmlComponent;
+class QQmlEngine;
+class QQmlCompiledData;
+
+class QQmlComponentAttached;
+class Q_QML_PRIVATE_EXPORT QQmlComponentPrivate : public QObjectPrivate, public QQmlTypeData::TypeDataCallback
+{
+ Q_DECLARE_PUBLIC(QQmlComponent)
+
+public:
+ QQmlComponentPrivate() : typeData(0), progress(0.), start(-1), cc(0), engine(0), creationContext(0) {}
+
+ QObject *beginCreate(QQmlContextData *);
+ void completeCreate();
+ void initializeObjectWithInitialProperties(v8::Handle<v8::Object> qmlGlobal, v8::Handle<v8::Object> valuemap, QObject *toCreate);
+
+ QQmlTypeData *typeData;
+ virtual void typeDataReady(QQmlTypeData *);
+ virtual void typeDataProgress(QQmlTypeData *, qreal);
+
+ void fromTypeData(QQmlTypeData *data);
+
+ QUrl url;
+ qreal progress;
+
+ int start;
+ QQmlCompiledData *cc;
+
+ struct ConstructionState {
+ ConstructionState() : completePending(false) {}
+
+ QQmlVME vme;
+ QList<QQmlError> errors;
+ bool completePending;
+ };
+ ConstructionState state;
+
+ static void beginDeferred(QQmlEnginePrivate *enginePriv, QObject *object,
+ ConstructionState *state);
+ static void complete(QQmlEnginePrivate *enginePriv, ConstructionState *state);
+
+ QQmlEngine *engine;
+ QQmlGuardedContextData creationContext;
+
+ void clear();
+
+ static QQmlComponentPrivate *get(QQmlComponent *c) {
+ return static_cast<QQmlComponentPrivate *>(QObjectPrivate::get(c));
+ }
+};
+
+QT_END_NAMESPACE
+
+#endif // QQMLCOMPONENT_P_H
diff --git a/src/qml/qml/qqmlcomponentattached_p.h b/src/qml/qml/qqmlcomponentattached_p.h
new file mode 100644
index 0000000000..09d111c227
--- /dev/null
+++ b/src/qml/qml/qqmlcomponentattached_p.h
@@ -0,0 +1,85 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLCOMPONENTATTACHED_P_H
+#define QQMLCOMPONENTATTACHED_P_H
+
+#include <QtQml/qqml.h>
+#include <QtCore/QObject>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+
+class Q_AUTOTEST_EXPORT QQmlComponentAttached : public QObject
+{
+ Q_OBJECT
+public:
+ QQmlComponentAttached(QObject *parent = 0);
+ ~QQmlComponentAttached();
+
+ void add(QQmlComponentAttached **a) {
+ prev = a; next = *a; *a = this;
+ if (next) next->prev = &next;
+ }
+ void rem() {
+ if (next) next->prev = prev;
+ *prev = next;
+ next = 0; prev = 0;
+ }
+ QQmlComponentAttached **prev;
+ QQmlComponentAttached *next;
+
+Q_SIGNALS:
+ void completed();
+ void destruction();
+
+private:
+ friend class QQmlVME;
+ friend class QQmlContextData;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QQMLCOMPONENTATTACHED_P_H
diff --git a/src/qml/qml/qqmlcontext.cpp b/src/qml/qml/qqmlcontext.cpp
new file mode 100644
index 0000000000..38acc0b0c3
--- /dev/null
+++ b/src/qml/qml/qqmlcontext.cpp
@@ -0,0 +1,811 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qqmlcontext.h"
+#include "qqmlcontext_p.h"
+#include "qqmlcomponentattached_p.h"
+
+#include "qqmlcomponent_p.h"
+#include "qqmlexpression_p.h"
+#include "qqmlengine_p.h"
+#include "qqmlengine.h"
+#include "qqmlinfo.h"
+#include <private/qv4bindings_p.h>
+#include <private/qv8bindings_p.h>
+
+#include <qjsengine.h>
+#include <QtCore/qvarlengtharray.h>
+#include <QtCore/qdebug.h>
+
+QT_BEGIN_NAMESPACE
+
+QQmlContextPrivate::QQmlContextPrivate()
+: data(0), notifyIndex(-1)
+{
+}
+
+/*!
+ \class QQmlContext
+ \since 4.7
+ \brief The QQmlContext class defines a context within a QML engine.
+ \mainclass
+
+ Contexts allow data to be exposed to the QML components instantiated by the
+ QML engine.
+
+ Each QQmlContext contains a set of properties, distinct from its QObject
+ properties, that allow data to be explicitly bound to a context by name. The
+ context properties are defined and updated by calling
+ QQmlContext::setContextProperty(). The following example shows a Qt model
+ being bound to a context and then accessed from a QML file.
+
+ \code
+ QQmlEngine engine;
+ QStringListModel modelData;
+ QQmlContext *context = new QQmlContext(engine.rootContext());
+ context->setContextProperty("myModel", &modelData);
+
+ QQmlComponent component(&engine);
+ component.setData("import QtQuick 2.0\nListView { model: myModel }", QUrl());
+ QObject *window = component.create(context);
+ \endcode
+
+ Note it is the responsibility of the creator to delete any QQmlContext it
+ constructs. If the \c context object in the example is no longer needed when the
+ \c window component instance is destroyed, the \c context must be destroyed explicitly.
+ The simplest way to ensure this is to set \c window as the parent of \c context.
+
+ To simplify binding and maintaining larger data sets, a context object can be set
+ on a QQmlContext. All the properties of the context object are available
+ by name in the context, as though they were all individually added through calls
+ to QQmlContext::setContextProperty(). Changes to the property's values are
+ detected through the property's notify signal. Setting a context object is both
+ faster and easier than manually adding and maintaing context property values.
+
+ The following example has the same effect as the previous one, but it uses a context
+ object.
+
+ \code
+ class MyDataSet : ... {
+ ...
+ Q_PROPERTY(QAbstractItemModel *myModel READ model NOTIFY modelChanged)
+ ...
+ };
+
+ MyDataSet myDataSet;
+ QQmlEngine engine;
+ QQmlContext *context = new QQmlContext(engine.rootContext());
+ context->setContextObject(&myDataSet);
+
+ QQmlComponent component(&engine);
+ component.setData("import QtQuick 2.0\nListView { model: myModel }", QUrl());
+ component.create(context);
+ \endcode
+
+ All properties added explicitly by QQmlContext::setContextProperty() take
+ precedence over the context object's properties.
+
+ \section2 The Context Hierarchy
+
+ Contexts form a hierarchy. The root of this hierarchy is the QML engine's
+ \l {QQmlEngine::rootContext()}{root context}. Child contexts inherit
+ the context properties of their parents; if a child context sets a context property
+ that already exists in its parent, the new context property overrides that of the
+ parent.
+
+ The following example defines two contexts - \c context1 and \c context2. The
+ second context overrides the "b" context property inherited from the first with a
+ new value.
+
+ \code
+ QQmlEngine engine;
+ QQmlContext *context1 = new QQmlContext(engine.rootContext());
+ QQmlContext *context2 = new QQmlContext(context1);
+
+ context1->setContextProperty("a", 12);
+ context1->setContextProperty("b", 12);
+
+ context2->setContextProperty("b", 15);
+ \endcode
+
+ While QML objects instantiated in a context are not strictly owned by that
+ context, their bindings are. If a context is destroyed, the property bindings of
+ outstanding QML objects will stop evaluating.
+
+ \warning Setting the context object or adding new context properties after an object
+ has been created in that context is an expensive operation (essentially forcing all bindings
+ to reevaluate). Thus whenever possible you should complete "setup" of the context
+ before using it to create any objects.
+
+ \sa {Using QML Bindings in C++ Applications}
+*/
+
+/*! \internal */
+QQmlContext::QQmlContext(QQmlEngine *e, bool)
+: QObject(*(new QQmlContextPrivate))
+{
+ Q_D(QQmlContext);
+ d->data = new QQmlContextData(this);
+
+ d->data->engine = e;
+}
+
+/*!
+ Create a new QQmlContext as a child of \a engine's root context, and the
+ QObject \a parent.
+*/
+QQmlContext::QQmlContext(QQmlEngine *engine, QObject *parent)
+: QObject(*(new QQmlContextPrivate), parent)
+{
+ Q_D(QQmlContext);
+ d->data = new QQmlContextData(this);
+
+ d->data->setParent(engine?QQmlContextData::get(engine->rootContext()):0);
+}
+
+/*!
+ Create a new QQmlContext with the given \a parentContext, and the
+ QObject \a parent.
+*/
+QQmlContext::QQmlContext(QQmlContext *parentContext, QObject *parent)
+: QObject(*(new QQmlContextPrivate), parent)
+{
+ Q_D(QQmlContext);
+ d->data = new QQmlContextData(this);
+
+ d->data->setParent(parentContext?QQmlContextData::get(parentContext):0);
+}
+
+/*!
+ \internal
+*/
+QQmlContext::QQmlContext(QQmlContextData *data)
+: QObject(*(new QQmlContextPrivate), 0)
+{
+ Q_D(QQmlContext);
+ d->data = data;
+}
+
+/*!
+ Destroys the QQmlContext.
+
+ Any expressions, or sub-contexts dependent on this context will be
+ invalidated, but not destroyed (unless they are parented to the QQmlContext
+ object).
+ */
+QQmlContext::~QQmlContext()
+{
+ Q_D(QQmlContext);
+
+ if (!d->data->isInternal)
+ d->data->destroy();
+}
+
+/*!
+ Returns whether the context is valid.
+
+ To be valid, a context must have a engine, and it's contextObject(), if any,
+ must not have been deleted.
+*/
+bool QQmlContext::isValid() const
+{
+ Q_D(const QQmlContext);
+ return d->data && d->data->isValid();
+}
+
+/*!
+ Return the context's QQmlEngine, or 0 if the context has no QQmlEngine or the
+ QQmlEngine was destroyed.
+*/
+QQmlEngine *QQmlContext::engine() const
+{
+ Q_D(const QQmlContext);
+ return d->data->engine;
+}
+
+/*!
+ Return the context's parent QQmlContext, or 0 if this context has no
+ parent or if the parent has been destroyed.
+*/
+QQmlContext *QQmlContext::parentContext() const
+{
+ Q_D(const QQmlContext);
+ return d->data->parent?d->data->parent->asQQmlContext():0;
+}
+
+/*!
+ Return the context object, or 0 if there is no context object.
+*/
+QObject *QQmlContext::contextObject() const
+{
+ Q_D(const QQmlContext);
+ return d->data->contextObject;
+}
+
+/*!
+ Set the context \a object.
+*/
+void QQmlContext::setContextObject(QObject *object)
+{
+ Q_D(QQmlContext);
+
+ QQmlContextData *data = d->data;
+
+ if (data->isInternal) {
+ qWarning("QQmlContext: Cannot set context object for internal context.");
+ return;
+ }
+
+ if (!isValid()) {
+ qWarning("QQmlContext: Cannot set context object on invalid context.");
+ return;
+ }
+
+ data->contextObject = object;
+}
+
+/*!
+ Set a the \a value of the \a name property on this context.
+*/
+void QQmlContext::setContextProperty(const QString &name, const QVariant &value)
+{
+ Q_D(QQmlContext);
+ if (d->notifyIndex == -1)
+ d->notifyIndex = this->metaObject()->methodCount();
+
+ QQmlContextData *data = d->data;
+
+ if (data->isInternal) {
+ qWarning("QQmlContext: Cannot set property on internal context.");
+ return;
+ }
+
+ if (!isValid()) {
+ qWarning("QQmlContext: Cannot set property on invalid context.");
+ return;
+ }
+
+ if (data->engine) {
+ bool ok;
+ QObject *o = QQmlEnginePrivate::get(data->engine)->toQObject(value, &ok);
+ if (ok) {
+ setContextProperty(name, o);
+ return;
+ }
+ }
+
+ if (!data->propertyNames) data->propertyNames = new QQmlIntegerCache();
+
+ int idx = data->propertyNames->value(name);
+ if (idx == -1) {
+ data->propertyNames->add(name, data->idValueCount + d->propertyValues.count());
+ d->propertyValues.append(value);
+
+ data->refreshExpressions();
+ } else {
+ d->propertyValues[idx] = value;
+ QMetaObject::activate(this, idx + d->notifyIndex, 0);
+ }
+}
+
+/*!
+ Set the \a value of the \a name property on this context.
+
+ QQmlContext does \bold not take ownership of \a value.
+*/
+void QQmlContext::setContextProperty(const QString &name, QObject *value)
+{
+ Q_D(QQmlContext);
+ if (d->notifyIndex == -1)
+ d->notifyIndex = this->metaObject()->methodCount();
+
+ QQmlContextData *data = d->data;
+
+ if (data->isInternal) {
+ qWarning("QQmlContext: Cannot set property on internal context.");
+ return;
+ }
+
+ if (!isValid()) {
+ qWarning("QQmlContext: Cannot set property on invalid context.");
+ return;
+ }
+
+ if (!data->propertyNames) data->propertyNames = new QQmlIntegerCache();
+ int idx = data->propertyNames->value(name);
+
+ if (idx == -1) {
+ data->propertyNames->add(name, data->idValueCount + d->propertyValues.count());
+ d->propertyValues.append(QVariant::fromValue(value));
+
+ data->refreshExpressions();
+ } else {
+ d->propertyValues[idx] = QVariant::fromValue(value);
+ QMetaObject::activate(this, idx + d->notifyIndex, 0);
+ }
+}
+
+/*!
+ Returns the value of the \a name property for this context
+ as a QVariant.
+ */
+QVariant QQmlContext::contextProperty(const QString &name) const
+{
+ Q_D(const QQmlContext);
+ QVariant value;
+ int idx = -1;
+
+ QQmlContextData *data = d->data;
+
+ if (data->propertyNames)
+ idx = data->propertyNames->value(name);
+
+ if (idx == -1) {
+ QByteArray utf8Name = name.toUtf8();
+ if (data->contextObject) {
+ QObject *obj = data->contextObject;
+ QQmlPropertyData local;
+ QQmlPropertyData *property =
+ QQmlPropertyCache::property(data->engine, obj, name, local);
+
+ if (property) value = obj->metaObject()->property(property->coreIndex).read(obj);
+ }
+ if (!value.isValid() && parentContext())
+ value = parentContext()->contextProperty(name);
+ } else {
+ if (idx >= d->propertyValues.count())
+ value = QVariant::fromValue(data->idValues[idx - d->propertyValues.count()].data());
+ else
+ value = d->propertyValues[idx];
+ }
+
+ return value;
+}
+
+/*!
+Returns the name of \a object in this context, or an empty string if \a object
+is not named in the context. Objects are named by setContextProperty(), or by ids in
+the case of QML created contexts.
+
+If the object has multiple names, the first is returned.
+*/
+QString QQmlContext::nameForObject(QObject *object) const
+{
+ Q_D(const QQmlContext);
+
+ return d->data->findObjectId(object);
+}
+
+/*!
+ Resolves the URL \a src relative to the URL of the
+ containing component.
+
+ \sa QQmlEngine::baseUrl(), setBaseUrl()
+*/
+QUrl QQmlContext::resolvedUrl(const QUrl &src)
+{
+ Q_D(QQmlContext);
+ return d->data->resolvedUrl(src);
+}
+
+QUrl QQmlContextData::resolvedUrl(const QUrl &src)
+{
+ QQmlContextData *ctxt = this;
+
+ if (src.isRelative() && !src.isEmpty()) {
+ if (ctxt) {
+ while(ctxt) {
+ if(ctxt->url.isValid())
+ break;
+ else
+ ctxt = ctxt->parent;
+ }
+
+ if (ctxt)
+ return ctxt->url.resolved(src);
+ else if (engine)
+ return engine->baseUrl().resolved(src);
+ }
+ return QUrl();
+ } else {
+ return src;
+ }
+}
+
+
+/*!
+ Explicitly sets the url resolvedUrl() will use for relative references to \a baseUrl.
+
+ Calling this function will override the url of the containing
+ component used by default.
+
+ \sa resolvedUrl()
+*/
+void QQmlContext::setBaseUrl(const QUrl &baseUrl)
+{
+ Q_D(QQmlContext);
+
+ d->data->url = baseUrl;
+ d->data->urlString = baseUrl.toString();
+}
+
+/*!
+ Returns the base url of the component, or the containing component
+ if none is set.
+*/
+QUrl QQmlContext::baseUrl() const
+{
+ Q_D(const QQmlContext);
+ const QQmlContextData* data = d->data;
+ while (data && data->url.isEmpty())
+ data = data->parent;
+
+ if (data)
+ return data->url;
+ else
+ return QUrl();
+}
+
+int QQmlContextPrivate::context_count(QQmlListProperty<QObject> *prop)
+{
+ QQmlContext *context = static_cast<QQmlContext*>(prop->object);
+ QQmlContextPrivate *d = QQmlContextPrivate::get(context);
+ int contextProperty = (int)(quintptr)prop->data;
+
+ if (d->propertyValues.at(contextProperty).userType() != qMetaTypeId<QList<QObject*> >()) {
+ return 0;
+ } else {
+ return ((const QList<QObject> *)d->propertyValues.at(contextProperty).constData())->count();
+ }
+}
+
+QObject *QQmlContextPrivate::context_at(QQmlListProperty<QObject> *prop, int index)
+{
+ QQmlContext *context = static_cast<QQmlContext*>(prop->object);
+ QQmlContextPrivate *d = QQmlContextPrivate::get(context);
+ int contextProperty = (int)(quintptr)prop->data;
+
+ if (d->propertyValues.at(contextProperty).userType() != qMetaTypeId<QList<QObject*> >()) {
+ return 0;
+ } else {
+ return ((const QList<QObject*> *)d->propertyValues.at(contextProperty).constData())->at(index);
+ }
+}
+
+
+QQmlContextData::QQmlContextData()
+: parent(0), engine(0), isInternal(false), ownedByParent(false), isJSContext(false),
+ isPragmaLibraryContext(false), unresolvedNames(false), publicContext(0), activeVMEData(0),
+ propertyNames(0), contextObject(0), imports(0), childContexts(0), nextChild(0), prevChild(0),
+ expressions(0), contextObjects(0), contextGuards(0), idValues(0), idValueCount(0), linkedContext(0),
+ componentAttached(0), v4bindings(0), v8bindings(0)
+{
+}
+
+QQmlContextData::QQmlContextData(QQmlContext *ctxt)
+: parent(0), engine(0), isInternal(false), ownedByParent(false), isJSContext(false),
+ isPragmaLibraryContext(false), unresolvedNames(false), publicContext(ctxt), activeVMEData(0),
+ propertyNames(0), contextObject(0), imports(0), childContexts(0), nextChild(0), prevChild(0),
+ expressions(0), contextObjects(0), contextGuards(0), idValues(0), idValueCount(0), linkedContext(0),
+ componentAttached(0), v4bindings(0), v8bindings(0)
+{
+}
+
+void QQmlContextData::invalidate()
+{
+ while (componentAttached) {
+ QQmlComponentAttached *a = componentAttached;
+ componentAttached = a->next;
+ if (componentAttached) componentAttached->prev = &componentAttached;
+
+ a->next = 0;
+ a->prev = 0;
+
+ emit a->destruction();
+ }
+
+ while (childContexts) {
+ if (childContexts->ownedByParent) {
+ childContexts->destroy();
+ } else {
+ childContexts->invalidate();
+ }
+ }
+
+ if (prevChild) {
+ *prevChild = nextChild;
+ if (nextChild) nextChild->prevChild = prevChild;
+ nextChild = 0;
+ prevChild = 0;
+ }
+
+ engine = 0;
+ parent = 0;
+}
+
+void QQmlContextData::clearContext()
+{
+ if (engine) {
+ while (componentAttached) {
+ QQmlComponentAttached *a = componentAttached;
+ componentAttached = a->next;
+ if (componentAttached) componentAttached->prev = &componentAttached;
+
+ a->next = 0;
+ a->prev = 0;
+
+ emit a->destruction();
+ }
+ }
+
+ QQmlAbstractExpression *expression = expressions;
+ while (expression) {
+ QQmlAbstractExpression *nextExpression = expression->m_nextExpression;
+
+ expression->m_prevExpression = 0;
+ expression->m_nextExpression = 0;
+
+ expression->setContext(0);
+
+ expression = nextExpression;
+ }
+ expressions = 0;
+}
+
+void QQmlContextData::destroy()
+{
+ if (linkedContext)
+ linkedContext->destroy();
+
+ if (engine) invalidate();
+
+ clearContext();
+
+ while (contextObjects) {
+ QQmlData *co = contextObjects;
+ contextObjects = contextObjects->nextContextObject;
+
+ co->context = 0;
+ co->outerContext = 0;
+ co->nextContextObject = 0;
+ co->prevContextObject = 0;
+ }
+
+ QQmlGuardedContextData *contextGuard = contextGuards;
+ while (contextGuard) {
+ QQmlGuardedContextData *next = contextGuard->m_next;
+ contextGuard->m_next = 0;
+ contextGuard->m_prev = 0;
+ contextGuard->m_contextData = 0;
+ contextGuard = next;
+ }
+ contextGuards = 0;
+
+ if (propertyNames)
+ propertyNames->release();
+
+ if (imports)
+ imports->release();
+
+ if (v4bindings)
+ v4bindings->release();
+
+ if (v8bindings)
+ v8bindings->release();
+
+ for (int ii = 0; ii < importedScripts.count(); ++ii) {
+ qPersistentDispose(importedScripts[ii]);
+ }
+
+ delete [] idValues;
+
+ if (isInternal)
+ delete publicContext;
+
+ delete this;
+}
+
+void QQmlContextData::setParent(QQmlContextData *p, bool parentTakesOwnership)
+{
+ if (p) {
+ parent = p;
+ engine = p->engine;
+ nextChild = p->childContexts;
+ if (nextChild) nextChild->prevChild = &nextChild;
+ prevChild = &p->childContexts;
+ p->childContexts = this;
+ ownedByParent = parentTakesOwnership;
+ }
+}
+
+void QQmlContextData::refreshExpressionsRecursive(QQmlAbstractExpression *expression)
+{
+ QQmlAbstractExpression::DeleteWatcher w(expression);
+
+ if (expression->m_nextExpression)
+ refreshExpressionsRecursive(expression->m_nextExpression);
+
+ if (!w.wasDeleted())
+ expression->refresh();
+}
+
+static inline bool expressions_to_run(QQmlContextData *ctxt, bool isGlobalRefresh)
+{
+ return ctxt->expressions && (!isGlobalRefresh || ctxt->unresolvedNames);
+}
+
+void QQmlContextData::refreshExpressionsRecursive(bool isGlobal)
+{
+ // For efficiency, we try and minimize the number of guards we have to create
+ if (expressions_to_run(this, isGlobal) && (nextChild || childContexts)) {
+ QQmlGuardedContextData guard(this);
+
+ if (childContexts)
+ childContexts->refreshExpressionsRecursive(isGlobal);
+
+ if (guard.isNull()) return;
+
+ if (nextChild)
+ nextChild->refreshExpressionsRecursive(isGlobal);
+
+ if (guard.isNull()) return;
+
+ if (expressions_to_run(this, isGlobal))
+ refreshExpressionsRecursive(expressions);
+
+ } else if (expressions_to_run(this, isGlobal)) {
+
+ refreshExpressionsRecursive(expressions);
+
+ } else if (nextChild && childContexts) {
+
+ QQmlGuardedContextData guard(this);
+
+ childContexts->refreshExpressionsRecursive(isGlobal);
+
+ if (!guard.isNull() && nextChild)
+ nextChild->refreshExpressionsRecursive(isGlobal);
+
+ } else if (nextChild) {
+
+ nextChild->refreshExpressionsRecursive(isGlobal);
+
+ } else if (childContexts) {
+
+ childContexts->refreshExpressionsRecursive(isGlobal);
+
+ }
+}
+
+// Refreshes all expressions that could possibly depend on this context. Refreshing flushes all
+// context-tree dependent caches in the expressions, and should occur every time the context tree
+// *structure* (not values) changes.
+void QQmlContextData::refreshExpressions()
+{
+ bool isGlobal = (parent == 0);
+
+ // For efficiency, we try and minimize the number of guards we have to create
+ if (expressions_to_run(this, isGlobal) && childContexts) {
+ QQmlGuardedContextData guard(this);
+
+ childContexts->refreshExpressionsRecursive(isGlobal);
+
+ if (!guard.isNull() && expressions_to_run(this, isGlobal))
+ refreshExpressionsRecursive(expressions);
+
+ } else if (expressions_to_run(this, isGlobal)) {
+
+ refreshExpressionsRecursive(expressions);
+
+ } else if (childContexts) {
+
+ childContexts->refreshExpressionsRecursive(isGlobal);
+
+ }
+}
+
+void QQmlContextData::addObject(QObject *o)
+{
+ QQmlData *data = QQmlData::get(o, true);
+
+ Q_ASSERT(data->context == 0);
+
+ data->context = this;
+ data->outerContext = this;
+
+ data->nextContextObject = contextObjects;
+ if (data->nextContextObject)
+ data->nextContextObject->prevContextObject = &data->nextContextObject;
+ data->prevContextObject = &contextObjects;
+ contextObjects = data;
+}
+
+void QQmlContextData::setIdProperty(int idx, QObject *obj)
+{
+ idValues[idx] = obj;
+ idValues[idx].context = this;
+}
+
+void QQmlContextData::setIdPropertyData(QQmlIntegerCache *data)
+{
+ Q_ASSERT(!propertyNames);
+ propertyNames = data;
+ propertyNames->addref();
+
+ idValueCount = data->count();
+ idValues = new ContextGuard[idValueCount];
+}
+
+QString QQmlContextData::findObjectId(const QObject *obj) const
+{
+ if (!propertyNames)
+ return QString();
+
+ for (int ii = 0; ii < idValueCount; ii++) {
+ if (idValues[ii] == obj)
+ return propertyNames->findId(ii);
+ }
+
+ if (publicContext) {
+ QQmlContextPrivate *p = QQmlContextPrivate::get(publicContext);
+ for (int ii = 0; ii < p->propertyValues.count(); ++ii)
+ if (p->propertyValues.at(ii) == QVariant::fromValue((QObject *)obj))
+ return propertyNames->findId(ii);
+ }
+
+ if (linkedContext)
+ return linkedContext->findObjectId(obj);
+ return QString();
+}
+
+QQmlContext *QQmlContextData::asQQmlContext()
+{
+ if (!publicContext)
+ publicContext = new QQmlContext(this);
+ return publicContext;
+}
+
+QQmlContextPrivate *QQmlContextData::asQQmlContextPrivate()
+{
+ return QQmlContextPrivate::get(asQQmlContext());
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlcontext.h b/src/qml/qml/qqmlcontext.h
new file mode 100644
index 0000000000..f6d8aa1d3a
--- /dev/null
+++ b/src/qml/qml/qqmlcontext.h
@@ -0,0 +1,113 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLCONTEXT_H
+#define QQMLCONTEXT_H
+
+#include <QtCore/qurl.h>
+#include <QtCore/qobject.h>
+#include <QtQml/qjsvalue.h>
+#include <QtCore/qmetatype.h>
+#include <QtCore/qvariant.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+
+class QString;
+class QQmlEngine;
+class QQmlRefCount;
+class QQmlContextPrivate;
+class QQmlCompositeTypeData;
+class QQmlContextData;
+
+class Q_QML_EXPORT QQmlContext : public QObject
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QQmlContext)
+
+public:
+ QQmlContext(QQmlEngine *parent, QObject *objParent=0);
+ QQmlContext(QQmlContext *parent, QObject *objParent=0);
+ virtual ~QQmlContext();
+
+ bool isValid() const;
+
+ QQmlEngine *engine() const;
+ QQmlContext *parentContext() const;
+
+ QObject *contextObject() const;
+ void setContextObject(QObject *);
+
+ QVariant contextProperty(const QString &) const;
+ void setContextProperty(const QString &, QObject *);
+ void setContextProperty(const QString &, const QVariant &);
+
+ QString nameForObject(QObject *) const;
+
+ QUrl resolvedUrl(const QUrl &);
+
+ void setBaseUrl(const QUrl &);
+ QUrl baseUrl() const;
+
+private:
+ friend class QQmlVME;
+ friend class QQmlEngine;
+ friend class QQmlEnginePrivate;
+ friend class QQmlExpression;
+ friend class QQmlExpressionPrivate;
+ friend class QQmlComponent;
+ friend class QQmlComponentPrivate;
+ friend class QQmlScriptPrivate;
+ friend class QQmlBoundSignalProxy;
+ friend class QQmlContextData;
+ QQmlContext(QQmlContextData *);
+ QQmlContext(QQmlEngine *, bool);
+ Q_DISABLE_COPY(QQmlContext)
+};
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(QList<QObject*>)
+
+QT_END_HEADER
+
+#endif // QQMLCONTEXT_H
diff --git a/src/qml/qml/qqmlcontext_p.h b/src/qml/qml/qqmlcontext_p.h
new file mode 100644
index 0000000000..d10543bde5
--- /dev/null
+++ b/src/qml/qml/qqmlcontext_p.h
@@ -0,0 +1,334 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLCONTEXT_P_H
+#define QQMLCONTEXT_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 "qqmlcontext.h"
+
+#include "qqmldata_p.h"
+#include "qqmlintegercache_p.h"
+#include "qqmltypenamecache_p.h"
+#include "qqmlnotifier_p.h"
+#include "qqmllist.h"
+#include "qqmlscript_p.h"
+
+#include <QtCore/qhash.h>
+#include <QtQml/qjsvalue.h>
+#include <QtCore/qset.h>
+
+#include <private/qobject_p.h>
+#include <private/qflagpointer_p.h>
+#include <private/qqmlguard_p.h>
+
+#include <private/qv8_p.h>
+
+
+QT_BEGIN_NAMESPACE
+
+class QV8Bindings;
+class QQmlContext;
+class QQmlExpression;
+class QQmlEngine;
+class QQmlExpression;
+class QQmlExpressionPrivate;
+class QQmlAbstractExpression;
+class QV4Bindings;
+class QQmlContextData;
+
+class QQmlContextPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QQmlContext)
+public:
+ QQmlContextPrivate();
+
+ QQmlContextData *data;
+
+ QList<QVariant> propertyValues;
+ int notifyIndex;
+
+ static QQmlContextPrivate *get(QQmlContext *context) {
+ return static_cast<QQmlContextPrivate *>(QObjectPrivate::get(context));
+ }
+ static QQmlContext *get(QQmlContextPrivate *context) {
+ return static_cast<QQmlContext *>(context->q_func());
+ }
+
+ // Only used for debugging
+ QList<QPointer<QObject> > instances;
+
+ static int context_count(QQmlListProperty<QObject> *);
+ static QObject *context_at(QQmlListProperty<QObject> *, int);
+};
+
+class QQmlVME;
+class QQmlComponentAttached;
+class QQmlGuardedContextData;
+class Q_QML_EXPORT QQmlContextData
+{
+public:
+ QQmlContextData();
+ QQmlContextData(QQmlContext *);
+ void clearContext();
+ void destroy();
+ void invalidate();
+
+ inline bool isValid() const {
+ return engine && (!isInternal || !contextObject || !QObjectPrivate::get(contextObject)->wasDeleted);
+ }
+
+ // My parent context and engine
+ QQmlContextData *parent;
+ QQmlEngine *engine;
+
+ void setParent(QQmlContextData *, bool parentTakesOwnership = false);
+ void refreshExpressions();
+
+ void addObject(QObject *);
+
+ QUrl resolvedUrl(const QUrl &);
+
+ // My containing QQmlContext. If isInternal is true this owns publicContext.
+ // If internal is false publicContext owns this.
+ QQmlContext *asQQmlContext();
+ QQmlContextPrivate *asQQmlContextPrivate();
+ quint32 isInternal:1;
+ quint32 ownedByParent:1; // unrelated to isInternal; parent context deletes children if true.
+ quint32 isJSContext:1;
+ quint32 isPragmaLibraryContext:1;
+ quint32 unresolvedNames:1; // True if expressions in this context failed to resolve a toplevel name
+ quint32 dummy:28;
+ QQmlContext *publicContext;
+
+ // VME data that is constructing this context if any
+ void *activeVMEData;
+
+ // Property name cache
+ QQmlIntegerCache *propertyNames;
+
+ // Context object
+ QObject *contextObject;
+
+ // Any script blocks that exist on this context
+ QList<v8::Persistent<v8::Object> > importedScripts;
+
+ // Context base url
+ QUrl url;
+ QString urlString;
+
+ // List of imports that apply to this context
+ QQmlTypeNameCache *imports;
+
+ // My children
+ QQmlContextData *childContexts;
+
+ // My peers in parent's childContexts list
+ QQmlContextData *nextChild;
+ QQmlContextData **prevChild;
+
+ // Expressions that use this context
+ QQmlAbstractExpression *expressions;
+
+ // Doubly-linked list of objects that are owned by this context
+ QQmlData *contextObjects;
+
+ // Doubly-linked list of context guards (XXX merge with contextObjects)
+ QQmlGuardedContextData *contextGuards;
+
+ // id guards
+ struct ContextGuard : public QQmlGuard<QObject>
+ {
+ inline ContextGuard();
+ inline ContextGuard &operator=(QObject *obj);
+ inline void objectDestroyed(QObject *);
+
+ inline bool wasSet() const;
+
+ QFlagPointer<QQmlContextData> context;
+ QQmlNotifier bindings;
+ };
+ ContextGuard *idValues;
+ int idValueCount;
+ void setIdProperty(int, QObject *);
+ void setIdPropertyData(QQmlIntegerCache *);
+
+ // Linked contexts. this owns linkedContext.
+ QQmlContextData *linkedContext;
+
+ // Linked list of uses of the Component attached property in this
+ // context
+ QQmlComponentAttached *componentAttached;
+
+ // Optimized binding objects. Needed for deferred properties.
+ QV4Bindings *v4bindings;
+ QV8Bindings *v8bindings;
+
+ // Return the outermost id for obj, if any.
+ QString findObjectId(const QObject *obj) const;
+
+ static QQmlContextData *get(QQmlContext *context) {
+ return QQmlContextPrivate::get(context)->data;
+ }
+
+private:
+ void refreshExpressionsRecursive(bool isGlobal);
+ void refreshExpressionsRecursive(QQmlAbstractExpression *);
+ ~QQmlContextData() {}
+};
+
+class QQmlGuardedContextData
+{
+public:
+ inline QQmlGuardedContextData();
+ inline QQmlGuardedContextData(QQmlContextData *);
+ inline ~QQmlGuardedContextData();
+
+ inline QQmlContextData *contextData();
+ inline void setContextData(QQmlContextData *);
+
+ inline bool isNull() const { return !m_contextData; }
+
+ inline operator QQmlContextData*() const { return m_contextData; }
+ inline QQmlContextData* operator->() const { return m_contextData; }
+ inline QQmlGuardedContextData &operator=(QQmlContextData *d);
+
+private:
+ QQmlGuardedContextData &operator=(const QQmlGuardedContextData &);
+ QQmlGuardedContextData(const QQmlGuardedContextData &);
+ friend class QQmlContextData;
+
+ inline void clear();
+
+ QQmlContextData *m_contextData;
+ QQmlGuardedContextData *m_next;
+ QQmlGuardedContextData **m_prev;
+};
+
+QQmlGuardedContextData::QQmlGuardedContextData()
+: m_contextData(0), m_next(0), m_prev(0)
+{
+}
+
+QQmlGuardedContextData::QQmlGuardedContextData(QQmlContextData *data)
+: m_contextData(0), m_next(0), m_prev(0)
+{
+ setContextData(data);
+}
+
+QQmlGuardedContextData::~QQmlGuardedContextData()
+{
+ clear();
+}
+
+void QQmlGuardedContextData::setContextData(QQmlContextData *contextData)
+{
+ clear();
+
+ if (contextData) {
+ m_contextData = contextData;
+ m_next = contextData->contextGuards;
+ if (m_next) m_next->m_prev = &m_next;
+ m_prev = &contextData->contextGuards;
+ contextData->contextGuards = this;
+ }
+}
+
+QQmlContextData *QQmlGuardedContextData::contextData()
+{
+ return m_contextData;
+}
+
+void QQmlGuardedContextData::clear()
+{
+ if (m_prev) {
+ *m_prev = m_next;
+ if (m_next) m_next->m_prev = m_prev;
+ m_contextData = 0;
+ m_next = 0;
+ m_prev = 0;
+ }
+}
+
+QQmlGuardedContextData &
+QQmlGuardedContextData::operator=(QQmlContextData *d)
+{
+ setContextData(d);
+ return *this;
+}
+
+QQmlContextData::ContextGuard::ContextGuard()
+: context(0)
+{
+}
+
+QQmlContextData::ContextGuard &QQmlContextData::ContextGuard::operator=(QObject *obj)
+{
+ QQmlGuard<QObject>::operator=(obj);
+ context.setFlag();
+ bindings.notify(); // For alias connections
+ return *this;
+}
+
+void QQmlContextData::ContextGuard::objectDestroyed(QObject *)
+{
+ if (context->contextObject && !QObjectPrivate::get(context->contextObject)->wasDeleted)
+ bindings.notify();
+}
+
+bool QQmlContextData::ContextGuard::wasSet() const
+{
+ return context.flag();
+}
+
+QT_END_NAMESPACE
+
+#endif // QQMLCONTEXT_P_H
diff --git a/src/qml/qml/qqmlcustomparser.cpp b/src/qml/qml/qqmlcustomparser.cpp
new file mode 100644
index 0000000000..f888b61e7d
--- /dev/null
+++ b/src/qml/qml/qqmlcustomparser.cpp
@@ -0,0 +1,319 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qqmlcustomparser_p.h"
+#include "qqmlcustomparser_p_p.h"
+
+#include "qqmlcompiler_p.h"
+
+#include <QtCore/qdebug.h>
+
+QT_BEGIN_NAMESPACE
+
+using namespace QQmlScript;
+
+/*!
+ \class QQmlCustomParser
+ \brief The QQmlCustomParser class allows you to add new arbitrary types to QML.
+ \internal
+
+ By subclassing QQmlCustomParser, you can add a parser for
+ building a particular type.
+
+ The subclass must implement compile() and setCustomData(), and register
+ itself in the meta type system by calling the macro:
+
+ \code
+ QML_REGISTER_CUSTOM_TYPE(Module, MajorVersion, MinorVersion, Name, TypeClass, ParserClass)
+ \endcode
+*/
+
+/*
+ \fn QByteArray QQmlCustomParser::compile(const QList<QQmlCustomParserProperty> & properties)
+
+ The custom parser processes \a properties, and returns
+ a QByteArray containing data meaningful only to the
+ custom parser; the type engine will pass this same data to
+ setCustomData() when making an instance of the data.
+
+ Errors must be reported via the error() functions.
+
+ The QByteArray may be cached between executions of the system, so
+ it must contain correctly-serialized data (not, for example,
+ pointers to stack objects).
+*/
+
+/*
+ \fn void QQmlCustomParser::setCustomData(QObject *object, const QByteArray &data)
+
+ This function sets \a object to have the properties defined
+ by \a data, which is a block of data previously returned by a call
+ to compile().
+
+ Errors should be reported using qmlInfo(object).
+
+ The \a object will be an instance of the TypeClass specified by QML_REGISTER_CUSTOM_TYPE.
+*/
+
+QQmlCustomParserNode
+QQmlCustomParserNodePrivate::fromObject(QQmlScript::Object *root)
+{
+ QQmlCustomParserNode rootNode;
+ rootNode.d->name = root->typeName;
+ rootNode.d->location = root->location.start;
+
+ for (Property *p = root->properties.first(); p; p = root->properties.next(p)) {
+ rootNode.d->properties << fromProperty(p);
+ }
+
+ if (root->defaultProperty)
+ rootNode.d->properties << fromProperty(root->defaultProperty);
+
+ return rootNode;
+}
+
+QQmlCustomParserProperty
+QQmlCustomParserNodePrivate::fromProperty(QQmlScript::Property *p)
+{
+ QQmlCustomParserProperty prop;
+ prop.d->name = p->name().toString();
+ prop.d->isList = p->values.isMany();
+ prop.d->location = p->location.start;
+
+ if (p->value) {
+ QQmlCustomParserNode node = fromObject(p->value);
+ QList<QQmlCustomParserProperty> props = node.properties();
+ for (int ii = 0; ii < props.count(); ++ii)
+ prop.d->values << QVariant::fromValue(props.at(ii));
+ } else {
+ for (QQmlScript::Value *v = p->values.first(); v; v = p->values.next(v)) {
+ v->type = QQmlScript::Value::Literal;
+
+ if(v->object) {
+ QQmlCustomParserNode node = fromObject(v->object);
+ prop.d->values << QVariant::fromValue(node);
+ } else {
+ prop.d->values << QVariant::fromValue(v->value);
+ }
+
+ }
+ }
+
+ return prop;
+}
+
+QQmlCustomParserNode::QQmlCustomParserNode()
+: d(new QQmlCustomParserNodePrivate)
+{
+}
+
+QQmlCustomParserNode::QQmlCustomParserNode(const QQmlCustomParserNode &other)
+: d(new QQmlCustomParserNodePrivate)
+{
+ *this = other;
+}
+
+QQmlCustomParserNode &QQmlCustomParserNode::operator=(const QQmlCustomParserNode &other)
+{
+ d->name = other.d->name;
+ d->properties = other.d->properties;
+ d->location = other.d->location;
+ return *this;
+}
+
+QQmlCustomParserNode::~QQmlCustomParserNode()
+{
+ delete d; d = 0;
+}
+
+QString QQmlCustomParserNode::name() const
+{
+ return d->name;
+}
+
+QList<QQmlCustomParserProperty> QQmlCustomParserNode::properties() const
+{
+ return d->properties;
+}
+
+QQmlScript::Location QQmlCustomParserNode::location() const
+{
+ return d->location;
+}
+
+QQmlCustomParserProperty::QQmlCustomParserProperty()
+: d(new QQmlCustomParserPropertyPrivate)
+{
+}
+
+QQmlCustomParserProperty::QQmlCustomParserProperty(const QQmlCustomParserProperty &other)
+: d(new QQmlCustomParserPropertyPrivate)
+{
+ *this = other;
+}
+
+QQmlCustomParserProperty &QQmlCustomParserProperty::operator=(const QQmlCustomParserProperty &other)
+{
+ d->name = other.d->name;
+ d->isList = other.d->isList;
+ d->values = other.d->values;
+ d->location = other.d->location;
+ return *this;
+}
+
+QQmlCustomParserProperty::~QQmlCustomParserProperty()
+{
+ delete d; d = 0;
+}
+
+QString QQmlCustomParserProperty::name() const
+{
+ return d->name;
+}
+
+bool QQmlCustomParserProperty::isList() const
+{
+ return d->isList;
+}
+
+QQmlScript::Location QQmlCustomParserProperty::location() const
+{
+ return d->location;
+}
+
+QList<QVariant> QQmlCustomParserProperty::assignedValues() const
+{
+ return d->values;
+}
+
+void QQmlCustomParser::clearErrors()
+{
+ exceptions.clear();
+}
+
+/*!
+ Reports an error with the given \a description.
+
+ This can only be used during the compile() step. For errors during setCustomData(), use qmlInfo().
+
+ An error is generated referring to the position of the element in the source file.
+*/
+void QQmlCustomParser::error(const QString& description)
+{
+ Q_ASSERT(object);
+ QQmlError error;
+ QString exceptionDescription;
+ error.setLine(object->location.start.line);
+ error.setColumn(object->location.start.column);
+ error.setDescription(description);
+ exceptions << error;
+}
+
+/*!
+ Reports an error in parsing \a prop, with the given \a description.
+
+ An error is generated referring to the position of \a node in the source file.
+*/
+void QQmlCustomParser::error(const QQmlCustomParserProperty& prop, const QString& description)
+{
+ QQmlError error;
+ QString exceptionDescription;
+ error.setLine(prop.location().line);
+ error.setColumn(prop.location().column);
+ error.setDescription(description);
+ exceptions << error;
+}
+
+/*!
+ Reports an error in parsing \a node, with the given \a description.
+
+ An error is generated referring to the position of \a node in the source file.
+*/
+void QQmlCustomParser::error(const QQmlCustomParserNode& node, const QString& description)
+{
+ QQmlError error;
+ QString exceptionDescription;
+ error.setLine(node.location().line);
+ error.setColumn(node.location().column);
+ error.setDescription(description);
+ exceptions << error;
+}
+
+/*!
+ If \a script is a simply enum expression (eg. Text.AlignLeft),
+ returns the integer equivalent (eg. 1).
+
+ Otherwise, returns -1.
+*/
+int QQmlCustomParser::evaluateEnum(const QByteArray& script) const
+{
+ return compiler->evaluateEnum(script);
+}
+
+/*!
+ Resolves \a name to a type, or 0 if it is not a type. This can be used
+ to type-check object nodes.
+*/
+const QMetaObject *QQmlCustomParser::resolveType(const QString& name) const
+{
+ return compiler->resolveType(name);
+}
+
+/*!
+ Rewrites \a value and returns an identifier that can be
+ used to construct the binding later. \a name
+ is used as the name of the rewritten function.
+*/
+QQmlBinding::Identifier QQmlCustomParser::rewriteBinding(const QQmlScript::Variant &value, const QString& name)
+{
+ return compiler->rewriteBinding(value, name);
+}
+
+/*!
+ Returns a rewritten \a handler. \a name
+ is used as the name of the rewritten function.
+*/
+QString QQmlCustomParser::rewriteSignalHandler(const QQmlScript::Variant &value, const QString &name)
+{
+ return compiler->rewriteSignalHandler(value , name);
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlcustomparser_p.h b/src/qml/qml/qqmlcustomparser_p.h
new file mode 100644
index 0000000000..ecc4bae4c3
--- /dev/null
+++ b/src/qml/qml/qqmlcustomparser_p.h
@@ -0,0 +1,168 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLCUSTOMPARSER_H
+#define QQMLCUSTOMPARSER_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 "qqmlmetatype_p.h"
+#include "qqmlerror.h"
+#include "qqmlscript_p.h"
+#include "qqmlbinding_p.h"
+
+#include <QtCore/qbytearray.h>
+#include <QtCore/qxmlstream.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+
+class QQmlCompiler;
+
+class QQmlCustomParserPropertyPrivate;
+class Q_QML_EXPORT QQmlCustomParserProperty
+{
+public:
+ QQmlCustomParserProperty();
+ QQmlCustomParserProperty(const QQmlCustomParserProperty &);
+ QQmlCustomParserProperty &operator=(const QQmlCustomParserProperty &);
+ ~QQmlCustomParserProperty();
+
+ QString name() const;
+ QQmlScript::Location location() const;
+
+ bool isList() const;
+ // Will be one of QQmlScript::Variant, QQmlCustomParserProperty or
+ // QQmlCustomParserNode
+ QList<QVariant> assignedValues() const;
+
+private:
+ friend class QQmlCustomParserNodePrivate;
+ friend class QQmlCustomParserPropertyPrivate;
+ QQmlCustomParserPropertyPrivate *d;
+};
+
+class QQmlCustomParserNodePrivate;
+class Q_QML_EXPORT QQmlCustomParserNode
+{
+public:
+ QQmlCustomParserNode();
+ QQmlCustomParserNode(const QQmlCustomParserNode &);
+ QQmlCustomParserNode &operator=(const QQmlCustomParserNode &);
+ ~QQmlCustomParserNode();
+
+ QString name() const;
+ QQmlScript::Location location() const;
+
+ QList<QQmlCustomParserProperty> properties() const;
+
+private:
+ friend class QQmlCustomParserNodePrivate;
+ QQmlCustomParserNodePrivate *d;
+};
+
+class Q_QML_EXPORT QQmlCustomParser
+{
+public:
+ enum Flag {
+ NoFlag = 0x00000000,
+ AcceptsAttachedProperties = 0x00000001,
+ AcceptsSignalHandlers = 0x00000002
+ };
+ Q_DECLARE_FLAGS(Flags, Flag)
+
+ QQmlCustomParser() : compiler(0), object(0), m_flags(NoFlag) {}
+ QQmlCustomParser(Flags f) : compiler(0), object(0), m_flags(f) {}
+ virtual ~QQmlCustomParser() {}
+
+ void clearErrors();
+ Flags flags() const { return m_flags; }
+
+ virtual QByteArray compile(const QList<QQmlCustomParserProperty> &)=0;
+ virtual void setCustomData(QObject *, const QByteArray &)=0;
+
+ QList<QQmlError> errors() const { return exceptions; }
+
+protected:
+ void error(const QString& description);
+ void error(const QQmlCustomParserProperty&, const QString& description);
+ void error(const QQmlCustomParserNode&, const QString& description);
+
+ int evaluateEnum(const QByteArray&) const;
+
+ const QMetaObject *resolveType(const QString&) const;
+
+ QQmlBinding::Identifier rewriteBinding(const QQmlScript::Variant&, const QString&);
+ QString rewriteSignalHandler(const QQmlScript::Variant&, const QString&);
+
+private:
+ QList<QQmlError> exceptions;
+ QQmlCompiler *compiler;
+ QQmlScript::Object *object;
+ Flags m_flags;
+ friend class QQmlCompiler;
+};
+Q_DECLARE_OPERATORS_FOR_FLAGS(QQmlCustomParser::Flags);
+
+#if 0
+#define QML_REGISTER_CUSTOM_TYPE(URI, VERSION_MAJ, VERSION_MIN, NAME, TYPE, CUSTOMTYPE) \
+ qmlRegisterCustomType<TYPE>(#URI, VERSION_MAJ, VERSION_MIN, #NAME, #TYPE, new CUSTOMTYPE)
+#endif
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(QQmlCustomParserProperty)
+Q_DECLARE_METATYPE(QQmlCustomParserNode)
+
+QT_END_HEADER
+
+#endif
diff --git a/src/qml/qml/qqmlcustomparser_p_p.h b/src/qml/qml/qqmlcustomparser_p_p.h
new file mode 100644
index 0000000000..c861f9e944
--- /dev/null
+++ b/src/qml/qml/qqmlcustomparser_p_p.h
@@ -0,0 +1,89 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLCUSTOMPARSER_P_H
+#define QQMLCUSTOMPARSER_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 "qqmlcustomparser_p.h"
+
+#include "qqmlscript_p.h"
+
+#include <QtCore/qglobal.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQmlCustomParserNodePrivate
+{
+public:
+ QString name;
+ QList<QQmlCustomParserProperty> properties;
+ QQmlScript::Location location;
+
+ static QQmlCustomParserNode fromObject(QQmlScript::Object *);
+ static QQmlCustomParserProperty fromProperty(QQmlScript::Property *);
+};
+
+class QQmlCustomParserPropertyPrivate
+{
+public:
+ QQmlCustomParserPropertyPrivate()
+ : isList(false) {}
+
+ QString name;
+ bool isList;
+ QQmlScript::Location location;
+ QList<QVariant> values;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQMLCUSTOMPARSER_P_H
diff --git a/src/qml/qml/qqmldata_p.h b/src/qml/qml/qqmldata_p.h
new file mode 100644
index 0000000000..e4ba44583d
--- /dev/null
+++ b/src/qml/qml/qqmldata_p.h
@@ -0,0 +1,207 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLDATA_P_H
+#define QQMLDATA_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qtqmlglobal_p.h>
+#include <private/qobject_p.h>
+#include <private/qv8_p.h>
+
+QT_BEGIN_NAMESPACE
+
+template <class Key, class T> class QHash;
+class QQmlGuardImpl;
+class QQmlCompiledData;
+class QQmlAbstractBinding;
+class QQmlContext;
+class QQmlPropertyCache;
+class QQmlContextData;
+class QQmlNotifier;
+class QQmlDataExtended;
+class QQmlNotifierEndpoint;
+// This class is structured in such a way, that simply zero'ing it is the
+// default state for elemental object allocations. This is crucial in the
+// workings of the QQmlInstruction::CreateSimpleObject instruction.
+// Don't change anything here without first considering that case!
+class Q_QML_EXPORT QQmlData : public QAbstractDeclarativeData
+{
+public:
+ QQmlData()
+ : ownMemory(true), ownContext(false), indestructible(true), explicitIndestructibleSet(false),
+ hasTaintedV8Object(false), notifyList(0), context(0), outerContext(0), bindings(0),
+ nextContextObject(0), prevContextObject(0), bindingBitsSize(0), bindingBits(0),
+ lineNumber(0), columnNumber(0), deferredComponent(0), deferredIdx(0), v8objectid(0),
+ propertyCache(0), guards(0), extendedData(0) {
+ init();
+ }
+
+ static inline void init() {
+ QAbstractDeclarativeData::destroyed = destroyed;
+ QAbstractDeclarativeData::parentChanged = parentChanged;
+ QAbstractDeclarativeData::objectNameChanged = objectNameChanged;
+ QAbstractDeclarativeData::signalEmitted = signalEmitted;
+ }
+
+ static void destroyed(QAbstractDeclarativeData *, QObject *);
+ static void parentChanged(QAbstractDeclarativeData *, QObject *, QObject *);
+ static void objectNameChanged(QAbstractDeclarativeData *, QObject *);
+ static void signalEmitted(QAbstractDeclarativeData *, QObject *, int, void **);
+
+ void destroyed(QObject *);
+ void parentChanged(QObject *, QObject *);
+ void objectNameChanged(QObject *);
+
+ void setImplicitDestructible() {
+ if (!explicitIndestructibleSet) indestructible = false;
+ }
+
+ quint32 ownMemory:1;
+ quint32 ownContext:1;
+ quint32 indestructible:1;
+ quint32 explicitIndestructibleSet:1;
+ quint32 hasTaintedV8Object:1;
+ quint32 dummy:27;
+
+ struct NotifyList {
+ quint64 connectionMask;
+
+ quint16 maximumTodoIndex;
+ quint16 notifiesSize;
+
+ QQmlNotifierEndpoint *todo;
+ QQmlNotifierEndpoint**notifies;
+ void layout();
+ private:
+ void layout(QQmlNotifierEndpoint*);
+ };
+ NotifyList *notifyList;
+
+ inline QQmlNotifierEndpoint *notify(int index);
+ void addNotify(int index, QQmlNotifierEndpoint *);
+
+ // The context that created the C++ object
+ QQmlContextData *context;
+ // The outermost context in which this object lives
+ QQmlContextData *outerContext;
+
+ QQmlAbstractBinding *bindings;
+
+ // Linked list for QQmlContext::contextObjects
+ QQmlData *nextContextObject;
+ QQmlData**prevContextObject;
+
+ int bindingBitsSize;
+ quint32 *bindingBits;
+ bool hasBindingBit(int) const;
+ void clearBindingBit(int);
+ void setBindingBit(QObject *obj, int);
+
+ ushort lineNumber;
+ ushort columnNumber;
+
+ QQmlCompiledData *deferredComponent; // Can't this be found from the context?
+ unsigned int deferredIdx;
+
+ quint32 v8objectid;
+ v8::Persistent<v8::Object> v8object;
+
+ QQmlPropertyCache *propertyCache;
+
+ QQmlGuardImpl *guards;
+
+ static QQmlData *get(const QObject *object, bool create = false) {
+ QObjectPrivate *priv = QObjectPrivate::get(const_cast<QObject *>(object));
+ if (priv->wasDeleted) {
+ Q_ASSERT(!create);
+ return 0;
+ } else if (priv->declarativeData) {
+ return static_cast<QQmlData *>(priv->declarativeData);
+ } else if (create) {
+ priv->declarativeData = new QQmlData;
+ return static_cast<QQmlData *>(priv->declarativeData);
+ } else {
+ return 0;
+ }
+ }
+
+ bool hasExtendedData() const { return extendedData != 0; }
+ QQmlNotifier *objectNameNotifier() const;
+ QHash<int, QObject *> *attachedProperties() const;
+
+private:
+ // For objectNameNotifier and attachedProperties
+ mutable QQmlDataExtended *extendedData;
+};
+
+QQmlNotifierEndpoint *QQmlData::notify(int index)
+{
+ Q_ASSERT(index <= 0xFFFF);
+
+ if (!notifyList || !(notifyList->connectionMask & (1ULL << quint64(index % 64)))) {
+ return 0;
+ } else if (index < notifyList->notifiesSize) {
+ return notifyList->notifies[index];
+ } else if (index <= notifyList->maximumTodoIndex) {
+ notifyList->layout();
+ }
+
+ if (index < notifyList->notifiesSize) {
+ return notifyList->notifies[index];
+ } else {
+ return 0;
+ }
+}
+
+QT_END_NAMESPACE
+
+#endif // QQMLDATA_P_H
diff --git a/src/qml/qml/qqmldirparser.cpp b/src/qml/qml/qqmldirparser.cpp
new file mode 100644
index 0000000000..7b99214f04
--- /dev/null
+++ b/src/qml/qml/qqmldirparser.cpp
@@ -0,0 +1,298 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qqmldirparser_p.h"
+#include "qqmlerror.h"
+#include "qqmlglobal_p.h"
+
+#include <QtCore/QTextStream>
+#include <QtCore/QFile>
+#include <QtCore/QtDebug>
+
+QT_BEGIN_NAMESPACE
+
+QQmlDirParser::QQmlDirParser()
+ : _isParsed(false)
+{
+}
+
+QQmlDirParser::~QQmlDirParser()
+{
+}
+
+QUrl QQmlDirParser::url() const
+{
+ return _url;
+}
+
+void QQmlDirParser::setUrl(const QUrl &url)
+{
+ _url = url;
+}
+
+QString QQmlDirParser::fileSource() const
+{
+ return _filePathSouce;
+}
+
+void QQmlDirParser::setFileSource(const QString &filePath)
+{
+ _filePathSouce = filePath;
+}
+
+QString QQmlDirParser::source() const
+{
+ return _source;
+}
+
+void QQmlDirParser::setSource(const QString &source)
+{
+ _isParsed = false;
+ _source = source;
+}
+
+bool QQmlDirParser::isParsed() const
+{
+ return _isParsed;
+}
+
+bool QQmlDirParser::parse()
+{
+ if (_isParsed)
+ return true;
+
+ _isParsed = true;
+ _errors.clear();
+ _plugins.clear();
+ _components.clear();
+ _scripts.clear();
+
+ if (_source.isEmpty() && !_filePathSouce.isEmpty()) {
+ QFile file(_filePathSouce);
+ if (!QQml_isFileCaseCorrect(_filePathSouce)) {
+ QQmlError error;
+ error.setDescription(QString::fromUtf8("cannot load module \"$$URI$$\": File name case mismatch for \"%1\"").arg(_filePathSouce));
+ _errors.prepend(error);
+ return false;
+ } else if (file.open(QFile::ReadOnly)) {
+ _source = QString::fromUtf8(file.readAll());
+ } else {
+ QQmlError error;
+ error.setDescription(QString::fromUtf8("module \"$$URI$$\" definition \"%1\" not readable").arg(_filePathSouce));
+ _errors.prepend(error);
+ return false;
+ }
+ }
+
+ QTextStream stream(&_source);
+ int lineNumber = 0;
+
+ forever {
+ ++lineNumber;
+
+ const QString line = stream.readLine();
+ if (line.isNull())
+ break;
+
+ QString sections[3];
+ int sectionCount = 0;
+
+ int index = 0;
+ const int length = line.length();
+
+ while (index != length) {
+ const QChar ch = line.at(index);
+
+ if (ch.isSpace()) {
+ do { ++index; }
+ while (index != length && line.at(index).isSpace());
+
+ } else if (ch == QLatin1Char('#')) {
+ // recognized a comment
+ break;
+
+ } else {
+ const int start = index;
+
+ do { ++index; }
+ while (index != length && !line.at(index).isSpace());
+
+ const QString lexeme = line.mid(start, index - start);
+
+ if (sectionCount >= 3) {
+ reportError(lineNumber, start, QLatin1String("unexpected token"));
+
+ } else {
+ sections[sectionCount++] = lexeme;
+ }
+ }
+ }
+
+ if (sectionCount == 0) {
+ continue; // no sections, no party.
+
+ } else if (sections[0] == QLatin1String("plugin")) {
+ if (sectionCount < 2) {
+ reportError(lineNumber, -1,
+ QString::fromUtf8("plugin directive requires one or two arguments, but %1 were provided").arg(sectionCount - 1));
+
+ continue;
+ }
+
+ const Plugin entry(sections[1], sections[2]);
+
+ _plugins.append(entry);
+
+ } else if (sections[0] == QLatin1String("internal")) {
+ if (sectionCount != 3) {
+ reportError(lineNumber, -1,
+ QString::fromUtf8("internal types require 2 arguments, but %1 were provided").arg(sectionCount - 1));
+ continue;
+ }
+ Component entry(sections[1], sections[2], -1, -1);
+ entry.internal = true;
+ _components.append(entry);
+ } else if (sections[0] == QLatin1String("typeinfo")) {
+ if (sectionCount != 2) {
+ reportError(lineNumber, -1,
+ QString::fromUtf8("typeinfo requires 1 argument, but %1 were provided").arg(sectionCount - 1));
+ continue;
+ }
+#ifdef QT_CREATOR
+ TypeInfo typeInfo(sections[1]);
+ _typeInfos.append(typeInfo);
+#endif
+
+ } else if (sectionCount == 2) {
+ // No version specified (should only be used for relative qmldir files)
+ const Component entry(sections[0], sections[1], -1, -1);
+ _components.append(entry);
+ } else if (sectionCount == 3) {
+ const QString &version = sections[1];
+ const int dotIndex = version.indexOf(QLatin1Char('.'));
+
+ if (dotIndex == -1) {
+ reportError(lineNumber, -1, QLatin1String("expected '.'"));
+ } else if (version.indexOf(QLatin1Char('.'), dotIndex + 1) != -1) {
+ reportError(lineNumber, -1, QLatin1String("unexpected '.'"));
+ } else {
+ bool validVersionNumber = false;
+ const int majorVersion = version.left(dotIndex).toInt(&validVersionNumber);
+
+ if (validVersionNumber) {
+ const int minorVersion = version.mid(dotIndex + 1).toInt(&validVersionNumber);
+
+ if (validVersionNumber) {
+ const QString &fileName = sections[2];
+
+ if (fileName.endsWith(QLatin1String(".js"))) {
+ // A 'js' extension indicates a namespaced script import
+ const Script entry(sections[0], fileName, majorVersion, minorVersion);
+ _scripts.append(entry);
+ } else {
+ const Component entry(sections[0], fileName, majorVersion, minorVersion);
+ _components.append(entry);
+ }
+ }
+ }
+ }
+ } else {
+ reportError(lineNumber, -1,
+ QString::fromUtf8("a component declaration requires two or three arguments, but %1 were provided").arg(sectionCount));
+ }
+ }
+
+ return hasError();
+}
+
+void QQmlDirParser::reportError(int line, int column, const QString &description)
+{
+ QQmlError error;
+ error.setUrl(_url);
+ error.setLine(line);
+ error.setColumn(column);
+ error.setDescription(description);
+ _errors.append(error);
+}
+
+bool QQmlDirParser::hasError() const
+{
+ if (! _errors.isEmpty())
+ return true;
+
+ return false;
+}
+
+QList<QQmlError> QQmlDirParser::errors(const QString &uri) const
+{
+ QList<QQmlError> errors = _errors;
+ for (int i = 0; i < errors.size(); ++i) {
+ QQmlError &e = errors[i];
+ QString description = e.description();
+ description.replace(QLatin1String("$$URI$$"), uri);
+ e.setDescription(description);
+ }
+ return errors;
+}
+
+QList<QQmlDirParser::Plugin> QQmlDirParser::plugins() const
+{
+ return _plugins;
+}
+
+QList<QQmlDirParser::Component> QQmlDirParser::components() const
+{
+ return _components;
+}
+
+QList<QQmlDirParser::Script> QQmlDirParser::scripts() const
+{
+ return _scripts;
+}
+
+#ifdef QT_CREATOR
+QList<QQmlDirParser::TypeInfo> QQmlDirParser::typeInfos() const
+{
+ return _typeInfos;
+}
+#endif
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmldirparser_p.h b/src/qml/qml/qqmldirparser_p.h
new file mode 100644
index 0000000000..8c681309ac
--- /dev/null
+++ b/src/qml/qml/qqmldirparser_p.h
@@ -0,0 +1,166 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLDIRPARSER_P_H
+#define QQMLDIRPARSER_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/QUrl>
+#include <QtCore/QHash>
+
+QT_BEGIN_NAMESPACE
+
+class QQmlError;
+class QQmlDirParser
+{
+ Q_DISABLE_COPY(QQmlDirParser)
+
+public:
+ QQmlDirParser();
+ ~QQmlDirParser();
+
+ QUrl url() const;
+ void setUrl(const QUrl &url);
+
+ QString fileSource() const;
+ void setFileSource(const QString &filePath);
+
+ QString source() const;
+ void setSource(const QString &source);
+
+ bool isParsed() const;
+ bool parse();
+
+ bool hasError() const;
+ QList<QQmlError> errors(const QString &uri) const;
+
+ struct Plugin
+ {
+ Plugin() {}
+
+ Plugin(const QString &name, const QString &path)
+ : name(name), path(path) {}
+
+ QString name;
+ QString path;
+ };
+
+ struct Component
+ {
+ Component()
+ : majorVersion(0), minorVersion(0), internal(false) {}
+
+ Component(const QString &typeName, const QString &fileName, int majorVersion, int minorVersion)
+ : typeName(typeName), fileName(fileName), majorVersion(majorVersion), minorVersion(minorVersion),
+ internal(false) {}
+
+ QString typeName;
+ QString fileName;
+ int majorVersion;
+ int minorVersion;
+ bool internal;
+ };
+
+ struct Script
+ {
+ Script()
+ : majorVersion(0), minorVersion(0) {}
+
+ Script(const QString &nameSpace, const QString &fileName, int majorVersion, int minorVersion)
+ : nameSpace(nameSpace), fileName(fileName), majorVersion(majorVersion), minorVersion(minorVersion) {}
+
+ QString nameSpace;
+ QString fileName;
+ int majorVersion;
+ int minorVersion;
+ };
+
+ QList<Component> components() const;
+ QList<Script> scripts() const;
+ QList<Plugin> plugins() const;
+
+#ifdef QT_CREATOR
+ struct TypeInfo
+ {
+ TypeInfo() {}
+ TypeInfo(const QString &fileName)
+ : fileName(fileName) {}
+
+ QString fileName;
+ };
+
+ QList<TypeInfo> typeInfos() const;
+#endif
+
+private:
+ void reportError(int line, int column, const QString &message);
+
+private:
+ QList<QQmlError> _errors;
+ QUrl _url;
+ QString _source;
+ QString _filePathSouce;
+ QList<Component> _components;
+ QList<Script> _scripts;
+ QList<Plugin> _plugins;
+#ifdef QT_CREATOR
+ QList<TypeInfo> _typeInfos;
+#endif
+ unsigned _isParsed: 1;
+};
+
+typedef QList<QQmlDirParser::Component> QQmlDirComponents;
+typedef QList<QQmlDirParser::Script> QQmlDirScripts;
+
+
+QT_END_NAMESPACE
+
+#endif // QQMLDIRPARSER_P_H
diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp
new file mode 100644
index 0000000000..8cfe635543
--- /dev/null
+++ b/src/qml/qml/qqmlengine.cpp
@@ -0,0 +1,1854 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qqmlengine_p.h"
+#include "qqmlengine.h"
+#include "qqmlcomponentattached_p.h"
+
+#include "qqmlcontext_p.h"
+#include "qqmlcompiler_p.h"
+#include "qqml.h"
+#include "qqmlcontext.h"
+#include "qqmlexpression.h"
+#include "qqmlcomponent.h"
+#include "qqmlbinding_p_p.h"
+#include "qqmlvme_p.h"
+#include <private/qqmlenginedebugservice_p.h>
+#include "qqmlstringconverters_p.h"
+#include "qqmlxmlhttprequest_p.h"
+#include "qqmlscriptstring.h"
+#include "qqmlglobal_p.h"
+#include "qquicklistmodel_p.h"
+#include "qquickworkerscript_p.h"
+#include "qqmlcomponent_p.h"
+#include "qqmlnetworkaccessmanagerfactory.h"
+#include "qqmlimageprovider.h"
+#include "qqmldirparser_p.h"
+#include "qqmlextensioninterface.h"
+#include "qqmllist_p.h"
+#include "qqmltypenamecache_p.h"
+#include "qqmlnotifier_p.h"
+#include <private/qqmlprofilerservice_p.h>
+#include <private/qquickapplication_p.h>
+#include <private/qv8debugservice_p.h>
+#include <private/qdebugmessageservice_p.h>
+#include "qqmlincubator.h"
+#include <private/qv8profilerservice_p.h>
+
+#include <QtCore/qstandardpaths.h>
+#include <QtCore/qsettings.h>
+
+#include <QtCore/qmetaobject.h>
+#include <QNetworkAccessManager>
+#include <QDebug>
+#include <QMetaObject>
+#include <QtCore/qcoreapplication.h>
+#include <QtCore/qdir.h>
+#include <QtCore/qmutex.h>
+#include <QtNetwork/qnetworkconfigmanager.h>
+
+#include <private/qobject_p.h>
+
+#include <private/qqmllocale_p.h>
+
+#ifdef Q_OS_WIN // for %APPDATA%
+#include <qt_windows.h>
+#include <qlibrary.h>
+#include <windows.h>
+
+#define CSIDL_APPDATA 0x001a // <username>\Application Data
+#endif
+
+Q_DECLARE_METATYPE(QQmlProperty)
+
+QT_BEGIN_NAMESPACE
+
+void qmlRegisterBaseTypes(const char *uri, int versionMajor, int versionMinor)
+{
+ QQmlEnginePrivate::registerBaseTypes(uri, versionMajor, versionMinor);
+ QQmlValueTypeFactory::registerBaseTypes(uri, versionMajor, versionMinor);
+}
+
+/*!
+ \qmlclass QtObject QObject
+ \ingroup qml-utility-elements
+ \since 4.7
+ \brief The QtObject element is the most basic element in QML.
+
+ The QtObject element is a non-visual element which contains only the
+ objectName property.
+
+ It can be useful to create a QtObject if you need an extremely
+ lightweight element to enclose a set of custom properties:
+
+ \snippet doc/src/snippets/qml/qtobject.qml 0
+
+ It can also be useful for C++ integration, as it is just a plain
+ QObject. See the QObject documentation for further details.
+*/
+/*!
+ \qmlproperty string QtObject::objectName
+ This property holds the QObject::objectName for this specific object instance.
+
+ This allows a C++ application to locate an item within a QML component
+ using the QObject::findChild() method. For example, the following C++
+ application locates the child \l Rectangle item and dynamically changes its
+ \c color value:
+
+ \qml
+ // MyRect.qml
+
+ import QtQuick 2.0
+
+ Item {
+ width: 200; height: 200
+
+ Rectangle {
+ anchors.fill: parent
+ color: "red"
+ objectName: "myRect"
+ }
+ }
+ \endqml
+
+ \code
+ // main.cpp
+
+ QQuickView view;
+ view.setSource(QUrl::fromLocalFile("MyRect.qml"));
+ view.show();
+
+ QQuickItem *item = view.rootObject()->findChild<QQuickItem*>("myRect");
+ if (item)
+ item->setProperty("color", QColor(Qt::yellow));
+ \endcode
+*/
+
+bool QQmlEnginePrivate::qml_debugging_enabled = false;
+
+void QQmlEnginePrivate::registerBaseTypes(const char *uri, int versionMajor, int versionMinor)
+{
+ qmlRegisterType<QQmlComponent>(uri,versionMajor,versionMinor,"Component");
+ qmlRegisterType<QObject>(uri,versionMajor,versionMinor,"QtObject");
+ qmlRegisterType<QQuickListElement>(uri, versionMajor, versionMinor,"ListElement");
+ qmlRegisterCustomType<QQuickListModel>(uri, versionMajor, versionMinor,"ListModel", new QQuickListModelParser);
+ qmlRegisterType<QQuickWorkerScript>(uri,versionMajor,versionMinor,"WorkerScript");
+}
+
+void QQmlEnginePrivate::defineModule()
+{
+ registerBaseTypes("QtQuick", 2, 0);
+ qmlRegisterType<QQmlBinding>();
+ qmlRegisterUncreatableType<QQuickApplication>("QtQuick",2,0,"Application", QQuickApplication::tr("Application is an abstract class"));
+ qmlRegisterUncreatableType<QQmlLocale>("QtQuick",2,0,"Locale",QQmlEngine::tr("Locale cannot be instantiated. Use Qt.locale()"));
+}
+
+/*!
+\qmlclass Qt QQmlEnginePrivate
+ \ingroup qml-utility-elements
+\brief The QML global Qt object provides useful enums and functions from Qt.
+
+\keyword QmlGlobalQtObject
+
+\brief The \c Qt object provides useful enums and functions from Qt, for use in all QML files.
+
+The \c Qt object is a global object with utility functions, properties and enums.
+
+It is not instantiable; to use it, call the members of the global \c Qt object directly.
+For example:
+
+\qml
+import QtQuick 2.0
+
+Text {
+ color: Qt.rgba(1, 0, 0, 1)
+ text: Qt.md5("hello, world")
+}
+\endqml
+
+
+\section1 Enums
+
+The Qt object contains the enums available in the \l {Qt Namespace}. For example, you can access
+the \l Qt::LeftButton and \l Qt::RightButton enum values as \c Qt.LeftButton and \c Qt.RightButton.
+
+
+\section1 Types
+The Qt object also contains helper functions for creating objects of specific
+data types. This is primarily useful when setting the properties of an item
+when the property has one of the following types:
+
+\list
+\o \c color - use \l{Qt::rgba()}{Qt.rgba()}, \l{Qt::hsla()}{Qt.hsla()}, \l{Qt::darker()}{Qt.darker()}, \l{Qt::lighter()}{Qt.lighter()} or \l{Qt::tint()}{Qt.tint()}
+\o \c rect - use \l{Qt::rect()}{Qt.rect()}
+\o \c point - use \l{Qt::point()}{Qt.point()}
+\o \c size - use \l{Qt::size()}{Qt.size()}
+\o \c vector3d - use \l{Qt::vector3d()}{Qt.vector3d()}
+\endlist
+
+There are also string based constructors for these types. See \l{qdeclarativebasictypes.html}{QML Basic Types} for more information.
+
+\section1 Date/Time Formatters
+
+The Qt object contains several functions for formatting QDateTime, QDate and QTime values.
+
+\list
+ \o \l{Qt::formatDateTime}{string Qt.formatDateTime(datetime date, variant format)}
+ \o \l{Qt::formatDate}{string Qt.formatDate(datetime date, variant format)}
+ \o \l{Qt::formatTime}{string Qt.formatTime(datetime date, variant format)}
+\endlist
+
+The format specification is described at \l{Qt::formatDateTime}{Qt.formatDateTime}.
+
+
+\section1 Dynamic Object Creation
+The following functions on the global object allow you to dynamically create QML
+items from files or strings. See \l{Dynamic Object Management in QML} for an overview
+of their use.
+
+\list
+ \o \l{Qt::createComponent()}{object Qt.createComponent(url)}
+ \o \l{Qt::createQmlObject()}{object Qt.createQmlObject(string qml, object parent, string filepath)}
+\endlist
+*/
+
+
+/*!
+ \qmlproperty object Qt::application
+ \since QtQuick 1.1
+
+ The \c application object provides access to global application state
+ properties shared by many QML components.
+
+ Its properties are:
+
+ \table
+ \row
+ \o \c application.active
+ \o
+ This read-only property indicates whether the application is the top-most and focused
+ application, and the user is able to interact with the application. The property
+ is false when the application is in the background, the device keylock or screen
+ saver is active, the screen backlight is turned off, or the global system dialog
+ is being displayed on top of the application. It can be used for stopping and
+ pausing animations, timers and active processing of data in order to save device
+ battery power and free device memory and processor load when the application is not
+ active.
+
+ \row
+ \o \c application.layoutDirection
+ \o
+ This read-only property can be used to query the default layout direction of the
+ application. On system start-up, the default layout direction depends on the
+ application's language. The property has a value of \c Qt.RightToLeft in locales
+ where text and graphic elements are read from right to left, and \c Qt.LeftToRight
+ where the reading direction flows from left to right. You can bind to this
+ property to customize your application layouts to support both layout directions.
+
+ Possible values are:
+
+ \list
+ \o Qt.LeftToRight - Text and graphics elements should be positioned
+ from left to right.
+ \o Qt.RightToLeft - Text and graphics elements should be positioned
+ from right to left.
+ \endlist
+
+ \row
+ \o \c application.inputPanel
+ \o
+ This read-only property allows access to application's QInputPanel object
+ and all its properties and slots. See the QInputPanel documentation for
+ further details. Deprecated in favor of Qt.InputMethod
+ \endtable
+
+ The following example uses the \c application object to indicate
+ whether the application is currently active:
+
+ \snippet doc/src/snippets/qml/application.qml document
+
+ \qmlproperty object Qt::inputMethod
+ \since QtQuick 2.0
+
+ The \c inputMethod object allows access to application's QInputMethod object
+ and all its properties and slots. See the QInputMethod documentation for
+ further details.
+*/
+
+
+/*!
+\qmlmethod object Qt::include(string url, jsobject callback)
+
+Includes another JavaScript file. This method can only be used from within JavaScript files,
+and not regular QML files.
+
+This imports all functions from \a url into the current script's namespace.
+
+Qt.include() returns an object that describes the status of the operation. The object has
+a single property, \c {status}, that is set to one of the following values:
+
+\table
+\header \o Symbol \o Value \o Description
+\row \o result.OK \o 0 \o The include completed successfully.
+\row \o result.LOADING \o 1 \o Data is being loaded from the network.
+\row \o result.NETWORK_ERROR \o 2 \o A network error occurred while fetching the url.
+\row \o result.EXCEPTION \o 3 \o A JavaScript exception occurred while executing the included code.
+An additional \c exception property will be set in this case.
+\endtable
+
+The \c status property will be updated as the operation progresses.
+
+If provided, \a callback is invoked when the operation completes. The callback is passed
+the same object as is returned from the Qt.include() call.
+*/
+// Qt.include() is implemented in qv8include.cpp
+
+
+QQmlEnginePrivate::QQmlEnginePrivate(QQmlEngine *e)
+: propertyCapture(0), rootContext(0), isDebugging(false),
+ outputWarningsToStdErr(true), sharedContext(0), sharedScope(0),
+ cleanup(0), erroredBindings(0), inProgressCreations(0),
+ workerScriptEngine(0), activeVME(0),
+ networkAccessManager(0), networkAccessManagerFactory(0),
+ scarceResourcesRefCount(0), typeLoader(e), importDatabase(e), uniqueId(1),
+ incubatorCount(0), incubationController(0), mutex(QMutex::Recursive)
+{
+}
+
+QQmlEnginePrivate::~QQmlEnginePrivate()
+{
+ Q_ASSERT(inProgressCreations == 0);
+
+ while (cleanup) {
+ QQmlCleanup *c = cleanup;
+ cleanup = c->next;
+ if (cleanup) cleanup->prev = &cleanup;
+ c->next = 0;
+ c->prev = 0;
+ c->clear();
+ }
+
+ doDeleteInEngineThread();
+
+ if (incubationController) incubationController->d = 0;
+ incubationController = 0;
+
+ delete rootContext;
+ rootContext = 0;
+
+ for(QHash<int, QQmlCompiledData*>::ConstIterator iter = m_compositeTypes.constBegin(); iter != m_compositeTypes.constEnd(); ++iter)
+ (*iter)->release();
+ for(QHash<const QMetaObject *, QQmlPropertyCache *>::Iterator iter = propertyCache.begin(); iter != propertyCache.end(); ++iter)
+ (*iter)->release();
+ for(QHash<QPair<QQmlType *, int>, QQmlPropertyCache *>::Iterator iter = typePropertyCache.begin(); iter != typePropertyCache.end(); ++iter)
+ (*iter)->release();
+ for(QHash<QQmlMetaType::ModuleApi, QQmlMetaType::ModuleApiInstance *>::Iterator iter = moduleApiInstances.begin(); iter != moduleApiInstances.end(); ++iter) {
+ delete (*iter)->qobjectApi;
+ delete *iter;
+ }
+}
+
+void QQmlPrivate::qdeclarativeelement_destructor(QObject *o)
+{
+ QObjectPrivate *p = QObjectPrivate::get(o);
+ if (p->declarativeData) {
+ QQmlData *d = static_cast<QQmlData*>(p->declarativeData);
+ if (d->ownContext && d->context) {
+ d->context->destroy();
+ d->context = 0;
+ }
+ }
+}
+
+void QQmlData::destroyed(QAbstractDeclarativeData *d, QObject *o)
+{
+ static_cast<QQmlData *>(d)->destroyed(o);
+}
+
+void QQmlData::parentChanged(QAbstractDeclarativeData *d, QObject *o, QObject *p)
+{
+ static_cast<QQmlData *>(d)->parentChanged(o, p);
+}
+
+void QQmlData::objectNameChanged(QAbstractDeclarativeData *d, QObject *o)
+{
+ static_cast<QQmlData *>(d)->objectNameChanged(o);
+}
+
+void QQmlData::signalEmitted(QAbstractDeclarativeData *, QObject *object, int index, void **)
+{
+ QQmlData *ddata = QQmlData::get(object, false);
+ if (!ddata) return; // Probably being deleted
+
+ QQmlNotifierEndpoint *ep = ddata->notify(index);
+ if (ep) QQmlNotifier::emitNotify(ep);
+}
+
+void QQmlEnginePrivate::init()
+{
+ Q_Q(QQmlEngine);
+
+ static bool firstTime = true;
+ if (firstTime) {
+ qmlRegisterType<QQmlComponent>("QML", 1, 0, "Component");
+
+ firstTime = false;
+ }
+
+ qRegisterMetaType<QVariant>("QVariant");
+ qRegisterMetaType<QQmlScriptString>("QQmlScriptString");
+ qRegisterMetaType<QJSValue>("QJSValue");
+ qRegisterMetaType<QQmlComponent::Status>("QQmlComponent::Status");
+ qRegisterMetaType<QList<QObject*> >("QList<QObject*>");
+ qRegisterMetaType<QList<int> >("QList<int>");
+ qRegisterMetaType<QQmlV8Handle>("QQmlV8Handle");
+
+ QQmlData::init();
+
+ v8engine()->setEngine(q);
+
+ rootContext = new QQmlContext(q,true);
+
+ if (QCoreApplication::instance()->thread() == q->thread() &&
+ QQmlEngineDebugService::isDebuggingEnabled()) {
+ isDebugging = true;
+ QQmlEngineDebugService::instance()->addEngine(q);
+ QV8DebugService::initialize(v8engine());
+ QV8ProfilerService::initialize();
+ QQmlProfilerService::initialize();
+ QDebugMessageService::instance();
+ }
+
+ QString dataLocation = QStandardPaths::writableLocation(QStandardPaths::DataLocation);
+ offlineStoragePath = dataLocation.replace(QLatin1Char('/'), QDir::separator()) +
+ QDir::separator() + QLatin1String("QML") +
+ QDir::separator() + QLatin1String("OfflineStorage");
+}
+
+QQuickWorkerScriptEngine *QQmlEnginePrivate::getWorkerScriptEngine()
+{
+ Q_Q(QQmlEngine);
+ if (!workerScriptEngine)
+ workerScriptEngine = new QQuickWorkerScriptEngine(q);
+ return workerScriptEngine;
+}
+
+/*!
+ \class QQmlEngine
+ \since 4.7
+ \brief The QQmlEngine class provides an environment for instantiating QML components.
+ \mainclass
+
+ Each QML component is instantiated in a QQmlContext.
+ QQmlContext's are essential for passing data to QML
+ components. In QML, contexts are arranged hierarchically and this
+ hierarchy is managed by the QQmlEngine.
+
+ Prior to creating any QML components, an application must have
+ created a QQmlEngine to gain access to a QML context. The
+ following example shows how to create a simple Text item.
+
+ \code
+ QQmlEngine engine;
+ QQmlComponent component(&engine);
+ component.setData("import QtQuick 2.0\nText { text: \"Hello world!\" }", QUrl());
+ QQuickItem *item = qobject_cast<QQuickItem *>(component.create());
+
+ //add item to view, etc
+ ...
+ \endcode
+
+ In this case, the Text item will be created in the engine's
+ \l {QQmlEngine::rootContext()}{root context}.
+
+ \sa QQmlComponent QQmlContext
+*/
+
+/*!
+ Create a new QQmlEngine with the given \a parent.
+*/
+QQmlEngine::QQmlEngine(QObject *parent)
+: QJSEngine(*new QQmlEnginePrivate(this), parent)
+{
+ Q_D(QQmlEngine);
+ d->init();
+}
+
+/*!
+ Destroys the QQmlEngine.
+
+ Any QQmlContext's created on this engine will be
+ invalidated, but not destroyed (unless they are parented to the
+ QQmlEngine object).
+*/
+QQmlEngine::~QQmlEngine()
+{
+ Q_D(QQmlEngine);
+ if (d->isDebugging) {
+ QQmlEngineDebugService::instance()->remEngine(this);
+ }
+
+ // if we are the parent of any of the qobject module api instances,
+ // we need to remove them from our internal list, in order to prevent
+ // a segfault in engine private dtor.
+ QList<QQmlMetaType::ModuleApi> keys = d->moduleApiInstances.keys();
+ QObject *currQObjectApi = 0;
+ QQmlMetaType::ModuleApiInstance *currInstance = 0;
+ foreach (const QQmlMetaType::ModuleApi &key, keys) {
+ currInstance = d->moduleApiInstances.value(key);
+ currQObjectApi = currInstance->qobjectApi;
+ if (this->children().contains(currQObjectApi)) {
+ delete currQObjectApi;
+ delete currInstance;
+ d->moduleApiInstances.remove(key);
+ }
+ }
+
+ // ensure we clean up QObjects with JS ownership
+ d->v8engine()->gc();
+
+ if (d->incubationController)
+ d->incubationController->d = 0;
+}
+
+/*! \fn void QQmlEngine::quit()
+ This signal is emitted when the QML loaded by the engine would like to quit.
+ */
+
+/*! \fn void QQmlEngine::warnings(const QList<QQmlError> &warnings)
+ This signal is emitted when \a warnings messages are generated by QML.
+ */
+
+/*!
+ Clears the engine's internal component cache.
+
+ Normally the QQmlEngine caches components loaded from qml
+ files. This method clears this cache and forces the component to be
+ reloaded.
+ */
+void QQmlEngine::clearComponentCache()
+{
+ Q_D(QQmlEngine);
+ d->typeLoader.clearCache();
+}
+
+/*!
+ Returns the engine's root context.
+
+ The root context is automatically created by the QQmlEngine.
+ Data that should be available to all QML component instances
+ instantiated by the engine should be put in the root context.
+
+ Additional data that should only be available to a subset of
+ component instances should be added to sub-contexts parented to the
+ root context.
+*/
+QQmlContext *QQmlEngine::rootContext() const
+{
+ Q_D(const QQmlEngine);
+ return d->rootContext;
+}
+
+/*!
+ Sets the \a factory to use for creating QNetworkAccessManager(s).
+
+ QNetworkAccessManager is used for all network access by QML. By
+ implementing a factory it is possible to create custom
+ QNetworkAccessManager with specialized caching, proxy and cookie
+ support.
+
+ The factory must be set before executing the engine.
+*/
+void QQmlEngine::setNetworkAccessManagerFactory(QQmlNetworkAccessManagerFactory *factory)
+{
+ Q_D(QQmlEngine);
+ QMutexLocker locker(&d->mutex);
+ d->networkAccessManagerFactory = factory;
+}
+
+/*!
+ Returns the current QQmlNetworkAccessManagerFactory.
+
+ \sa setNetworkAccessManagerFactory()
+*/
+QQmlNetworkAccessManagerFactory *QQmlEngine::networkAccessManagerFactory() const
+{
+ Q_D(const QQmlEngine);
+ return d->networkAccessManagerFactory;
+}
+
+void QQmlEnginePrivate::registerFinalizeCallback(QObject *obj, int index)
+{
+ if (activeVME) {
+ activeVME->finalizeCallbacks.append(qMakePair(QQmlGuard<QObject>(obj), index));
+ } else {
+ void *args[] = { 0 };
+ QMetaObject::metacall(obj, QMetaObject::InvokeMetaMethod, index, args);
+ }
+}
+
+QNetworkAccessManager *QQmlEnginePrivate::createNetworkAccessManager(QObject *parent) const
+{
+ QMutexLocker locker(&mutex);
+ QNetworkAccessManager *nam;
+ if (networkAccessManagerFactory) {
+ nam = networkAccessManagerFactory->create(parent);
+ } else {
+ nam = new QNetworkAccessManager(parent);
+ }
+
+ return nam;
+}
+
+QNetworkAccessManager *QQmlEnginePrivate::getNetworkAccessManager() const
+{
+ Q_Q(const QQmlEngine);
+ if (!networkAccessManager)
+ networkAccessManager = createNetworkAccessManager(const_cast<QQmlEngine*>(q));
+ return networkAccessManager;
+}
+
+/*!
+ Returns a common QNetworkAccessManager which can be used by any QML
+ element instantiated by this engine.
+
+ If a QQmlNetworkAccessManagerFactory has been set and a
+ QNetworkAccessManager has not yet been created, the
+ QQmlNetworkAccessManagerFactory will be used to create the
+ QNetworkAccessManager; otherwise the returned QNetworkAccessManager
+ will have no proxy or cache set.
+
+ \sa setNetworkAccessManagerFactory()
+*/
+QNetworkAccessManager *QQmlEngine::networkAccessManager() const
+{
+ Q_D(const QQmlEngine);
+ return d->getNetworkAccessManager();
+}
+
+/*!
+
+ Sets the \a provider to use for images requested via the \e
+ image: url scheme, with host \a providerId. The QQmlEngine
+ takes ownership of \a provider.
+
+ Image providers enable support for pixmap and threaded image
+ requests. See the QQmlImageProvider documentation for details on
+ implementing and using image providers.
+
+ All required image providers should be added to the engine before any
+ QML sources files are loaded.
+
+ \sa removeImageProvider()
+*/
+void QQmlEngine::addImageProvider(const QString &providerId, QQmlImageProvider *provider)
+{
+ Q_D(QQmlEngine);
+ QMutexLocker locker(&d->mutex);
+ d->imageProviders.insert(providerId.toLower(), QSharedPointer<QQmlImageProvider>(provider));
+}
+
+/*!
+ Returns the QQmlImageProvider set for \a providerId.
+
+ Returns the provider if it was found; otherwise returns 0.
+*/
+QQmlImageProvider *QQmlEngine::imageProvider(const QString &providerId) const
+{
+ Q_D(const QQmlEngine);
+ QMutexLocker locker(&d->mutex);
+ return d->imageProviders.value(providerId).data();
+}
+
+/*!
+ Removes the QQmlImageProvider for \a providerId.
+
+ \sa addImageProvider()
+*/
+void QQmlEngine::removeImageProvider(const QString &providerId)
+{
+ Q_D(QQmlEngine);
+ QMutexLocker locker(&d->mutex);
+ d->imageProviders.take(providerId);
+}
+
+QQmlImageProvider::ImageType QQmlEnginePrivate::getImageProviderType(const QUrl &url)
+{
+ QMutexLocker locker(&mutex);
+ QSharedPointer<QQmlImageProvider> provider = imageProviders.value(url.host());
+ locker.unlock();
+ if (provider)
+ return provider->imageType();
+ return QQmlImageProvider::Invalid;
+}
+
+QQuickTextureFactory *QQmlEnginePrivate::getTextureFromProvider(const QUrl &url, QSize *size, const QSize& req_size)
+{
+ QMutexLocker locker(&mutex);
+ QSharedPointer<QQmlImageProvider> provider = imageProviders.value(url.host());
+ locker.unlock();
+ if (provider) {
+ QString imageId = url.toString(QUrl::RemoveScheme | QUrl::RemoveAuthority).mid(1);
+ return provider->requestTexture(imageId, size, req_size);
+ }
+ return 0;
+}
+
+QImage QQmlEnginePrivate::getImageFromProvider(const QUrl &url, QSize *size, const QSize& req_size)
+{
+ QMutexLocker locker(&mutex);
+ QImage image;
+ QSharedPointer<QQmlImageProvider> provider = imageProviders.value(url.host());
+ locker.unlock();
+ if (provider) {
+ QString imageId = url.toString(QUrl::RemoveScheme | QUrl::RemoveAuthority).mid(1);
+ image = provider->requestImage(imageId, size, req_size);
+ }
+ return image;
+}
+
+QPixmap QQmlEnginePrivate::getPixmapFromProvider(const QUrl &url, QSize *size, const QSize& req_size)
+{
+ QMutexLocker locker(&mutex);
+ QPixmap pixmap;
+ QSharedPointer<QQmlImageProvider> provider = imageProviders.value(url.host());
+ locker.unlock();
+ if (provider) {
+ QString imageId = url.toString(QUrl::RemoveScheme | QUrl::RemoveAuthority).mid(1);
+ pixmap = provider->requestPixmap(imageId, size, req_size);
+ }
+ return pixmap;
+}
+
+/*!
+ Return the base URL for this engine. The base URL is only used to
+ resolve components when a relative URL is passed to the
+ QQmlComponent constructor.
+
+ If a base URL has not been explicitly set, this method returns the
+ application's current working directory.
+
+ \sa setBaseUrl()
+*/
+QUrl QQmlEngine::baseUrl() const
+{
+ Q_D(const QQmlEngine);
+ if (d->baseUrl.isEmpty()) {
+ return QUrl::fromLocalFile(QDir::currentPath() + QDir::separator());
+ } else {
+ return d->baseUrl;
+ }
+}
+
+/*!
+ Set the base URL for this engine to \a url.
+
+ \sa baseUrl()
+*/
+void QQmlEngine::setBaseUrl(const QUrl &url)
+{
+ Q_D(QQmlEngine);
+ d->baseUrl = url;
+}
+
+/*!
+ Returns true if warning messages will be output to stderr in addition
+ to being emitted by the warnings() signal, otherwise false.
+
+ The default value is true.
+*/
+bool QQmlEngine::outputWarningsToStandardError() const
+{
+ Q_D(const QQmlEngine);
+ return d->outputWarningsToStdErr;
+}
+
+/*!
+ Set whether warning messages will be output to stderr to \a enabled.
+
+ If \a enabled is true, any warning messages generated by QML will be
+ output to stderr and emitted by the warnings() signal. If \a enabled
+ is false, on the warnings() signal will be emitted. This allows
+ applications to handle warning output themselves.
+
+ The default value is true.
+*/
+void QQmlEngine::setOutputWarningsToStandardError(bool enabled)
+{
+ Q_D(QQmlEngine);
+ d->outputWarningsToStdErr = enabled;
+}
+
+/*!
+ Attempt to free unused memory.
+*/
+void QQmlEngine::collectGarbage()
+{
+ QV8Engine::gc();
+}
+
+/*!
+ Returns the QQmlContext for the \a object, or 0 if no
+ context has been set.
+
+ When the QQmlEngine instantiates a QObject, the context is
+ set automatically.
+ */
+QQmlContext *QQmlEngine::contextForObject(const QObject *object)
+{
+ if(!object)
+ return 0;
+
+ QObjectPrivate *priv = QObjectPrivate::get(const_cast<QObject *>(object));
+
+ QQmlData *data =
+ static_cast<QQmlData *>(priv->declarativeData);
+
+ if (!data)
+ return 0;
+ else if (data->outerContext)
+ return data->outerContext->asQQmlContext();
+ else
+ return 0;
+}
+
+/*!
+ Sets the QQmlContext for the \a object to \a context.
+ If the \a object already has a context, a warning is
+ output, but the context is not changed.
+
+ When the QQmlEngine instantiates a QObject, the context is
+ set automatically.
+ */
+void QQmlEngine::setContextForObject(QObject *object, QQmlContext *context)
+{
+ if (!object || !context)
+ return;
+
+ QQmlData *data = QQmlData::get(object, true);
+ if (data->context) {
+ qWarning("QQmlEngine::setContextForObject(): Object already has a QQmlContext");
+ return;
+ }
+
+ QQmlContextData *contextData = QQmlContextData::get(context);
+ contextData->addObject(object);
+}
+
+/*!
+ \enum QQmlEngine::ObjectOwnership
+
+ Ownership controls whether or not QML automatically destroys the
+ QObject when the object is garbage collected by the JavaScript
+ engine. The two ownership options are:
+
+ \value CppOwnership The object is owned by C++ code, and will
+ never be deleted by QML. The JavaScript destroy() method cannot be
+ used on objects with CppOwnership. This option is similar to
+ QScriptEngine::QtOwnership.
+
+ \value JavaScriptOwnership The object is owned by JavaScript.
+ When the object is returned to QML as the return value of a method
+ call or property access, QML will delete the object if there are no
+ remaining JavaScript references to it and it has no
+ QObject::parent(). This option is similar to
+ QScriptEngine::ScriptOwnership.
+
+ Generally an application doesn't need to set an object's ownership
+ explicitly. QML uses a heuristic to set the default object
+ ownership. By default, an object that is created by QML has
+ JavaScriptOwnership. The exception to this are the root objects
+ created by calling QQmlComponent::create() or
+ QQmlComponent::beginCreate() which have CppOwnership by
+ default. The ownership of these root-level objects is considered to
+ have been transferred to the C++ caller.
+
+ Objects not-created by QML have CppOwnership by default. The
+ exception to this is objects returned from a C++ method call. The
+ ownership of these objects is passed to JavaScript.
+
+ Calling setObjectOwnership() overrides the default ownership
+ heuristic used by QML.
+*/
+
+/*!
+ Sets the \a ownership of \a object.
+*/
+void QQmlEngine::setObjectOwnership(QObject *object, ObjectOwnership ownership)
+{
+ if (!object)
+ return;
+
+ QQmlData *ddata = QQmlData::get(object, true);
+ if (!ddata)
+ return;
+
+ ddata->indestructible = (ownership == CppOwnership)?true:false;
+ ddata->explicitIndestructibleSet = true;
+}
+
+/*!
+ Returns the ownership of \a object.
+*/
+QQmlEngine::ObjectOwnership QQmlEngine::objectOwnership(QObject *object)
+{
+ if (!object)
+ return CppOwnership;
+
+ QQmlData *ddata = QQmlData::get(object, false);
+ if (!ddata)
+ return CppOwnership;
+ else
+ return ddata->indestructible?CppOwnership:JavaScriptOwnership;
+}
+
+bool QQmlEngine::event(QEvent *e)
+{
+ Q_D(QQmlEngine);
+ if (e->type() == QEvent::User)
+ d->doDeleteInEngineThread();
+
+ return QJSEngine::event(e);
+}
+
+void QQmlEnginePrivate::doDeleteInEngineThread()
+{
+ QFieldList<Deletable, &Deletable::next> list;
+ mutex.lock();
+ list.copyAndClear(toDeleteInEngineThread);
+ mutex.unlock();
+
+ while (Deletable *d = list.takeFirst())
+ delete d;
+}
+
+Q_AUTOTEST_EXPORT void qmlExecuteDeferred(QObject *object)
+{
+ QQmlData *data = QQmlData::get(object);
+
+ if (data && data->deferredComponent) {
+ if (QQmlDebugService::isDebuggingEnabled()) {
+ QQmlProfilerService::startRange(QQmlProfilerService::Creating);
+ QQmlType *type = QQmlMetaType::qmlType(object->metaObject());
+ QString typeName = type ? type->qmlTypeName() : QString::fromUtf8(object->metaObject()->className());
+ QQmlProfilerService::rangeData(QQmlProfilerService::Creating, typeName);
+ if (data->outerContext)
+ QQmlProfilerService::rangeLocation(QQmlProfilerService::Creating, data->outerContext->url, data->lineNumber, data->columnNumber);
+ }
+ QQmlEnginePrivate *ep = QQmlEnginePrivate::get(data->context->engine);
+
+ QQmlComponentPrivate::ConstructionState state;
+ QQmlComponentPrivate::beginDeferred(ep, object, &state);
+
+ data->deferredComponent->release();
+ data->deferredComponent = 0;
+
+ QQmlComponentPrivate::complete(ep, &state);
+ QQmlProfilerService::endRange(QQmlProfilerService::Creating);
+ }
+}
+
+QQmlContext *qmlContext(const QObject *obj)
+{
+ return QQmlEngine::contextForObject(obj);
+}
+
+QQmlEngine *qmlEngine(const QObject *obj)
+{
+ QQmlData *data = QQmlData::get(obj, false);
+ if (!data || !data->context)
+ return 0;
+ return data->context->engine;
+}
+
+QObject *qmlAttachedPropertiesObjectById(int id, const QObject *object, bool create)
+{
+ QQmlData *data = QQmlData::get(object);
+ if (!data)
+ return 0; // Attached properties are only on objects created by QML
+
+ QObject *rv = data->hasExtendedData()?data->attachedProperties()->value(id):0;
+ if (rv || !create)
+ return rv;
+
+ QQmlAttachedPropertiesFunc pf = QQmlMetaType::attachedPropertiesFuncById(id);
+ if (!pf)
+ return 0;
+
+ rv = pf(const_cast<QObject *>(object));
+
+ if (rv)
+ data->attachedProperties()->insert(id, rv);
+
+ return rv;
+}
+
+QObject *qmlAttachedPropertiesObject(int *idCache, const QObject *object,
+ const QMetaObject *attachedMetaObject, bool create)
+{
+ if (*idCache == -1)
+ *idCache = QQmlMetaType::attachedPropertiesFuncId(attachedMetaObject);
+
+ if (*idCache == -1 || !object)
+ return 0;
+
+ return qmlAttachedPropertiesObjectById(*idCache, object, create);
+}
+
+QQmlDebuggingEnabler::QQmlDebuggingEnabler()
+{
+#ifndef QQML_NO_DEBUG_PROTOCOL
+ if (!QQmlEnginePrivate::qml_debugging_enabled) {
+ qWarning("Qml debugging is enabled. Only use this in a safe environment!");
+ }
+ QQmlEnginePrivate::qml_debugging_enabled = true;
+#endif
+}
+
+
+class QQmlDataExtended {
+public:
+ QQmlDataExtended();
+ ~QQmlDataExtended();
+
+ QHash<int, QObject *> attachedProperties;
+ QQmlNotifier objectNameNotifier;
+};
+
+QQmlDataExtended::QQmlDataExtended()
+{
+}
+
+QQmlDataExtended::~QQmlDataExtended()
+{
+}
+
+void QQmlData::NotifyList::layout(QQmlNotifierEndpoint *endpoint)
+{
+ if (endpoint->next)
+ layout(endpoint->next);
+
+ int index = endpoint->sourceSignal;
+ index = qMin(index, 0xFFFF - 1);
+
+ endpoint->next = notifies[index];
+ if (endpoint->next) endpoint->next->prev = &endpoint->next;
+ endpoint->prev = &notifies[index];
+ notifies[index] = endpoint;
+}
+
+void QQmlData::NotifyList::layout()
+{
+ Q_ASSERT(maximumTodoIndex >= notifiesSize);
+
+ if (todo) {
+ QQmlNotifierEndpoint **old = notifies;
+ const int reallocSize = (maximumTodoIndex + 1) * sizeof(QQmlNotifierEndpoint*);
+ notifies = (QQmlNotifierEndpoint**)realloc(notifies, reallocSize);
+ const int memsetSize = (maximumTodoIndex - notifiesSize + 1) *
+ sizeof(QQmlNotifierEndpoint*);
+ memset(notifies + notifiesSize, 0, memsetSize);
+
+ if (notifies != old) {
+ for (int ii = 0; ii < notifiesSize; ++ii)
+ if (notifies[ii])
+ notifies[ii]->prev = &notifies[ii];
+ }
+
+ notifiesSize = maximumTodoIndex + 1;
+
+ layout(todo);
+ }
+
+ maximumTodoIndex = 0;
+ todo = 0;
+}
+
+void QQmlData::addNotify(int index, QQmlNotifierEndpoint *endpoint)
+{
+ if (!notifyList) {
+ notifyList = (NotifyList *)malloc(sizeof(NotifyList));
+ notifyList->connectionMask = 0;
+ notifyList->maximumTodoIndex = 0;
+ notifyList->notifiesSize = 0;
+ notifyList->todo = 0;
+ notifyList->notifies = 0;
+ }
+
+ Q_ASSERT(!endpoint->isConnected());
+
+ index = qMin(index, 0xFFFF - 1);
+ notifyList->connectionMask |= (1ULL << quint64(index % 64));
+
+ if (index < notifyList->notifiesSize) {
+
+ endpoint->next = notifyList->notifies[index];
+ if (endpoint->next) endpoint->next->prev = &endpoint->next;
+ endpoint->prev = &notifyList->notifies[index];
+ notifyList->notifies[index] = endpoint;
+
+ } else {
+ notifyList->maximumTodoIndex = qMax(int(notifyList->maximumTodoIndex), index);
+
+ endpoint->next = notifyList->todo;
+ if (endpoint->next) endpoint->next->prev = &endpoint->next;
+ endpoint->prev = &notifyList->todo;
+ notifyList->todo = endpoint;
+ }
+}
+
+QQmlNotifier *QQmlData::objectNameNotifier() const
+{
+ if (!extendedData) extendedData = new QQmlDataExtended;
+ return &extendedData->objectNameNotifier;
+}
+
+QHash<int, QObject *> *QQmlData::attachedProperties() const
+{
+ if (!extendedData) extendedData = new QQmlDataExtended;
+ return &extendedData->attachedProperties;
+}
+
+void QQmlData::destroyed(QObject *object)
+{
+ if (deferredComponent)
+ deferredComponent->release();
+
+ if (nextContextObject)
+ nextContextObject->prevContextObject = prevContextObject;
+ if (prevContextObject)
+ *prevContextObject = nextContextObject;
+
+ QQmlAbstractBinding *binding = bindings;
+ while (binding) {
+ QQmlAbstractBinding *next = binding->m_nextBinding;
+ binding->m_prevBinding = 0;
+ binding->m_nextBinding = 0;
+ binding->destroy();
+ binding = next;
+ }
+
+ if (bindingBits)
+ free(bindingBits);
+
+ if (propertyCache)
+ propertyCache->release();
+
+ if (ownContext && context)
+ context->destroy();
+
+ while (guards) {
+ QQmlGuard<QObject> *guard = static_cast<QQmlGuard<QObject> *>(guards);
+ *guard = (QObject *)0;
+ guard->objectDestroyed(object);
+ }
+
+ if (notifyList) {
+ while (notifyList->todo)
+ notifyList->todo->disconnect();
+ for (int ii = 0; ii < notifyList->notifiesSize; ++ii) {
+ while (QQmlNotifierEndpoint *ep = notifyList->notifies[ii])
+ ep->disconnect();
+ }
+ free(notifyList->notifies);
+ free(notifyList);
+ }
+
+ if (extendedData)
+ delete extendedData;
+
+ v8object.Clear(); // The WeakReference handler will clean the actual handle
+
+ if (ownMemory)
+ delete this;
+}
+
+void QQmlData::parentChanged(QObject *object, QObject *parent)
+{
+ Q_UNUSED(object);
+ Q_UNUSED(parent);
+}
+
+void QQmlData::objectNameChanged(QObject *)
+{
+ if (extendedData) objectNameNotifier()->notify();
+}
+
+bool QQmlData::hasBindingBit(int bit) const
+{
+ if (bindingBitsSize > bit)
+ return bindingBits[bit / 32] & (1 << (bit % 32));
+ else
+ return false;
+}
+
+void QQmlData::clearBindingBit(int bit)
+{
+ if (bindingBitsSize > bit)
+ bindingBits[bit / 32] &= ~(1 << (bit % 32));
+}
+
+void QQmlData::setBindingBit(QObject *obj, int bit)
+{
+ if (bindingBitsSize <= bit) {
+ int props = obj->metaObject()->propertyCount();
+ Q_ASSERT(bit < props);
+
+ int arraySize = (props + 31) / 32;
+ int oldArraySize = bindingBitsSize / 32;
+
+ bindingBits = (quint32 *)realloc(bindingBits,
+ arraySize * sizeof(quint32));
+
+ memset(bindingBits + oldArraySize,
+ 0x00,
+ sizeof(quint32) * (arraySize - oldArraySize));
+
+ bindingBitsSize = arraySize * 32;
+ }
+
+ bindingBits[bit / 32] |= (1 << (bit % 32));
+}
+
+QString QQmlEnginePrivate::urlToLocalFileOrQrc(const QUrl& url)
+{
+ if (url.scheme().compare(QLatin1String("qrc"), Qt::CaseInsensitive) == 0) {
+ if (url.authority().isEmpty())
+ return QLatin1Char(':') + url.path();
+ return QString();
+ }
+ return url.toLocalFile();
+}
+
+
+static QString toLocalFile(const QString &url)
+{
+ if (!url.startsWith(QLatin1String("file://"), Qt::CaseInsensitive))
+ return QString();
+
+ QString file = url.mid(7);
+
+ //XXX TODO: handle windows hostnames: "//servername/path/to/file.txt"
+
+ // magic for drives on windows
+ if (file.length() > 2 && file.at(0) == QLatin1Char('/') && file.at(2) == QLatin1Char(':'))
+ file.remove(0, 1);
+
+ return file;
+}
+
+QString QQmlEnginePrivate::urlToLocalFileOrQrc(const QString& url)
+{
+ if (url.startsWith(QLatin1String("qrc:"), Qt::CaseInsensitive)) {
+ if (url.length() > 4)
+ return QLatin1Char(':') + url.mid(4);
+ return QString();
+ }
+
+ return toLocalFile(url);
+}
+
+void QQmlEnginePrivate::sendQuit()
+{
+ Q_Q(QQmlEngine);
+ emit q->quit();
+ if (q->receivers(SIGNAL(quit())) == 0) {
+ qWarning("Signal QQmlEngine::quit() emitted, but no receivers connected to handle it.");
+ }
+}
+
+static void dumpwarning(const QQmlError &error)
+{
+ qWarning().nospace() << qPrintable(error.toString());
+}
+
+static void dumpwarning(const QList<QQmlError> &errors)
+{
+ for (int ii = 0; ii < errors.count(); ++ii)
+ dumpwarning(errors.at(ii));
+}
+
+void QQmlEnginePrivate::warning(const QQmlError &error)
+{
+ Q_Q(QQmlEngine);
+ q->warnings(QList<QQmlError>() << error);
+ if (outputWarningsToStdErr)
+ dumpwarning(error);
+}
+
+void QQmlEnginePrivate::warning(const QList<QQmlError> &errors)
+{
+ Q_Q(QQmlEngine);
+ q->warnings(errors);
+ if (outputWarningsToStdErr)
+ dumpwarning(errors);
+}
+
+void QQmlEnginePrivate::warning(QQmlEngine *engine, const QQmlError &error)
+{
+ if (engine)
+ QQmlEnginePrivate::get(engine)->warning(error);
+ else
+ dumpwarning(error);
+}
+
+void QQmlEnginePrivate::warning(QQmlEngine *engine, const QList<QQmlError> &error)
+{
+ if (engine)
+ QQmlEnginePrivate::get(engine)->warning(error);
+ else
+ dumpwarning(error);
+}
+
+void QQmlEnginePrivate::warning(QQmlEnginePrivate *engine, const QQmlError &error)
+{
+ if (engine)
+ engine->warning(error);
+ else
+ dumpwarning(error);
+}
+
+void QQmlEnginePrivate::warning(QQmlEnginePrivate *engine, const QList<QQmlError> &error)
+{
+ if (engine)
+ engine->warning(error);
+ else
+ dumpwarning(error);
+}
+
+/*
+ This function should be called prior to evaluation of any js expression,
+ so that scarce resources are not freed prematurely (eg, if there is a
+ nested javascript expression).
+ */
+void QQmlEnginePrivate::referenceScarceResources()
+{
+ scarceResourcesRefCount += 1;
+}
+
+/*
+ This function should be called after evaluation of the js expression is
+ complete, and so the scarce resources may be freed safely.
+ */
+void QQmlEnginePrivate::dereferenceScarceResources()
+{
+ Q_ASSERT(scarceResourcesRefCount > 0);
+ scarceResourcesRefCount -= 1;
+
+ // if the refcount is zero, then evaluation of the "top level"
+ // expression must have completed. We can safely release the
+ // scarce resources.
+ if (scarceResourcesRefCount == 0) {
+ // iterate through the list and release them all.
+ // note that the actual SRD is owned by the JS engine,
+ // so we cannot delete the SRD; but we can free the
+ // memory used by the variant in the SRD.
+ while (ScarceResourceData *sr = scarceResources.first()) {
+ sr->data = QVariant();
+ scarceResources.remove(sr);
+ }
+ }
+}
+
+/*!
+ Adds \a path as a directory where the engine searches for
+ installed modules in a URL-based directory structure.
+ The \a path may be a local filesystem directory or a URL.
+
+ The newly added \a path will be first in the importPathList().
+
+ \sa setImportPathList(), {QML Modules}
+*/
+void QQmlEngine::addImportPath(const QString& path)
+{
+ Q_D(QQmlEngine);
+ d->importDatabase.addImportPath(path);
+}
+
+/*!
+ Returns the list of directories where the engine searches for
+ installed modules in a URL-based directory structure.
+
+ For example, if \c /opt/MyApp/lib/imports is in the path, then QML that
+ imports \c com.mycompany.Feature will cause the QQmlEngine to look
+ in \c /opt/MyApp/lib/imports/com/mycompany/Feature/ for the components
+ provided by that module. A \c qmldir file is required for defining the
+ type version mapping and possibly declarative extensions plugins.
+
+ By default, the list contains the directory of the application executable,
+ paths specified in the \c QML_IMPORT_PATH environment variable,
+ and the builtin \c ImportsPath from QLibraryInfo.
+
+ \sa addImportPath() setImportPathList()
+*/
+QStringList QQmlEngine::importPathList() const
+{
+ Q_D(const QQmlEngine);
+ return d->importDatabase.importPathList();
+}
+
+/*!
+ Sets \a paths as the list of directories where the engine searches for
+ installed modules in a URL-based directory structure.
+
+ By default, the list contains the directory of the application executable,
+ paths specified in the \c QML_IMPORT_PATH environment variable,
+ and the builtin \c ImportsPath from QLibraryInfo.
+
+ \sa importPathList() addImportPath()
+ */
+void QQmlEngine::setImportPathList(const QStringList &paths)
+{
+ Q_D(QQmlEngine);
+ d->importDatabase.setImportPathList(paths);
+}
+
+
+/*!
+ Adds \a path as a directory where the engine searches for
+ native plugins for imported modules (referenced in the \c qmldir file).
+
+ By default, the list contains only \c ., i.e. the engine searches
+ in the directory of the \c qmldir file itself.
+
+ The newly added \a path will be first in the pluginPathList().
+
+ \sa setPluginPathList()
+*/
+void QQmlEngine::addPluginPath(const QString& path)
+{
+ Q_D(QQmlEngine);
+ d->importDatabase.addPluginPath(path);
+}
+
+
+/*!
+ Returns the list of directories where the engine searches for
+ native plugins for imported modules (referenced in the \c qmldir file).
+
+ By default, the list contains only \c ., i.e. the engine searches
+ in the directory of the \c qmldir file itself.
+
+ \sa addPluginPath() setPluginPathList()
+*/
+QStringList QQmlEngine::pluginPathList() const
+{
+ Q_D(const QQmlEngine);
+ return d->importDatabase.pluginPathList();
+}
+
+/*!
+ Sets the list of directories where the engine searches for
+ native plugins for imported modules (referenced in the \c qmldir file)
+ to \a paths.
+
+ By default, the list contains only \c ., i.e. the engine searches
+ in the directory of the \c qmldir file itself.
+
+ \sa pluginPathList() addPluginPath()
+ */
+void QQmlEngine::setPluginPathList(const QStringList &paths)
+{
+ Q_D(QQmlEngine);
+ d->importDatabase.setPluginPathList(paths);
+}
+
+/*!
+ Imports the plugin named \a filePath with the \a uri provided.
+ Returns true if the plugin was successfully imported; otherwise returns false.
+
+ On failure and if non-null, the \a errors list will have any errors which occurred prepended to it.
+
+ The plugin has to be a Qt plugin which implements the QQmlExtensionPlugin interface.
+*/
+bool QQmlEngine::importPlugin(const QString &filePath, const QString &uri, QList<QQmlError> *errors)
+{
+ Q_D(QQmlEngine);
+ return d->importDatabase.importPlugin(filePath, uri, errors);
+}
+
+/*!
+ Imports the plugin named \a filePath with the \a uri provided.
+ Returns true if the plugin was successfully imported; otherwise returns false.
+
+ On failure and if non-null, *\a errorString will be set to a message describing the failure.
+
+ The plugin has to be a Qt plugin which implements the QQmlExtensionPlugin interface.
+*/
+bool QQmlEngine::importPlugin(const QString &filePath, const QString &uri, QString *errorString)
+{
+ Q_D(QQmlEngine);
+ QList<QQmlError> errors;
+ bool retn = d->importDatabase.importPlugin(filePath, uri, &errors);
+ if (!errors.isEmpty()) {
+ QString builtError;
+ for (int i = 0; i < errors.size(); ++i) {
+ builtError = QString(QLatin1String("%1\n %2"))
+ .arg(builtError)
+ .arg(errors.at(i).toString());
+ }
+ *errorString = builtError;
+ }
+ return retn;
+}
+
+/*!
+ \property QQmlEngine::offlineStoragePath
+ \brief the directory for storing offline user data
+
+ Returns the directory where SQL and other offline
+ storage is placed.
+
+ QQuickWebView and the SQL databases created with openDatabase()
+ are stored here.
+
+ The default is QML/OfflineStorage in the platform-standard
+ user application data directory.
+
+ Note that the path may not currently exist on the filesystem, so
+ callers wanting to \e create new files at this location should create
+ it first - see QDir::mkpath().
+*/
+void QQmlEngine::setOfflineStoragePath(const QString& dir)
+{
+ Q_D(QQmlEngine);
+ d->offlineStoragePath = dir;
+}
+
+QString QQmlEngine::offlineStoragePath() const
+{
+ Q_D(const QQmlEngine);
+ return d->offlineStoragePath;
+}
+
+static void voidptr_destructor(void *v)
+{
+ void **ptr = (void **)v;
+ delete ptr;
+}
+
+static void *voidptr_constructor(const void *v)
+{
+ if (!v) {
+ return new void*;
+ } else {
+ return new void*(*(void **)v);
+ }
+}
+
+QQmlPropertyCache *QQmlEnginePrivate::createCache(const QMetaObject *mo)
+{
+ Q_Q(QQmlEngine);
+
+ if (!mo->superClass()) {
+ QQmlPropertyCache *rv = new QQmlPropertyCache(q, mo);
+ propertyCache.insert(mo, rv);
+ return rv;
+ } else {
+ QQmlPropertyCache *super = cache(mo->superClass());
+ QQmlPropertyCache *rv = super->copyAndAppend(q, mo);
+ propertyCache.insert(mo, rv);
+ return rv;
+ }
+}
+
+QQmlPropertyCache *QQmlEnginePrivate::createCache(QQmlType *type, int minorVersion,
+ QQmlError &error)
+{
+ QList<QQmlType *> types;
+
+ int maxMinorVersion = 0;
+
+ const QMetaObject *metaObject = type->metaObject();
+
+ while (metaObject) {
+ QQmlType *t = QQmlMetaType::qmlType(metaObject, type->module(),
+ type->majorVersion(), minorVersion);
+ if (t) {
+ maxMinorVersion = qMax(maxMinorVersion, t->minorVersion());
+ types << t;
+ } else {
+ types << 0;
+ }
+
+ metaObject = metaObject->superClass();
+ }
+
+ if (QQmlPropertyCache *c = typePropertyCache.value(qMakePair(type, maxMinorVersion))) {
+ c->addref();
+ typePropertyCache.insert(qMakePair(type, minorVersion), c);
+ return c;
+ }
+
+ QQmlPropertyCache *raw = cache(type->metaObject());
+
+ bool hasCopied = false;
+
+ for (int ii = 0; ii < types.count(); ++ii) {
+ QQmlType *currentType = types.at(ii);
+ if (!currentType)
+ continue;
+
+ int rev = currentType->metaObjectRevision();
+ int moIndex = types.count() - 1 - ii;
+
+ if (raw->allowedRevisionCache[moIndex] != rev) {
+ if (!hasCopied) {
+ raw = raw->copy();
+ hasCopied = true;
+ }
+ raw->allowedRevisionCache[moIndex] = rev;
+ }
+ }
+
+ // Test revision compatibility - the basic rule is:
+ // * Anything that is excluded, cannot overload something that is not excluded *
+
+ // Signals override:
+ // * other signals and methods of the same name.
+ // * properties named on<Signal Name>
+ // * automatic <property name>Changed notify signals
+
+ // Methods override:
+ // * other methods of the same name
+
+ // Properties override:
+ // * other elements of the same name
+
+ bool overloadError = false;
+ QString overloadName;
+
+#if 0
+ for (QQmlPropertyCache::StringCache::ConstIterator iter = raw->stringCache.begin();
+ !overloadError && iter != raw->stringCache.end();
+ ++iter) {
+
+ QQmlPropertyData *d = *iter;
+ if (raw->isAllowedInRevision(d))
+ continue; // Not excluded - no problems
+
+ // check that a regular "name" overload isn't happening
+ QQmlPropertyData *current = d;
+ while (!overloadError && current) {
+ current = d->overrideData(current);
+ if (current && raw->isAllowedInRevision(current))
+ overloadError = true;
+ }
+ }
+#endif
+
+ if (overloadError) {
+ if (hasCopied) raw->release();
+
+ error.setDescription(QLatin1String("Type ") + type->qmlTypeName() + QLatin1String(" ") + QString::number(type->majorVersion()) + QLatin1String(".") + QString::number(minorVersion) + QLatin1String(" contains an illegal property \"") + overloadName + QLatin1String("\". This is an error in the type's implementation."));
+ return 0;
+ }
+
+ if (!hasCopied) raw->addref();
+ typePropertyCache.insert(qMakePair(type, minorVersion), raw);
+
+ if (minorVersion != maxMinorVersion) {
+ raw->addref();
+ typePropertyCache.insert(qMakePair(type, maxMinorVersion), raw);
+ }
+
+ return raw;
+}
+
+QQmlMetaType::ModuleApiInstance *
+QQmlEnginePrivate::moduleApiInstance(const QQmlMetaType::ModuleApi &module)
+{
+ Locker locker(this);
+
+ QQmlMetaType::ModuleApiInstance *a = moduleApiInstances.value(module);
+ if (!a) {
+ a = new QQmlMetaType::ModuleApiInstance;
+ a->scriptCallback = module.script;
+ a->qobjectCallback = module.qobject;
+ moduleApiInstances.insert(module, a);
+ }
+
+ return a;
+}
+
+bool QQmlEnginePrivate::isQObject(int t)
+{
+ Locker locker(this);
+ return m_compositeTypes.contains(t) || QQmlMetaType::isQObject(t);
+}
+
+QObject *QQmlEnginePrivate::toQObject(const QVariant &v, bool *ok) const
+{
+ Locker locker(this);
+ int t = v.userType();
+ if (t == QMetaType::QObjectStar || m_compositeTypes.contains(t)) {
+ if (ok) *ok = true;
+ return *(QObject **)(v.constData());
+ } else {
+ return QQmlMetaType::toQObject(v, ok);
+ }
+}
+
+QQmlMetaType::TypeCategory QQmlEnginePrivate::typeCategory(int t) const
+{
+ Locker locker(this);
+ if (m_compositeTypes.contains(t))
+ return QQmlMetaType::Object;
+ else if (m_qmlLists.contains(t))
+ return QQmlMetaType::List;
+ else
+ return QQmlMetaType::typeCategory(t);
+}
+
+bool QQmlEnginePrivate::isList(int t) const
+{
+ Locker locker(this);
+ return m_qmlLists.contains(t) || QQmlMetaType::isList(t);
+}
+
+int QQmlEnginePrivate::listType(int t) const
+{
+ Locker locker(this);
+ QHash<int, int>::ConstIterator iter = m_qmlLists.find(t);
+ if (iter != m_qmlLists.end())
+ return *iter;
+ else
+ return QQmlMetaType::listType(t);
+}
+
+const QMetaObject *QQmlEnginePrivate::rawMetaObjectForType(int t) const
+{
+ Locker locker(this);
+ QHash<int, QQmlCompiledData*>::ConstIterator iter = m_compositeTypes.find(t);
+ if (iter != m_compositeTypes.end()) {
+ return (*iter)->root;
+ } else {
+ QQmlType *type = QQmlMetaType::qmlType(t);
+ return type?type->baseMetaObject():0;
+ }
+}
+
+const QMetaObject *QQmlEnginePrivate::metaObjectForType(int t) const
+{
+ Locker locker(this);
+ QHash<int, QQmlCompiledData*>::ConstIterator iter = m_compositeTypes.find(t);
+ if (iter != m_compositeTypes.end()) {
+ return (*iter)->root;
+ } else {
+ QQmlType *type = QQmlMetaType::qmlType(t);
+ return type?type->metaObject():0;
+ }
+}
+
+void QQmlEnginePrivate::registerCompositeType(QQmlCompiledData *data)
+{
+ QByteArray name = data->root->className();
+
+ QByteArray ptr = name + '*';
+ QByteArray lst = "QQmlListProperty<" + name + '>';
+
+ int ptr_type = QMetaType::registerType(ptr.constData(), voidptr_destructor,
+ voidptr_constructor);
+ int lst_type = QMetaType::registerType(lst.constData(), voidptr_destructor,
+ voidptr_constructor);
+
+ data->addref();
+
+ Locker locker(this);
+ m_qmlLists.insert(lst_type, ptr_type);
+ m_compositeTypes.insert(ptr_type, data);
+}
+
+bool QQml_isFileCaseCorrect(const QString &fileName)
+{
+#if defined(Q_OS_MAC) || defined(Q_OS_WIN)
+ QFileInfo info(fileName);
+ const QString absolute = info.absoluteFilePath();
+
+#if defined(Q_OS_MAC)
+ const QString canonical = info.canonicalFilePath();
+#elif defined(Q_OS_WIN)
+ wchar_t buffer[1024];
+
+ DWORD rv = ::GetShortPathName((wchar_t*)absolute.utf16(), buffer, 1024);
+ if (rv == 0 || rv >= 1024) return true;
+ rv = ::GetLongPathName(buffer, buffer, 1024);
+ if (rv == 0 || rv >= 1024) return true;
+
+ const QString canonical = QString::fromWCharArray(buffer);
+#endif
+
+ const int absoluteLength = absolute.length();
+ const int canonicalLength = canonical.length();
+
+ const int length = qMin(absoluteLength, canonicalLength);
+ for (int ii = 0; ii < length; ++ii) {
+ const QChar &a = absolute.at(absoluteLength - 1 - ii);
+ const QChar &c = canonical.at(canonicalLength - 1 - ii);
+
+ if (a.toLower() != c.toLower())
+ return true;
+ if (a != c)
+ return false;
+ }
+#else
+ Q_UNUSED(fileName)
+#endif
+ return true;
+}
+
+/*!
+ \fn QQmlEngine *qmlEngine(const QObject *object)
+ \relates QQmlEngine
+
+ Returns the QQmlEngine associated with \a object, if any. This is equivalent to
+ QQmlEngine::contextForObject(object)->engine(), but more efficient.
+*/
+
+/*!
+ \fn QQmlContext *qmlContext(const QObject *object)
+ \relates QQmlEngine
+
+ Returns the QQmlContext associated with \a object, if any. This is equivalent to
+ QQmlEngine::contextForObject(object).
+*/
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlengine.h b/src/qml/qml/qqmlengine.h
new file mode 100644
index 0000000000..04ac61c05b
--- /dev/null
+++ b/src/qml/qml/qqmlengine.h
@@ -0,0 +1,138 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLENGINE_H
+#define QQMLENGINE_H
+
+#include <QtCore/qurl.h>
+#include <QtCore/qobject.h>
+#include <QtCore/qmap.h>
+#include <QtQml/qjsengine.h>
+#include <QtQml/qqmlerror.h>
+#include <QtQml/qqmldebug.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+
+class QQmlComponent;
+class QQmlEnginePrivate;
+class QQmlImportsPrivate;
+class QQmlExpression;
+class QQmlContext;
+class QQmlType;
+class QUrl;
+class QScriptContext;
+class QQmlImageProvider;
+class QNetworkAccessManager;
+class QQmlNetworkAccessManagerFactory;
+class QQmlIncubationController;
+class Q_QML_EXPORT QQmlEngine : public QJSEngine
+{
+ Q_PROPERTY(QString offlineStoragePath READ offlineStoragePath WRITE setOfflineStoragePath)
+ Q_OBJECT
+public:
+ QQmlEngine(QObject *p = 0);
+ virtual ~QQmlEngine();
+
+ QQmlContext *rootContext() const;
+
+ void clearComponentCache();
+
+ QStringList importPathList() const;
+ void setImportPathList(const QStringList &paths);
+ void addImportPath(const QString& dir);
+
+ QStringList pluginPathList() const;
+ void setPluginPathList(const QStringList &paths);
+ void addPluginPath(const QString& dir);
+
+ bool importPlugin(const QString &filePath, const QString &uri, QString *errorString); // XXX: Qt 5: Remove this function
+ bool importPlugin(const QString &filePath, const QString &uri, QList<QQmlError> *errors);
+
+ void setNetworkAccessManagerFactory(QQmlNetworkAccessManagerFactory *);
+ QQmlNetworkAccessManagerFactory *networkAccessManagerFactory() const;
+
+ QNetworkAccessManager *networkAccessManager() const;
+
+ void addImageProvider(const QString &id, QQmlImageProvider *);
+ QQmlImageProvider *imageProvider(const QString &id) const;
+ void removeImageProvider(const QString &id);
+
+ void setIncubationController(QQmlIncubationController *);
+ QQmlIncubationController *incubationController() const;
+
+ void setOfflineStoragePath(const QString& dir);
+ QString offlineStoragePath() const;
+
+ QUrl baseUrl() const;
+ void setBaseUrl(const QUrl &);
+
+ bool outputWarningsToStandardError() const;
+ void setOutputWarningsToStandardError(bool);
+
+ void collectGarbage();
+
+ static QQmlContext *contextForObject(const QObject *);
+ static void setContextForObject(QObject *, QQmlContext *);
+
+ enum ObjectOwnership { CppOwnership, JavaScriptOwnership };
+ static void setObjectOwnership(QObject *, ObjectOwnership);
+ static ObjectOwnership objectOwnership(QObject *);
+
+protected:
+ virtual bool event(QEvent *);
+
+Q_SIGNALS:
+ void quit();
+ void warnings(const QList<QQmlError> &warnings);
+
+private:
+ Q_DISABLE_COPY(QQmlEngine)
+ Q_DECLARE_PRIVATE(QQmlEngine)
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QQMLENGINE_H
diff --git a/src/qml/qml/qqmlengine_p.h b/src/qml/qml/qqmlengine_p.h
new file mode 100644
index 0000000000..db834489ba
--- /dev/null
+++ b/src/qml/qml/qqmlengine_p.h
@@ -0,0 +1,522 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLENGINE_P_H
+#define QQMLENGINE_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 "qqmlengine.h"
+
+#include "qqmltypeloader_p.h"
+#include "qqmlimport_p.h"
+#include <private/qpodvector_p.h>
+#include "qqml.h"
+#include "qqmlvaluetype_p.h"
+#include "qqmlcontext.h"
+#include "qqmlcontext_p.h"
+#include "qqmlexpression.h"
+#include "qqmlimageprovider.h"
+#include "qqmlproperty_p.h"
+#include "qqmlpropertycache_p.h"
+#include "qqmlmetatype_p.h"
+#include "qqmldirparser_p.h"
+#include <private/qintrusivelist_p.h>
+#include <private/qrecyclepool_p.h>
+
+#include <QtCore/qlist.h>
+#include <QtCore/qpair.h>
+#include <QtCore/qstack.h>
+#include <QtCore/qmutex.h>
+#include <QtCore/qstring.h>
+#include <QtCore/qthread.h>
+
+#include <private/qobject_p.h>
+
+#include <private/qv8engine_p.h>
+#include <private/qjsengine_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQmlContext;
+class QQmlEngine;
+class QQmlContextPrivate;
+class QQmlExpression;
+class QQmlImportDatabase;
+class QNetworkReply;
+class QNetworkAccessManager;
+class QQmlNetworkAccessManagerFactory;
+class QQmlAbstractBinding;
+class QQmlTypeNameCache;
+class QQmlComponentAttached;
+class QQmlCleanup;
+class QQmlDelayedError;
+class QQuickWorkerScriptEngine;
+class QQmlVME;
+class QDir;
+class QQmlIncubator;
+
+// This needs to be declared here so that the pool for it can live in QQmlEnginePrivate.
+// The inline method definitions are in qqmlexpression_p.h
+class QQmlJavaScriptExpressionGuard : public QQmlNotifierEndpoint
+{
+public:
+ inline QQmlJavaScriptExpressionGuard(QQmlJavaScriptExpression *);
+
+ static inline void endpointCallback(QQmlNotifierEndpoint *);
+ static inline QQmlJavaScriptExpressionGuard *New(QQmlJavaScriptExpression *e,
+ QQmlEngine *engine);
+ inline void Delete();
+
+ QQmlJavaScriptExpression *expression;
+ QQmlJavaScriptExpressionGuard *next;
+};
+
+class Q_QML_EXPORT QQmlEnginePrivate : public QJSEnginePrivate
+{
+ Q_DECLARE_PUBLIC(QQmlEngine)
+public:
+ QQmlEnginePrivate(QQmlEngine *);
+ ~QQmlEnginePrivate();
+
+ void init();
+
+ class PropertyCapture {
+ public:
+ inline virtual ~PropertyCapture() {}
+ virtual void captureProperty(QQmlNotifier *) = 0;
+ virtual void captureProperty(QObject *, int, int) = 0;
+ };
+
+ PropertyCapture *propertyCapture;
+ inline void captureProperty(QQmlNotifier *);
+ inline void captureProperty(QObject *, int, int);
+
+ QRecyclePool<QQmlJavaScriptExpressionGuard> jsExpressionGuardPool;
+
+ QQmlContext *rootContext;
+ bool isDebugging;
+
+ bool outputWarningsToStdErr;
+
+ QQmlContextData *sharedContext;
+ QObject *sharedScope;
+
+ // Registered cleanup handlers
+ QQmlCleanup *cleanup;
+
+ // Bindings that have had errors during startup
+ QQmlDelayedError *erroredBindings;
+ int inProgressCreations;
+
+ QV8Engine *v8engine() const { return q_func()->handle(); }
+
+ QQuickWorkerScriptEngine *getWorkerScriptEngine();
+ QQuickWorkerScriptEngine *workerScriptEngine;
+
+ QUrl baseUrl;
+
+ typedef QPair<QQmlGuard<QObject>,int> FinalizeCallback;
+ void registerFinalizeCallback(QObject *obj, int index);
+
+ QQmlVME *activeVME;
+
+ QNetworkAccessManager *createNetworkAccessManager(QObject *parent) const;
+ QNetworkAccessManager *getNetworkAccessManager() const;
+ mutable QNetworkAccessManager *networkAccessManager;
+ mutable QQmlNetworkAccessManagerFactory *networkAccessManagerFactory;
+
+ QHash<QString,QSharedPointer<QQmlImageProvider> > imageProviders;
+ QQmlImageProvider::ImageType getImageProviderType(const QUrl &url);
+ QQuickTextureFactory *getTextureFromProvider(const QUrl &url, QSize *size, const QSize& req_size);
+ QImage getImageFromProvider(const QUrl &url, QSize *size, const QSize& req_size);
+ QPixmap getPixmapFromProvider(const QUrl &url, QSize *size, const QSize& req_size);
+
+ // Scarce resources are "exceptionally high cost" QVariant types where allowing the
+ // normal JavaScript GC to clean them up is likely to lead to out-of-memory or other
+ // out-of-resource situations. When such a resource is passed into JavaScript we
+ // add it to the scarceResources list and it is destroyed when we return from the
+ // JavaScript execution that created it. The user can prevent this behavior by
+ // calling preserve() on the object which removes it from this scarceResource list.
+ class ScarceResourceData {
+ public:
+ ScarceResourceData(const QVariant &data) : data(data) {}
+ QVariant data;
+ QIntrusiveListNode node;
+ };
+ QIntrusiveList<ScarceResourceData, &ScarceResourceData::node> scarceResources;
+ int scarceResourcesRefCount;
+ void referenceScarceResources();
+ void dereferenceScarceResources();
+
+ QQmlTypeLoader typeLoader;
+ QQmlImportDatabase importDatabase;
+
+ QString offlineStoragePath;
+
+ mutable quint32 uniqueId;
+ inline quint32 getUniqueId() const {
+ return uniqueId++;
+ }
+
+ QQmlValueTypeFactory valueTypes;
+
+ // Unfortunate workaround to avoid a circular dependency between
+ // qqmlengine_p.h and qqmlincubator_p.h
+ struct Incubator {
+ QIntrusiveListNode next;
+ // Unfortunate workaround for MSVC
+ QIntrusiveListNode nextWaitingFor;
+ };
+ QIntrusiveList<Incubator, &Incubator::next> incubatorList;
+ unsigned int incubatorCount;
+ QQmlIncubationController *incubationController;
+ void incubate(QQmlIncubator &, QQmlContextData *);
+
+ // These methods may be called from any thread
+ inline bool isEngineThread() const;
+ inline static bool isEngineThread(const QQmlEngine *);
+ template<typename T>
+ inline void deleteInEngineThread(T *);
+ template<typename T>
+ inline static void deleteInEngineThread(QQmlEngine *, T *);
+
+ // These methods may be called from the loader thread
+ QQmlMetaType::ModuleApiInstance *moduleApiInstance(const QQmlMetaType::ModuleApi &module);
+
+ // These methods may be called from the loader thread
+ inline QQmlPropertyCache *cache(QObject *obj);
+ inline QQmlPropertyCache *cache(const QMetaObject *);
+ inline QQmlPropertyCache *cache(QQmlType *, int, QQmlError &error);
+
+ // These methods may be called from the loader thread
+ bool isQObject(int);
+ QObject *toQObject(const QVariant &, bool *ok = 0) const;
+ QQmlMetaType::TypeCategory typeCategory(int) const;
+ bool isList(int) const;
+ int listType(int) const;
+ const QMetaObject *rawMetaObjectForType(int) const;
+ const QMetaObject *metaObjectForType(int) const;
+ void registerCompositeType(QQmlCompiledData *);
+
+ void sendQuit();
+ void warning(const QQmlError &);
+ void warning(const QList<QQmlError> &);
+ static void warning(QQmlEngine *, const QQmlError &);
+ static void warning(QQmlEngine *, const QList<QQmlError> &);
+ static void warning(QQmlEnginePrivate *, const QQmlError &);
+ static void warning(QQmlEnginePrivate *, const QList<QQmlError> &);
+
+ inline static QV8Engine *getV8Engine(QQmlEngine *e);
+ inline static QQmlEnginePrivate *get(QQmlEngine *e);
+ inline static const QQmlEnginePrivate *get(const QQmlEngine *e);
+ inline static QQmlEnginePrivate *get(QQmlContext *c);
+ inline static QQmlEnginePrivate *get(QQmlContextData *c);
+ inline static QQmlEngine *get(QQmlEnginePrivate *p);
+
+ static QString urlToLocalFileOrQrc(const QUrl& url);
+ static QString urlToLocalFileOrQrc(const QString& url);
+
+ static void registerBaseTypes(const char *uri, int versionMajor, int versionMinor);
+ static void defineModule();
+
+ static bool qml_debugging_enabled;
+
+ mutable QMutex mutex;
+
+private:
+ // Locker locks the QQmlEnginePrivate data structures for read and write, if necessary.
+ // Currently, locking is only necessary if the threaded loader is running concurrently. If it is
+ // either idle, or is running with the main thread blocked, no locking is necessary. This way
+ // we only pay for locking when we have to.
+ // Consequently, this class should only be used to protect simple accesses or modifications of the
+ // QQmlEnginePrivate structures or operations that can be guarenteed not to start activity
+ // on the loader thread.
+ // The Locker API is identical to QMutexLocker. Locker reuses the QQmlEnginePrivate::mutex
+ // QMutex instance and multiple Lockers are recursive in the same thread.
+ class Locker
+ {
+ public:
+ inline Locker(const QQmlEngine *);
+ inline Locker(const QQmlEnginePrivate *);
+ inline ~Locker();
+
+ inline void unlock();
+ inline void relock();
+
+ private:
+ const QQmlEnginePrivate *m_ep;
+ quint32 m_locked:1;
+ };
+
+ // Must be called locked
+ QQmlPropertyCache *createCache(const QMetaObject *);
+ QQmlPropertyCache *createCache(QQmlType *, int, QQmlError &error);
+
+ // These members must be protected by a QQmlEnginePrivate::Locker as they are required by
+ // the threaded loader. Only access them through their respective accessor methods.
+ QHash<QQmlMetaType::ModuleApi, QQmlMetaType::ModuleApiInstance *> moduleApiInstances;
+ QHash<const QMetaObject *, QQmlPropertyCache *> propertyCache;
+ QHash<QPair<QQmlType *, int>, QQmlPropertyCache *> typePropertyCache;
+ QHash<int, int> m_qmlLists;
+ QHash<int, QQmlCompiledData *> m_compositeTypes;
+
+ // These members is protected by the full QQmlEnginePrivate::mutex mutex
+ struct Deletable { Deletable():next(0) {} virtual ~Deletable() {} Deletable *next; };
+ QFieldList<Deletable, &Deletable::next> toDeleteInEngineThread;
+ void doDeleteInEngineThread();
+};
+
+QQmlEnginePrivate::Locker::Locker(const QQmlEngine *e)
+: m_ep(QQmlEnginePrivate::get(e))
+{
+ relock();
+}
+
+QQmlEnginePrivate::Locker::Locker(const QQmlEnginePrivate *e)
+: m_ep(e), m_locked(false)
+{
+ relock();
+}
+
+QQmlEnginePrivate::Locker::~Locker()
+{
+ unlock();
+}
+
+void QQmlEnginePrivate::Locker::unlock()
+{
+ if (m_locked) {
+ m_ep->mutex.unlock();
+ m_locked = false;
+ }
+}
+
+void QQmlEnginePrivate::Locker::relock()
+{
+ Q_ASSERT(!m_locked);
+ if (m_ep->typeLoader.isConcurrent()) {
+ m_ep->mutex.lock();
+ m_locked = true;
+ }
+}
+
+/*!
+Returns true if the calling thread is the QQmlEngine thread.
+*/
+bool QQmlEnginePrivate::isEngineThread() const
+{
+ Q_Q(const QQmlEngine);
+ return QThread::currentThread() == q->thread();
+}
+
+/*!
+Returns true if the calling thread is the QQmlEngine \a engine thread.
+*/
+bool QQmlEnginePrivate::isEngineThread(const QQmlEngine *engine)
+{
+ Q_ASSERT(engine);
+ return QQmlEnginePrivate::get(engine)->isEngineThread();
+}
+
+/*!
+Delete \a value in the engine thread. If the calling thread is the engine
+thread, \a value will be deleted immediately.
+
+This method should be used for *any* type that has resources that need to
+be freed in the engine thread. This is generally types that use V8 handles.
+As there is some small overhead in checking the current thread, it is best
+practice to check if any V8 handles actually need to be freed and delete
+the instance directly if not.
+*/
+template<typename T>
+void QQmlEnginePrivate::deleteInEngineThread(T *value)
+{
+ Q_Q(QQmlEngine);
+
+ Q_ASSERT(value);
+ if (isEngineThread()) {
+ delete value;
+ } else {
+ struct I : public Deletable {
+ I(T *value) : value(value) {}
+ ~I() { delete value; }
+ T *value;
+ };
+ I *i = new I(value);
+ mutex.lock();
+ bool wasEmpty = toDeleteInEngineThread.isEmpty();
+ toDeleteInEngineThread.append(i);
+ mutex.unlock();
+ if (wasEmpty)
+ QCoreApplication::postEvent(q, new QEvent(QEvent::User));
+ }
+}
+
+/*!
+Delete \a value in the \a engine thread. If the calling thread is the engine
+thread, \a value will be deleted immediately.
+*/
+template<typename T>
+void QQmlEnginePrivate::deleteInEngineThread(QQmlEngine *engine, T *value)
+{
+ Q_ASSERT(engine);
+ QQmlEnginePrivate::get(engine)->deleteInEngineThread<T>(value);
+}
+
+/*!
+Returns a QQmlPropertyCache for \a obj if one is available.
+
+If \a obj is null, being deleted or contains a dynamic meta object 0
+is returned.
+
+The returned cache is not referenced, so if it is to be stored, call addref().
+
+XXX thread There is a potential future race condition in this and all the cache()
+functions. As the QQmlPropertyCache is returned unreferenced, when called
+from the loader thread, it is possible that the cache will have been dereferenced
+and deleted before the loader thread has a chance to use or reference it. This
+can't currently happen as the cache holds a reference to the
+QQmlPropertyCache until the QQmlEngine is destroyed.
+*/
+QQmlPropertyCache *QQmlEnginePrivate::cache(QObject *obj)
+{
+ if (!obj || QObjectPrivate::get(obj)->metaObject || QObjectPrivate::get(obj)->wasDeleted)
+ return 0;
+
+ Locker locker(this);
+ const QMetaObject *mo = obj->metaObject();
+ QQmlPropertyCache *rv = propertyCache.value(mo);
+ if (!rv) rv = createCache(mo);
+ return rv;
+}
+
+/*!
+Returns a QQmlPropertyCache for \a metaObject.
+
+As the cache is persisted for the life of the engine, \a metaObject must be
+a static "compile time" meta-object, or a meta-object that is otherwise known to
+exist for the lifetime of the QQmlEngine.
+
+The returned cache is not referenced, so if it is to be stored, call addref().
+*/
+QQmlPropertyCache *QQmlEnginePrivate::cache(const QMetaObject *metaObject)
+{
+ Q_ASSERT(metaObject);
+
+ Locker locker(this);
+ QQmlPropertyCache *rv = propertyCache.value(metaObject);
+ if (!rv) rv = createCache(metaObject);
+ return rv;
+}
+
+/*!
+Returns a QQmlPropertyCache for \a type with \a minorVersion.
+
+The returned cache is not referenced, so if it is to be stored, call addref().
+*/
+QQmlPropertyCache *QQmlEnginePrivate::cache(QQmlType *type, int minorVersion, QQmlError &error)
+{
+ Q_ASSERT(type);
+
+ if (minorVersion == -1 || !type->containsRevisionedAttributes())
+ return cache(type->metaObject());
+
+ Locker locker(this);
+ QQmlPropertyCache *rv = typePropertyCache.value(qMakePair(type, minorVersion));
+ if (!rv) rv = createCache(type, minorVersion, error);
+ return rv;
+}
+
+QV8Engine *QQmlEnginePrivate::getV8Engine(QQmlEngine *e)
+{
+ return e->d_func()->v8engine();
+}
+
+QQmlEnginePrivate *QQmlEnginePrivate::get(QQmlEngine *e)
+{
+ return e->d_func();
+}
+
+const QQmlEnginePrivate *QQmlEnginePrivate::get(const QQmlEngine *e)
+{
+ return e->d_func();
+}
+
+QQmlEnginePrivate *QQmlEnginePrivate::get(QQmlContext *c)
+{
+ return (c && c->engine()) ? QQmlEnginePrivate::get(c->engine()) : 0;
+}
+
+QQmlEnginePrivate *QQmlEnginePrivate::get(QQmlContextData *c)
+{
+ return (c && c->engine) ? QQmlEnginePrivate::get(c->engine) : 0;
+}
+
+QQmlEngine *QQmlEnginePrivate::get(QQmlEnginePrivate *p)
+{
+ return p->q_func();
+}
+
+void QQmlEnginePrivate::captureProperty(QQmlNotifier *n)
+{
+ if (propertyCapture)
+ propertyCapture->captureProperty(n);
+}
+
+void QQmlEnginePrivate::captureProperty(QObject *o, int c, int n)
+{
+ if (propertyCapture)
+ propertyCapture->captureProperty(o, c, n);
+}
+
+QT_END_NAMESPACE
+
+#endif // QQMLENGINE_P_H
diff --git a/src/qml/qml/qqmlerror.cpp b/src/qml/qml/qqmlerror.cpp
new file mode 100644
index 0000000000..79424913f8
--- /dev/null
+++ b/src/qml/qml/qqmlerror.cpp
@@ -0,0 +1,285 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qqmlerror.h"
+
+#include <QtCore/qdebug.h>
+#include <QtCore/qfile.h>
+#include <QtCore/qstringlist.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QQmlError
+ \since 4.7
+ \brief The QQmlError class encapsulates a QML error.
+
+ QQmlError includes a textual description of the error, as well
+ as location information (the file, line, and column). The toString()
+ method creates a single-line, human-readable string containing all of
+ this information, for example:
+ \code
+ file:///home/user/test.qml:7:8: Invalid property assignment: double expected
+ \endcode
+
+ You can use qDebug() or qWarning() to output errors to the console. This method
+ will attempt to open the file indicated by the error
+ and include additional contextual information.
+ \code
+ file:///home/user/test.qml:7:8: Invalid property assignment: double expected
+ y: "hello"
+ ^
+ \endcode
+
+ \sa QQuickView::errors(), QQmlComponent::errors()
+*/
+class QQmlErrorPrivate
+{
+public:
+ QQmlErrorPrivate();
+
+ QUrl url;
+ QString description;
+ int line;
+ int column;
+};
+
+QQmlErrorPrivate::QQmlErrorPrivate()
+: line(-1), column(-1)
+{
+}
+
+/*!
+ Creates an empty error object.
+*/
+QQmlError::QQmlError()
+: d(0)
+{
+}
+
+/*!
+ Creates a copy of \a other.
+*/
+QQmlError::QQmlError(const QQmlError &other)
+: d(0)
+{
+ *this = other;
+}
+
+/*!
+ Assigns \a other to this error object.
+*/
+QQmlError &QQmlError::operator=(const QQmlError &other)
+{
+ if (!other.d) {
+ delete d;
+ d = 0;
+ } else {
+ if (!d) d = new QQmlErrorPrivate;
+ d->url = other.d->url;
+ d->description = other.d->description;
+ d->line = other.d->line;
+ d->column = other.d->column;
+ }
+ return *this;
+}
+
+/*!
+ \internal
+*/
+QQmlError::~QQmlError()
+{
+ delete d; d = 0;
+}
+
+/*!
+ Returns true if this error is valid, otherwise false.
+*/
+bool QQmlError::isValid() const
+{
+ return d != 0;
+}
+
+/*!
+ Returns the url for the file that caused this error.
+*/
+QUrl QQmlError::url() const
+{
+ if (d) return d->url;
+ else return QUrl();
+}
+
+/*!
+ Sets the \a url for the file that caused this error.
+*/
+void QQmlError::setUrl(const QUrl &url)
+{
+ if (!d) d = new QQmlErrorPrivate;
+ d->url = url;
+}
+
+/*!
+ Returns the error description.
+*/
+QString QQmlError::description() const
+{
+ if (d) return d->description;
+ else return QString();
+}
+
+/*!
+ Sets the error \a description.
+*/
+void QQmlError::setDescription(const QString &description)
+{
+ if (!d) d = new QQmlErrorPrivate;
+ d->description = description;
+}
+
+/*!
+ Returns the error line number.
+*/
+int QQmlError::line() const
+{
+ if (d) return d->line;
+ else return -1;
+}
+
+/*!
+ Sets the error \a line number.
+*/
+void QQmlError::setLine(int line)
+{
+ if (!d) d = new QQmlErrorPrivate;
+ d->line = line;
+}
+
+/*!
+ Returns the error column number.
+*/
+int QQmlError::column() const
+{
+ if (d) return d->column;
+ else return -1;
+}
+
+/*!
+ Sets the error \a column number.
+*/
+void QQmlError::setColumn(int column)
+{
+ if (!d) d = new QQmlErrorPrivate;
+ d->column = column;
+}
+
+/*!
+ Returns the error as a human readable string.
+*/
+QString QQmlError::toString() const
+{
+ QString rv;
+ if (url().isEmpty()) {
+ rv = QLatin1String("<Unknown File>");
+ } else if (line() != -1) {
+ rv = url().toString() + QLatin1Char(':') + QString::number(line());
+ if(column() != -1)
+ rv += QLatin1Char(':') + QString::number(column());
+ } else {
+ rv = url().toString();
+ }
+
+ rv += QLatin1String(": ") + description();
+
+ return rv;
+}
+
+/*!
+ \relates QQmlError
+ \fn QDebug operator<<(QDebug debug, const QQmlError &error)
+
+ Outputs a human readable version of \a error to \a debug.
+*/
+
+QDebug operator<<(QDebug debug, const QQmlError &error)
+{
+ debug << qPrintable(error.toString());
+
+ QUrl url = error.url();
+
+ if (error.line() > 0 && url.scheme() == QLatin1String("file")) {
+ QString file = url.toLocalFile();
+ QFile f(file);
+ if (f.open(QIODevice::ReadOnly)) {
+ QByteArray data = f.readAll();
+ QTextStream stream(data, QIODevice::ReadOnly);
+#ifndef QT_NO_TEXTCODEC
+ stream.setCodec("UTF-8");
+#endif
+ const QString code = stream.readAll();
+ const QStringList lines = code.split(QLatin1Char('\n'));
+
+ if (lines.count() >= error.line()) {
+ const QString &line = lines.at(error.line() - 1);
+ debug << "\n " << qPrintable(line);
+
+ if(error.column() > 0) {
+ int column = qMax(0, error.column() - 1);
+ column = qMin(column, line.length());
+
+ QByteArray ind;
+ ind.reserve(column);
+ for (int i = 0; i < column; ++i) {
+ const QChar ch = line.at(i);
+ if (ch.isSpace())
+ ind.append(ch.unicode());
+ else
+ ind.append(' ');
+ }
+ ind.append('^');
+ debug << "\n " << ind.constData();
+ }
+ }
+ }
+ }
+ return debug;
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlerror.h b/src/qml/qml/qqmlerror.h
new file mode 100644
index 0000000000..3c148549d0
--- /dev/null
+++ b/src/qml/qml/qqmlerror.h
@@ -0,0 +1,87 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLERROR_H
+#define QQMLERROR_H
+
+#include <QtQml/qtqmlglobal.h>
+
+#include <QtCore/qurl.h>
+#include <QtCore/qstring.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+
+class QDebug;
+class QQmlErrorPrivate;
+class Q_QML_EXPORT QQmlError
+{
+public:
+ QQmlError();
+ QQmlError(const QQmlError &);
+ QQmlError &operator=(const QQmlError &);
+ ~QQmlError();
+
+ bool isValid() const;
+
+ QUrl url() const;
+ void setUrl(const QUrl &);
+ QString description() const;
+ void setDescription(const QString &);
+ int line() const;
+ void setLine(int);
+ int column() const;
+ void setColumn(int);
+
+ QString toString() const;
+private:
+ QQmlErrorPrivate *d;
+};
+
+QDebug Q_QML_EXPORT operator<<(QDebug debug, const QQmlError &error);
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QQMLERROR_H
diff --git a/src/qml/qml/qqmlexpression.cpp b/src/qml/qml/qqmlexpression.cpp
new file mode 100644
index 0000000000..3fbb80c280
--- /dev/null
+++ b/src/qml/qml/qqmlexpression.cpp
@@ -0,0 +1,982 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qqmlexpression.h"
+#include "qqmlexpression_p.h"
+
+#include "qqmlengine_p.h"
+#include "qqmlcontext_p.h"
+#include "qqmlrewrite_p.h"
+#include "qqmlscriptstring_p.h"
+#include "qqmlcompiler_p.h"
+
+#include <QtCore/qdebug.h>
+
+QT_BEGIN_NAMESPACE
+
+bool QQmlDelayedError::addError(QQmlEnginePrivate *e)
+{
+ if (!e) return false;
+
+ if (e->inProgressCreations == 0) return false; // Not in construction
+
+ if (prevError) return true; // Already in error chain
+
+ prevError = &e->erroredBindings;
+ nextError = e->erroredBindings;
+ e->erroredBindings = this;
+ if (nextError) nextError->prevError = &nextError;
+
+ return true;
+}
+
+QQmlJavaScriptExpression::QQmlJavaScriptExpression(VTable *v)
+: m_vtable(v)
+{
+}
+
+QQmlJavaScriptExpression::~QQmlJavaScriptExpression()
+{
+ clearGuards();
+}
+
+static QQmlJavaScriptExpression::VTable QDeclarativeExpressionPrivate_jsvtable = {
+ QQmlExpressionPrivate::expressionIdentifier,
+ QQmlExpressionPrivate::expressionChanged
+};
+
+QQmlExpressionPrivate::QQmlExpressionPrivate()
+: QQmlJavaScriptExpression(&QDeclarativeExpressionPrivate_jsvtable),
+ expressionFunctionValid(true), expressionFunctionRewritten(false),
+ extractExpressionFromFunction(false), line(-1), dataRef(0)
+{
+}
+
+QQmlExpressionPrivate::~QQmlExpressionPrivate()
+{
+ qPersistentDispose(v8qmlscope);
+ qPersistentDispose(v8function);
+ if (dataRef) dataRef->release();
+ dataRef = 0;
+}
+
+void QQmlExpressionPrivate::init(QQmlContextData *ctxt, const QString &expr,
+ QObject *me)
+{
+ expression = expr;
+
+ QQmlAbstractExpression::setContext(ctxt);
+ setScopeObject(me);
+ expressionFunctionValid = false;
+ expressionFunctionRewritten = false;
+}
+
+void QQmlExpressionPrivate::init(QQmlContextData *ctxt, v8::Handle<v8::Function> func,
+ QObject *me)
+{
+ QQmlAbstractExpression::setContext(ctxt);
+ setScopeObject(me);
+
+ v8function = qPersistentNew<v8::Function>(func);
+ setUseSharedContext(false);
+ expressionFunctionValid = true;
+ expressionFunctionRewritten = false;
+ extractExpressionFromFunction = true;
+}
+
+void QQmlExpressionPrivate::init(QQmlContextData *ctxt, const QString &expr,
+ bool isRewritten, QObject *me, const QString &srcUrl,
+ int lineNumber, int columnNumber)
+{
+ url = srcUrl;
+ line = lineNumber;
+ column = columnNumber;
+
+ expression = expr;
+
+ expressionFunctionValid = false;
+ expressionFunctionRewritten = isRewritten;
+
+ QQmlAbstractExpression::setContext(ctxt);
+ setScopeObject(me);
+}
+
+void QQmlExpressionPrivate::init(QQmlContextData *ctxt, const QByteArray &expr,
+ bool isRewritten, QObject *me, const QString &srcUrl,
+ int lineNumber, int columnNumber)
+{
+ url = srcUrl;
+ line = lineNumber;
+ column = columnNumber;
+
+ if (isRewritten) {
+ expressionFunctionValid = true;
+ expressionFunctionRewritten = true;
+ v8function = evalFunction(ctxt, me, expr.constData(), expr.length(),
+ srcUrl, lineNumber, &v8qmlscope);
+ setUseSharedContext(false);
+
+ expressionUtf8 = expr;
+ } else {
+ expression = QString::fromUtf8(expr);
+
+ expressionFunctionValid = false;
+ expressionFunctionRewritten = isRewritten;
+ }
+
+ QQmlAbstractExpression::setContext(ctxt);
+ setScopeObject(me);
+}
+
+// Callee owns the persistent handle
+v8::Persistent<v8::Function>
+QQmlExpressionPrivate::evalFunction(QQmlContextData *ctxt, QObject *scope,
+ const char *code, int codeLength,
+ const QString &filename, int line,
+ v8::Persistent<v8::Object> *qmlscope)
+{
+ QQmlEngine *engine = ctxt->engine;
+ QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine);
+
+ v8::HandleScope handle_scope;
+ v8::Context::Scope ctxtscope(ep->v8engine()->context());
+
+ v8::TryCatch tc;
+ v8::Local<v8::Object> scopeobject = ep->v8engine()->qmlScope(ctxt, scope);
+ v8::Local<v8::Script> script = ep->v8engine()->qmlModeCompile(code, codeLength, filename, line);
+ if (tc.HasCaught()) {
+ QQmlError error;
+ error.setDescription(QLatin1String("Exception occurred during function compilation"));
+ error.setLine(line);
+ error.setUrl(QUrl::fromLocalFile(filename));
+ v8::Local<v8::Message> message = tc.Message();
+ if (!message.IsEmpty())
+ QQmlExpressionPrivate::exceptionToError(message, error);
+ ep->warning(error);
+ return v8::Persistent<v8::Function>();
+ }
+ v8::Local<v8::Value> result = script->Run(scopeobject);
+ if (tc.HasCaught()) {
+ QQmlError error;
+ error.setDescription(QLatin1String("Exception occurred during function evaluation"));
+ error.setLine(line);
+ error.setUrl(QUrl::fromLocalFile(filename));
+ v8::Local<v8::Message> message = tc.Message();
+ if (!message.IsEmpty())
+ QQmlExpressionPrivate::exceptionToError(message, error);
+ ep->warning(error);
+ return v8::Persistent<v8::Function>();
+ }
+ if (qmlscope) *qmlscope = qPersistentNew<v8::Object>(scopeobject);
+ return qPersistentNew<v8::Function>(v8::Local<v8::Function>::Cast(result));
+}
+
+// Callee owns the persistent handle
+v8::Persistent<v8::Function>
+QQmlExpressionPrivate::evalFunction(QQmlContextData *ctxt, QObject *scope,
+ const QString &code, const QString &filename, int line,
+ v8::Persistent<v8::Object> *qmlscope)
+{
+ QQmlEngine *engine = ctxt->engine;
+ QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine);
+
+ v8::HandleScope handle_scope;
+ v8::Context::Scope ctxtscope(ep->v8engine()->context());
+
+ v8::TryCatch tc;
+ v8::Local<v8::Object> scopeobject = ep->v8engine()->qmlScope(ctxt, scope);
+ v8::Local<v8::Script> script = ep->v8engine()->qmlModeCompile(code, filename, line);
+ if (tc.HasCaught()) {
+ QQmlError error;
+ error.setDescription(QLatin1String("Exception occurred during function compilation"));
+ error.setLine(line);
+ error.setUrl(QUrl::fromLocalFile(filename));
+ v8::Local<v8::Message> message = tc.Message();
+ if (!message.IsEmpty())
+ QQmlExpressionPrivate::exceptionToError(message, error);
+ ep->warning(error);
+ return v8::Persistent<v8::Function>();
+ }
+ v8::Local<v8::Value> result = script->Run(scopeobject);
+ if (tc.HasCaught()) {
+ QQmlError error;
+ error.setDescription(QLatin1String("Exception occurred during function evaluation"));
+ error.setLine(line);
+ error.setUrl(QUrl::fromLocalFile(filename));
+ v8::Local<v8::Message> message = tc.Message();
+ if (!message.IsEmpty())
+ QQmlExpressionPrivate::exceptionToError(message, error);
+ ep->warning(error);
+ return v8::Persistent<v8::Function>();
+ }
+ if (qmlscope) *qmlscope = qPersistentNew<v8::Object>(scopeobject);
+ return qPersistentNew<v8::Function>(v8::Local<v8::Function>::Cast(result));
+}
+
+QQmlExpression *
+QQmlExpressionPrivate::create(QQmlContextData *ctxt, QObject *object,
+ const QString &expr, bool isRewritten,
+ const QString &url, int lineNumber, int columnNumber)
+{
+ return new QQmlExpression(ctxt, object, expr, isRewritten, url, lineNumber, columnNumber, *new QQmlExpressionPrivate);
+}
+
+/*!
+ \class QQmlExpression
+ \since 4.7
+ \brief The QQmlExpression class evaluates JavaScript in a QML context.
+
+ For example, given a file \c main.qml like this:
+
+ \qml
+ import QtQuick 2.0
+
+ Item {
+ width: 200; height: 200
+ }
+ \endqml
+
+ The following code evaluates a JavaScript expression in the context of the
+ above QML:
+
+ \code
+ QQmlEngine *engine = new QQmlEngine;
+ QQmlComponent component(engine, QUrl::fromLocalFile("main.qml"));
+
+ QObject *myObject = component.create();
+ QQmlExpression *expr = new QQmlExpression(engine->rootContext(), myObject, "width * 2");
+ int result = expr->evaluate().toInt(); // result = 400
+ \endcode
+*/
+
+/*!
+ Create an invalid QQmlExpression.
+
+ As the expression will not have an associated QQmlContext, this will be a
+ null expression object and its value will always be an invalid QVariant.
+ */
+QQmlExpression::QQmlExpression()
+: QObject(*new QQmlExpressionPrivate, 0)
+{
+}
+
+/*! \internal */
+QQmlExpression::QQmlExpression(QQmlContextData *ctxt,
+ QObject *object, const QString &expr, bool isRewritten,
+ const QString &url, int lineNumber, int columnNumber,
+ QQmlExpressionPrivate &dd)
+: QObject(dd, 0)
+{
+ Q_D(QQmlExpression);
+ d->init(ctxt, expr, isRewritten, object, url, lineNumber, columnNumber);
+}
+
+/*! \internal */
+QQmlExpression::QQmlExpression(QQmlContextData *ctxt,
+ QObject *object, const QByteArray &expr,
+ bool isRewritten,
+ const QString &url, int lineNumber, int columnNumber,
+ QQmlExpressionPrivate &dd)
+: QObject(dd, 0)
+{
+ Q_D(QQmlExpression);
+ d->init(ctxt, expr, isRewritten, object, url, lineNumber, columnNumber);
+}
+
+/*!
+ Create a QQmlExpression object that is a child of \a parent.
+
+ The \script provides the expression to be evaluated, the context to evaluate it in,
+ and the scope object to evaluate it with.
+
+ This constructor is functionally equivalent to the following, but in most cases
+ is more efficient.
+ \code
+ QQmlExpression expression(script.context(), script.scopeObject(), script.script(), parent);
+ \endcode
+
+ \sa QQmlScriptString
+*/
+QQmlExpression::QQmlExpression(const QQmlScriptString &script, QObject *parent)
+: QObject(*new QQmlExpressionPrivate, parent)
+{
+ Q_D(QQmlExpression);
+ bool defaultConstruction = false;
+
+ int id = script.d.data()->bindingId;
+ if (id < 0) {
+ defaultConstruction = true;
+ } else {
+ QQmlContextData *ctxtdata = QQmlContextData::get(script.context());
+
+ QQmlEnginePrivate *engine = QQmlEnginePrivate::get(script.context()->engine());
+ QQmlCompiledData *cdata = 0;
+ QQmlTypeData *typeData = 0;
+ if (engine && ctxtdata && !ctxtdata->url.isEmpty()) {
+ typeData = engine->typeLoader.get(ctxtdata->url);
+ cdata = typeData->compiledData();
+ }
+
+ if (cdata)
+ d->init(ctxtdata, cdata->primitives.at(id), true, script.scopeObject(),
+ cdata->name, script.d.data()->lineNumber, script.d.data()->columnNumber);
+ else
+ defaultConstruction = true;
+
+ if (cdata)
+ cdata->release();
+ if (typeData)
+ typeData->release();
+ }
+
+ if (defaultConstruction)
+ d->init(QQmlContextData::get(script.context()), script.script(), script.scopeObject());
+}
+
+/*!
+ Create a QQmlExpression object that is a child of \a parent.
+
+ The \a expression JavaScript will be executed in the \a ctxt QQmlContext.
+ If specified, the \a scope object's properties will also be in scope during
+ the expression's execution.
+*/
+QQmlExpression::QQmlExpression(QQmlContext *ctxt,
+ QObject *scope,
+ const QString &expression,
+ QObject *parent)
+: QObject(*new QQmlExpressionPrivate, parent)
+{
+ Q_D(QQmlExpression);
+ d->init(QQmlContextData::get(ctxt), expression, scope);
+}
+
+/*!
+ \internal
+*/
+QQmlExpression::QQmlExpression(QQmlContextData *ctxt, QObject *scope,
+ const QString &expression)
+: QObject(*new QQmlExpressionPrivate, 0)
+{
+ Q_D(QQmlExpression);
+ d->init(ctxt, expression, scope);
+}
+
+/*! \internal */
+QQmlExpression::QQmlExpression(QQmlContextData *ctxt, QObject *scope,
+ const QString &expression, QQmlExpressionPrivate &dd)
+: QObject(dd, 0)
+{
+ Q_D(QQmlExpression);
+ d->init(ctxt, expression, scope);
+}
+
+/*!
+ \internal
+
+ To avoid exposing v8 in the public API, functionPtr must be a pointer to a v8::Handle<v8::Function>.
+ For example:
+ v8::Handle<v8::Function> function;
+ new QQmlExpression(ctxt, scope, &function, ...);
+ */
+QQmlExpression::QQmlExpression(QQmlContextData *ctxt, QObject *scope, void *functionPtr,
+ QQmlExpressionPrivate &dd)
+: QObject(dd, 0)
+{
+ v8::Handle<v8::Function> function = *(v8::Handle<v8::Function> *)functionPtr;
+
+ Q_D(QQmlExpression);
+ d->init(ctxt, function, scope);
+}
+
+/*!
+ Destroy the QQmlExpression instance.
+*/
+QQmlExpression::~QQmlExpression()
+{
+}
+
+/*!
+ Returns the QQmlEngine this expression is associated with, or 0 if there
+ is no association or the QQmlEngine has been destroyed.
+*/
+QQmlEngine *QQmlExpression::engine() const
+{
+ Q_D(const QQmlExpression);
+ return d->context()?d->context()->engine:0;
+}
+
+/*!
+ Returns the QQmlContext this expression is associated with, or 0 if there
+ is no association or the QQmlContext has been destroyed.
+*/
+QQmlContext *QQmlExpression::context() const
+{
+ Q_D(const QQmlExpression);
+ QQmlContextData *data = d->context();
+ return data?data->asQQmlContext():0;
+}
+
+/*!
+ Returns the expression string.
+*/
+QString QQmlExpression::expression() const
+{
+ Q_D(const QQmlExpression);
+ if (d->extractExpressionFromFunction && context()->engine()) {
+ QV8Engine *v8engine = QQmlEnginePrivate::getV8Engine(context()->engine());
+ v8::HandleScope handle_scope;
+ v8::Context::Scope scope(v8engine->context());
+
+ return v8engine->toString(v8::Handle<v8::Value>(d->v8function));
+ } else if (!d->expressionUtf8.isEmpty()) {
+ return QString::fromUtf8(d->expressionUtf8);
+ } else {
+ return d->expression;
+ }
+}
+
+/*!
+ Set the expression to \a expression.
+*/
+void QQmlExpression::setExpression(const QString &expression)
+{
+ Q_D(QQmlExpression);
+
+ d->resetNotifyOnValueChanged();
+ d->expression = expression;
+ d->expressionUtf8.clear();
+ d->expressionFunctionValid = false;
+ d->expressionFunctionRewritten = false;
+ qPersistentDispose(d->v8function);
+ qPersistentDispose(d->v8qmlscope);
+}
+
+void QQmlExpressionPrivate::exceptionToError(v8::Handle<v8::Message> message,
+ QQmlError &error)
+{
+ Q_ASSERT(!message.IsEmpty());
+
+ v8::Handle<v8::Value> name = message->GetScriptResourceName();
+ v8::Handle<v8::String> description = message->Get();
+ int lineNumber = message->GetLineNumber();
+
+ v8::Local<v8::String> file = name->IsString()?name->ToString():v8::Local<v8::String>();
+ if (file.IsEmpty() || file->Length() == 0)
+ error.setUrl(QUrl(QLatin1String("<Unknown File>")));
+ else
+ error.setUrl(QUrl(QV8Engine::toStringStatic(file)));
+
+ error.setLine(lineNumber);
+ error.setColumn(-1);
+
+ QString qDescription = QV8Engine::toStringStatic(description);
+ if (qDescription.startsWith(QLatin1String("Uncaught ")))
+ qDescription = qDescription.mid(9 /* strlen("Uncaught ") */);
+
+ error.setDescription(qDescription);
+}
+
+void QQmlJavaScriptExpression::setNotifyOnValueChanged(bool v)
+{
+ activeGuards.setFlagValue(v);
+ if (!v) clearGuards();
+}
+
+void QQmlJavaScriptExpression::resetNotifyOnValueChanged()
+{
+ clearGuards();
+}
+
+v8::Local<v8::Value>
+QQmlJavaScriptExpression::evaluate(QQmlContextData *context,
+ v8::Handle<v8::Function> function, bool *isUndefined)
+{
+ Q_ASSERT(context && context->engine);
+
+ if (function.IsEmpty() || function->IsUndefined()) {
+ if (isUndefined) *isUndefined = true;
+ return v8::Local<v8::Value>();
+ }
+
+ QQmlEnginePrivate *ep = QQmlEnginePrivate::get(context->engine);
+
+ Q_ASSERT(notifyOnValueChanged() || activeGuards.isEmpty());
+ GuardCapture capture(context->engine, this);
+
+ QQmlEnginePrivate::PropertyCapture *lastPropertyCapture = ep->propertyCapture;
+ ep->propertyCapture = notifyOnValueChanged()?&capture:0;
+
+
+ if (notifyOnValueChanged())
+ capture.guards.copyAndClearPrepend(activeGuards);
+
+ QQmlContextData *lastSharedContext = 0;
+ QObject *lastSharedScope = 0;
+
+ bool sharedContext = useSharedContext();
+
+ // All code that follows must check with watcher before it accesses data members
+ // incase we have been deleted.
+ DeleteWatcher watcher(this);
+
+ if (sharedContext) {
+ lastSharedContext = ep->sharedContext;
+ lastSharedScope = ep->sharedScope;
+ ep->sharedContext = context;
+ ep->sharedScope = scopeObject();
+ }
+
+ v8::Local<v8::Value> result;
+ {
+ v8::TryCatch try_catch;
+ v8::Handle<v8::Object> This = ep->v8engine()->global();
+ if (scopeObject() && requiresThisObject()) {
+ v8::Handle<v8::Value> value = ep->v8engine()->newQObject(scopeObject());
+ if (value->IsObject()) This = v8::Handle<v8::Object>::Cast(value);
+ }
+
+ result = function->Call(This, 0, 0);
+
+ if (isUndefined)
+ *isUndefined = try_catch.HasCaught() || result->IsUndefined();
+
+ if (watcher.wasDeleted()) {
+ } else if (try_catch.HasCaught()) {
+ v8::Context::Scope scope(ep->v8engine()->context());
+ v8::Local<v8::Message> message = try_catch.Message();
+ if (!message.IsEmpty()) {
+ QQmlExpressionPrivate::exceptionToError(message, delayedError()->error);
+ } else {
+ if (hasDelayedError()) delayedError()->error = QQmlError();
+ }
+ } else {
+ if (hasDelayedError()) delayedError()->error = QQmlError();
+ }
+ }
+
+ if (sharedContext) {
+ ep->sharedContext = lastSharedContext;
+ ep->sharedScope = lastSharedScope;
+ }
+
+ if (capture.errorString) {
+ for (int ii = 0; ii < capture.errorString->count(); ++ii)
+ qWarning("%s", qPrintable(capture.errorString->at(ii)));
+ delete capture.errorString;
+ capture.errorString = 0;
+ }
+
+ while (Guard *g = capture.guards.takeFirst())
+ g->Delete();
+
+ ep->propertyCapture = lastPropertyCapture;
+
+ return result;
+}
+
+void QQmlJavaScriptExpression::GuardCapture::captureProperty(QQmlNotifier *n)
+{
+ if (expression) {
+
+ // Try and find a matching guard
+ while (!guards.isEmpty() && !guards.first()->isConnected(n))
+ guards.takeFirst()->Delete();
+
+ Guard *g = 0;
+ if (!guards.isEmpty()) {
+ g = guards.takeFirst();
+ g->cancelNotify();
+ Q_ASSERT(g->isConnected(n));
+ } else {
+ g = Guard::New(expression, engine);
+ g->connect(n);
+ }
+
+ expression->activeGuards.prepend(g);
+ }
+}
+
+void QQmlJavaScriptExpression::GuardCapture::captureProperty(QObject *o, int c, int n)
+{
+ if (expression) {
+ if (n == -1) {
+ if (!errorString) {
+ errorString = new QStringList;
+ QString preamble = QLatin1String("QQmlExpression: Expression ") +
+ expression->m_vtable->expressionIdentifier(expression) +
+ QLatin1String(" depends on non-NOTIFYable properties:");
+ errorString->append(preamble);
+ }
+
+ const QMetaObject *metaObj = o->metaObject();
+ QMetaProperty metaProp = metaObj->property(c);
+
+ QString error = QLatin1String(" ") +
+ QString::fromUtf8(metaObj->className()) +
+ QLatin1String("::") +
+ QString::fromUtf8(metaProp.name());
+ errorString->append(error);
+ } else {
+
+ // Try and find a matching guard
+ while (!guards.isEmpty() && !guards.first()->isConnected(o, n))
+ guards.takeFirst()->Delete();
+
+ Guard *g = 0;
+ if (!guards.isEmpty()) {
+ g = guards.takeFirst();
+ g->cancelNotify();
+ Q_ASSERT(g->isConnected(o, n));
+ } else {
+ g = Guard::New(expression, engine);
+ g->connect(o, n);
+ }
+
+ expression->activeGuards.prepend(g);
+ }
+ }
+}
+
+void QQmlJavaScriptExpression::clearError()
+{
+ if (m_vtable.hasValue()) {
+ m_vtable.value().error = QQmlError();
+ m_vtable.value().removeError();
+ }
+}
+
+QQmlError QQmlJavaScriptExpression::error() const
+{
+ if (m_vtable.hasValue()) return m_vtable.constValue()->error;
+ else return QQmlError();
+}
+
+QQmlDelayedError *QQmlJavaScriptExpression::delayedError()
+{
+ return &m_vtable.value();
+}
+
+void QQmlJavaScriptExpression::clearGuards()
+{
+ while (Guard *g = activeGuards.takeFirst())
+ g->Delete();
+}
+
+// Must be called with a valid handle scope
+v8::Local<v8::Value> QQmlExpressionPrivate::v8value(QObject *secondaryScope, bool *isUndefined)
+{
+ if (!expressionFunctionValid) {
+ bool ok = true;
+
+ QQmlRewrite::RewriteBinding rewriteBinding;
+ rewriteBinding.setName(name);
+ QString code;
+ if (expressionFunctionRewritten)
+ code = expression;
+ else
+ code = rewriteBinding(expression, &ok);
+
+ if (ok) v8function = evalFunction(context(), scopeObject(), code, url, line, &v8qmlscope);
+ setUseSharedContext(false);
+ expressionFunctionValid = true;
+ }
+
+
+ if (secondaryScope) {
+ v8::Local<v8::Value> result;
+ QQmlEnginePrivate *ep = QQmlEnginePrivate::get(context()->engine);
+ QObject *restoreSecondaryScope = 0;
+ restoreSecondaryScope = ep->v8engine()->contextWrapper()->setSecondaryScope(v8qmlscope, secondaryScope);
+ result = evaluate(context(), v8function, isUndefined);
+ ep->v8engine()->contextWrapper()->setSecondaryScope(v8qmlscope, restoreSecondaryScope);
+ return result;
+ } else {
+ return evaluate(context(), v8function, isUndefined);
+ }
+}
+
+QVariant QQmlExpressionPrivate::value(QObject *secondaryScope, bool *isUndefined)
+{
+ Q_Q(QQmlExpression);
+
+ if (!context() || !context()->isValid()) {
+ qWarning("QQmlExpression: Attempted to evaluate an expression in an invalid context");
+ return QVariant();
+ }
+
+ QQmlEnginePrivate *ep = QQmlEnginePrivate::get(q->engine());
+ QVariant rv;
+
+ ep->referenceScarceResources(); // "hold" scarce resources in memory during evaluation.
+
+ {
+ v8::HandleScope handle_scope;
+ v8::Context::Scope context_scope(ep->v8engine()->context());
+ v8::Local<v8::Value> result = v8value(secondaryScope, isUndefined);
+ rv = ep->v8engine()->toVariant(result, qMetaTypeId<QList<QObject*> >());
+ }
+
+ ep->dereferenceScarceResources(); // "release" scarce resources if top-level expression evaluation is complete.
+
+ return rv;
+}
+
+/*!
+ Evaulates the expression, returning the result of the evaluation,
+ or an invalid QVariant if the expression is invalid or has an error.
+
+ \a valueIsUndefined is set to true if the expression resulted in an
+ undefined value.
+
+ \sa hasError(), error()
+*/
+QVariant QQmlExpression::evaluate(bool *valueIsUndefined)
+{
+ Q_D(QQmlExpression);
+ return d->value(0, valueIsUndefined);
+}
+
+/*!
+Returns true if the valueChanged() signal is emitted when the expression's evaluated
+value changes.
+*/
+bool QQmlExpression::notifyOnValueChanged() const
+{
+ Q_D(const QQmlExpression);
+ return d->notifyOnValueChanged();
+}
+
+/*!
+ Sets whether the valueChanged() signal is emitted when the
+ expression's evaluated value changes.
+
+ If \a notifyOnChange is true, the QQmlExpression will
+ monitor properties involved in the expression's evaluation, and emit
+ QQmlExpression::valueChanged() if they have changed. This
+ allows an application to ensure that any value associated with the
+ result of the expression remains up to date.
+
+ If \a notifyOnChange is false (default), the QQmlExpression
+ will not montitor properties involved in the expression's
+ evaluation, and QQmlExpression::valueChanged() will never be
+ emitted. This is more efficient if an application wants a "one off"
+ evaluation of the expression.
+*/
+void QQmlExpression::setNotifyOnValueChanged(bool notifyOnChange)
+{
+ Q_D(QQmlExpression);
+ d->setNotifyOnValueChanged(notifyOnChange);
+}
+
+/*!
+ Returns the source file URL for this expression. The source location must
+ have been previously set by calling setSourceLocation().
+*/
+QString QQmlExpression::sourceFile() const
+{
+ Q_D(const QQmlExpression);
+ return d->url;
+}
+
+/*!
+ Returns the source file line number for this expression. The source location
+ must have been previously set by calling setSourceLocation().
+*/
+int QQmlExpression::lineNumber() const
+{
+ Q_D(const QQmlExpression);
+ return d->line;
+}
+
+/*!
+ Returns the source file column number for this expression. The source location
+ must have been previously set by calling setSourceLocation().
+*/
+int QQmlExpression::columnNumber() const
+{
+ Q_D(const QQmlExpression);
+ return d->column;
+}
+
+/*!
+ Set the location of this expression to \a line of \a url. This information
+ is used by the script engine.
+*/
+void QQmlExpression::setSourceLocation(const QString &url, int line, int column)
+{
+ Q_D(QQmlExpression);
+ d->url = url;
+ d->line = line;
+ d->column = column;
+}
+
+/*!
+ Returns the expression's scope object, if provided, otherwise 0.
+
+ In addition to data provided by the expression's QQmlContext, the scope
+ object's properties are also in scope during the expression's evaluation.
+*/
+QObject *QQmlExpression::scopeObject() const
+{
+ Q_D(const QQmlExpression);
+ return d->scopeObject();
+}
+
+/*!
+ Returns true if the last call to evaluate() resulted in an error,
+ otherwise false.
+
+ \sa error(), clearError()
+*/
+bool QQmlExpression::hasError() const
+{
+ Q_D(const QQmlExpression);
+ return d->hasError();
+}
+
+/*!
+ Clear any expression errors. Calls to hasError() following this will
+ return false.
+
+ \sa hasError(), error()
+*/
+void QQmlExpression::clearError()
+{
+ Q_D(QQmlExpression);
+ d->clearError();
+}
+
+/*!
+ Return any error from the last call to evaluate(). If there was no error,
+ this returns an invalid QQmlError instance.
+
+ \sa hasError(), clearError()
+*/
+
+QQmlError QQmlExpression::error() const
+{
+ Q_D(const QQmlExpression);
+ return d->error();
+}
+
+/*!
+ \fn void QQmlExpression::valueChanged()
+
+ Emitted each time the expression value changes from the last time it was
+ evaluated. The expression must have been evaluated at least once (by
+ calling QQmlExpression::evaluate()) before this signal will be emitted.
+*/
+
+void QQmlExpressionPrivate::expressionChanged(QQmlJavaScriptExpression *e)
+{
+ QQmlExpressionPrivate *This = static_cast<QQmlExpressionPrivate *>(e);
+ This->expressionChanged();
+}
+
+void QQmlExpressionPrivate::expressionChanged()
+{
+ Q_Q(QQmlExpression);
+ emit q->valueChanged();
+}
+
+QString QQmlExpressionPrivate::expressionIdentifier(QQmlJavaScriptExpression *e)
+{
+ QQmlExpressionPrivate *This = static_cast<QQmlExpressionPrivate *>(e);
+ return QLatin1String("\"") + This->expression + QLatin1String("\"");
+}
+
+QQmlAbstractExpression::QQmlAbstractExpression()
+: m_prevExpression(0), m_nextExpression(0)
+{
+}
+
+QQmlAbstractExpression::~QQmlAbstractExpression()
+{
+ if (m_prevExpression) {
+ *m_prevExpression = m_nextExpression;
+ if (m_nextExpression)
+ m_nextExpression->m_prevExpression = m_prevExpression;
+ }
+
+ if (m_context.isT2())
+ m_context.asT2()->_s = 0;
+}
+
+QQmlContextData *QQmlAbstractExpression::context() const
+{
+ if (m_context.isT1()) return m_context.asT1();
+ else return m_context.asT2()->_c;
+}
+
+void QQmlAbstractExpression::setContext(QQmlContextData *context)
+{
+ if (m_prevExpression) {
+ *m_prevExpression = m_nextExpression;
+ if (m_nextExpression)
+ m_nextExpression->m_prevExpression = m_prevExpression;
+ m_prevExpression = 0;
+ m_nextExpression = 0;
+ }
+
+ if (m_context.isT1()) m_context = context;
+ else m_context.asT2()->_c = context;
+
+ if (context) {
+ m_nextExpression = context->expressions;
+ if (m_nextExpression)
+ m_nextExpression->m_prevExpression = &m_nextExpression;
+ m_prevExpression = &context->expressions;
+ context->expressions = this;
+ }
+}
+
+void QQmlAbstractExpression::refresh()
+{
+}
+
+bool QQmlAbstractExpression::isValid() const
+{
+ return context() != 0;
+}
+
+QT_END_NAMESPACE
+
+#include <moc_qqmlexpression.cpp>
diff --git a/src/qml/qml/qqmlexpression.h b/src/qml/qml/qqmlexpression.h
new file mode 100644
index 0000000000..4044546fbf
--- /dev/null
+++ b/src/qml/qml/qqmlexpression.h
@@ -0,0 +1,121 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLEXPRESSION_H
+#define QQMLEXPRESSION_H
+
+#include <QtQml/qqmlerror.h>
+#include <QtQml/qqmlscriptstring.h>
+
+#include <QtCore/qobject.h>
+#include <QtCore/qvariant.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+
+class QString;
+class QQmlRefCount;
+class QQmlEngine;
+class QQmlContext;
+class QQmlExpressionPrivate;
+class QQmlContextData;
+class Q_QML_EXPORT QQmlExpression : public QObject
+{
+ Q_OBJECT
+public:
+ QQmlExpression();
+ QQmlExpression(QQmlContext *, QObject *, const QString &, QObject * = 0);
+ explicit QQmlExpression(const QQmlScriptString &, QObject * = 0);
+ virtual ~QQmlExpression();
+
+ QQmlEngine *engine() const;
+ QQmlContext *context() const;
+
+ QString expression() const;
+ void setExpression(const QString &);
+
+ bool notifyOnValueChanged() const;
+ void setNotifyOnValueChanged(bool);
+
+ QString sourceFile() const;
+ int lineNumber() const;
+ int columnNumber() const;
+ void setSourceLocation(const QString &fileName, int line, int column = 0);
+
+ QObject *scopeObject() const;
+
+ bool hasError() const;
+ void clearError();
+ QQmlError error() const;
+
+ QVariant evaluate(bool *valueIsUndefined = 0);
+
+Q_SIGNALS:
+ void valueChanged();
+
+protected:
+ QQmlExpression(QQmlContextData *, QObject *, const QString &,
+ QQmlExpressionPrivate &dd);
+ QQmlExpression(QQmlContextData *, QObject *, void *,
+ QQmlExpressionPrivate &dd);
+ QQmlExpression(QQmlContextData *, QObject *, const QString &, bool,
+ const QString &, int, int, QQmlExpressionPrivate &dd);
+ QQmlExpression(QQmlContextData *, QObject *, const QByteArray &, bool,
+ const QString &, int, int, QQmlExpressionPrivate &dd);
+
+private:
+ QQmlExpression(QQmlContextData *, QObject *, const QString &);
+
+ Q_DISABLE_COPY(QQmlExpression)
+ Q_DECLARE_PRIVATE(QQmlExpression)
+ friend class QQmlDebugger;
+ friend class QQmlContext;
+ friend class QQmlVME;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QQMLEXPRESSION_H
+
diff --git a/src/qml/qml/qqmlexpression_p.h b/src/qml/qml/qqmlexpression_p.h
new file mode 100644
index 0000000000..deca29ab60
--- /dev/null
+++ b/src/qml/qml/qqmlexpression_p.h
@@ -0,0 +1,406 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLEXPRESSION_P_H
+#define QQMLEXPRESSION_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 "qqmlexpression.h"
+
+#include <private/qv8engine_p.h>
+#include <private/qfieldlist_p.h>
+#include <private/qflagpointer_p.h>
+#include <private/qdeletewatcher_p.h>
+#include <private/qqmlguard_p.h>
+#include <private/qpointervaluepair_p.h>
+#include <private/qqmlengine_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQmlAbstractExpression
+{
+public:
+ QQmlAbstractExpression();
+ virtual ~QQmlAbstractExpression();
+
+ bool isValid() const;
+
+ QQmlContextData *context() const;
+ void setContext(QQmlContextData *);
+
+ virtual void refresh();
+
+ class DeleteWatcher {
+ public:
+ inline DeleteWatcher(QQmlAbstractExpression *);
+ inline ~DeleteWatcher();
+ inline bool wasDeleted() const;
+ private:
+ friend class QQmlAbstractExpression;
+ QQmlContextData *_c;
+ QQmlAbstractExpression **_w;
+ QQmlAbstractExpression *_s;
+ };
+
+private:
+ friend class QQmlContext;
+ friend class QQmlContextData;
+ friend class QQmlContextPrivate;
+
+ QBiPointer<QQmlContextData, DeleteWatcher> m_context;
+ QQmlAbstractExpression **m_prevExpression;
+ QQmlAbstractExpression *m_nextExpression;
+};
+
+class QQmlDelayedError
+{
+public:
+ inline QQmlDelayedError() : nextError(0), prevError(0) {}
+ inline ~QQmlDelayedError() { removeError(); }
+
+ QQmlError error;
+
+ bool addError(QQmlEnginePrivate *);
+
+ inline void removeError() {
+ if (!prevError) return;
+ if (nextError) nextError->prevError = prevError;
+ *prevError = nextError;
+ nextError = 0;
+ prevError = 0;
+ }
+
+private:
+ QQmlDelayedError *nextError;
+ QQmlDelayedError **prevError;
+};
+
+class QQmlJavaScriptExpression
+{
+public:
+ // Although this looks crazy, we implement our own "vtable" here, rather than relying on
+ // C++ virtuals, to save memory. By doing it ourselves, we can overload the storage
+ // location that is use for the vtable to also store the rarely used delayed error.
+ // If we use C++ virtuals, we can't do this and it consts us an extra sizeof(void *) in
+ // memory for every expression.
+ struct VTable {
+ QString (*expressionIdentifier)(QQmlJavaScriptExpression *);
+ void (*expressionChanged)(QQmlJavaScriptExpression *);
+ };
+
+ QQmlJavaScriptExpression(VTable *vtable);
+
+ v8::Local<v8::Value> evaluate(QQmlContextData *, v8::Handle<v8::Function>,
+ bool *isUndefined);
+
+ inline bool requiresThisObject() const;
+ inline void setRequiresThisObject(bool v);
+ inline bool useSharedContext() const;
+ inline void setUseSharedContext(bool v);
+ inline bool notifyOnValueChanged() const;
+
+ void setNotifyOnValueChanged(bool v);
+ void resetNotifyOnValueChanged();
+
+ inline QObject *scopeObject() const;
+ inline void setScopeObject(QObject *v);
+
+ class DeleteWatcher {
+ public:
+ inline DeleteWatcher(QQmlJavaScriptExpression *);
+ inline ~DeleteWatcher();
+ inline bool wasDeleted() const;
+ private:
+ friend class QQmlJavaScriptExpression;
+ QObject *_c;
+ QQmlJavaScriptExpression **_w;
+ QQmlJavaScriptExpression *_s;
+ };
+
+ inline bool hasError() const;
+ inline bool hasDelayedError() const;
+ QQmlError error() const;
+ void clearError();
+ QQmlDelayedError *delayedError();
+
+protected:
+ ~QQmlJavaScriptExpression();
+
+private:
+ typedef QQmlJavaScriptExpressionGuard Guard;
+ friend class QQmlJavaScriptExpressionGuard;
+
+ struct GuardCapture : public QQmlEnginePrivate::PropertyCapture {
+ GuardCapture(QQmlEngine *engine, QQmlJavaScriptExpression *e)
+ : engine(engine), expression(e), errorString(0) { }
+
+ ~GuardCapture() {
+ Q_ASSERT(guards.isEmpty());
+ Q_ASSERT(errorString == 0);
+ }
+
+ virtual void captureProperty(QQmlNotifier *);
+ virtual void captureProperty(QObject *, int, int);
+
+ QQmlEngine *engine;
+ QQmlJavaScriptExpression *expression;
+ QFieldList<Guard, &Guard::next> guards;
+ QStringList *errorString;
+ };
+
+ 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;
+ QForwardFieldList<Guard, &Guard::next> activeGuards;
+
+ void clearGuards();
+};
+
+class QQmlExpression;
+class QString;
+class Q_QML_PRIVATE_EXPORT QQmlExpressionPrivate : public QObjectPrivate, public QQmlJavaScriptExpression, public QQmlAbstractExpression
+{
+ Q_DECLARE_PUBLIC(QQmlExpression)
+public:
+ QQmlExpressionPrivate();
+ ~QQmlExpressionPrivate();
+
+ void init(QQmlContextData *, const QString &, QObject *);
+ void init(QQmlContextData *, v8::Handle<v8::Function>, QObject *);
+ void init(QQmlContextData *, const QString &, bool, QObject *, const QString &, int, int);
+ void init(QQmlContextData *, const QByteArray &, bool, QObject *, const QString &, int, int);
+
+ QVariant value(QObject *secondaryScope = 0, bool *isUndefined = 0);
+
+ v8::Local<v8::Value> v8value(QObject *secondaryScope = 0, bool *isUndefined = 0);
+
+ static inline QQmlExpressionPrivate *get(QQmlExpression *expr);
+ static inline QQmlExpression *get(QQmlExpressionPrivate *expr);
+
+ void _q_notify();
+
+ static void exceptionToError(v8::Handle<v8::Message>, QQmlError &);
+ static v8::Persistent<v8::Function> evalFunction(QQmlContextData *ctxt, QObject *scope,
+ const QString &code, const QString &filename,
+ int line,
+ v8::Persistent<v8::Object> *qmlscope = 0);
+ static v8::Persistent<v8::Function> evalFunction(QQmlContextData *ctxt, QObject *scope,
+ const char *code, int codeLength,
+ const QString &filename, int line,
+ v8::Persistent<v8::Object> *qmlscope = 0);
+
+ static QQmlExpression *create(QQmlContextData *, QObject *, const QString &, bool,
+ const QString &, int, int);
+
+ bool expressionFunctionValid:1;
+ bool expressionFunctionRewritten:1;
+ bool extractExpressionFromFunction:1;
+
+ // "Inherited" from QQmlJavaScriptExpression
+ static QString expressionIdentifier(QQmlJavaScriptExpression *);
+ static void expressionChanged(QQmlJavaScriptExpression *);
+ virtual void expressionChanged();
+
+ QString expression;
+ QByteArray expressionUtf8;
+
+ v8::Persistent<v8::Object> v8qmlscope;
+ v8::Persistent<v8::Function> v8function;
+
+ QString url; // This is a QString for a reason. QUrls are slooooooow...
+ int line;
+ int column;
+ QString name; //function name, hint for the debugger
+
+ QQmlRefCount *dataRef;
+};
+
+QQmlAbstractExpression::DeleteWatcher::DeleteWatcher(QQmlAbstractExpression *e)
+: _c(0), _w(0), _s(e)
+{
+ if (e->m_context.isT1()) {
+ _w = &_s;
+ _c = e->m_context.asT1();
+ e->m_context = this;
+ } else {
+ // Another watcher is already registered
+ _w = &e->m_context.asT2()->_s;
+ }
+}
+
+QQmlAbstractExpression::DeleteWatcher::~DeleteWatcher()
+{
+ Q_ASSERT(*_w == 0 || (*_w == _s && _s->m_context.isT2()));
+ if (*_w && _s->m_context.asT2() == this)
+ _s->m_context = _c;
+}
+
+bool QQmlAbstractExpression::DeleteWatcher::wasDeleted() const
+{
+ return *_w == 0;
+}
+
+QQmlJavaScriptExpression::DeleteWatcher::DeleteWatcher(QQmlJavaScriptExpression *e)
+: _c(0), _w(0), _s(e)
+{
+ if (e->m_scopeObject.isT1()) {
+ _w = &_s;
+ _c = e->m_scopeObject.asT1();
+ e->m_scopeObject = this;
+ } else {
+ // Another watcher is already registered
+ _w = &e->m_scopeObject.asT2()->_s;
+ }
+}
+
+QQmlJavaScriptExpression::DeleteWatcher::~DeleteWatcher()
+{
+ Q_ASSERT(*_w == 0 || (*_w == _s && _s->m_scopeObject.isT2()));
+ if (*_w && _s->m_scopeObject.asT2() == this)
+ _s->m_scopeObject = _c;
+}
+
+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::useSharedContext() const
+{
+ return activeGuards.flag2();
+}
+
+void QQmlJavaScriptExpression::setUseSharedContext(bool v)
+{
+ activeGuards.setFlag2Value(v);
+}
+
+bool QQmlJavaScriptExpression::notifyOnValueChanged() const
+{
+ return activeGuards.flag();
+}
+
+QObject *QQmlJavaScriptExpression::scopeObject() const
+{
+ if (m_scopeObject.isT1()) return m_scopeObject.asT1();
+ else return m_scopeObject.asT2()->_c;
+}
+
+void QQmlJavaScriptExpression::setScopeObject(QObject *v)
+{
+ if (m_scopeObject.isT1()) m_scopeObject = v;
+ else m_scopeObject.asT2()->_c = v;
+}
+
+bool QQmlJavaScriptExpression::hasError() const
+{
+ return m_vtable.hasValue() && m_vtable.constValue()->error.isValid();
+}
+
+bool QQmlJavaScriptExpression::hasDelayedError() const
+{
+ return m_vtable.hasValue();
+}
+
+QQmlExpressionPrivate *QQmlExpressionPrivate::get(QQmlExpression *expr)
+{
+ return static_cast<QQmlExpressionPrivate *>(QObjectPrivate::get(expr));
+}
+
+QQmlExpression *QQmlExpressionPrivate::get(QQmlExpressionPrivate *expr)
+{
+ return expr->q_func();
+}
+
+QQmlJavaScriptExpressionGuard::QQmlJavaScriptExpressionGuard(QQmlJavaScriptExpression *e)
+: expression(e), next(0)
+{
+ callback = &endpointCallback;
+}
+
+void QQmlJavaScriptExpressionGuard::endpointCallback(QQmlNotifierEndpoint *e)
+{
+ QQmlJavaScriptExpression *expression =
+ static_cast<QQmlJavaScriptExpressionGuard *>(e)->expression;
+
+ expression->m_vtable->expressionChanged(expression);
+}
+
+QQmlJavaScriptExpressionGuard *
+QQmlJavaScriptExpressionGuard::New(QQmlJavaScriptExpression *e,
+ QQmlEngine *engine)
+{
+ Q_ASSERT(e);
+ return QQmlEnginePrivate::get(engine)->jsExpressionGuardPool.New(e);
+}
+
+void QQmlJavaScriptExpressionGuard::Delete()
+{
+ QRecyclePool<QQmlJavaScriptExpressionGuard>::Delete(this);
+}
+
+QT_END_NAMESPACE
+
+#endif // QQMLEXPRESSION_P_H
diff --git a/src/qml/qml/qqmlextensioninterface.h b/src/qml/qml/qqmlextensioninterface.h
new file mode 100644
index 0000000000..63ef1adc08
--- /dev/null
+++ b/src/qml/qml/qqmlextensioninterface.h
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLEXTENSIONINTERFACE_H
+#define QQMLEXTENSIONINTERFACE_H
+
+#include <QtQml/qtqmlglobal.h>
+#include <QtCore/qobject.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+
+class QQmlEngine;
+
+class Q_QML_EXPORT QQmlTypesExtensionInterface
+{
+public:
+ virtual ~QQmlTypesExtensionInterface() {}
+ virtual void registerTypes(const char *uri) = 0;
+};
+
+class Q_QML_EXPORT QQmlExtensionInterface : public QQmlTypesExtensionInterface
+{
+public:
+ virtual ~QQmlExtensionInterface() {}
+ virtual void initializeEngine(QQmlEngine *engine, const char *uri) = 0;
+};
+
+Q_DECLARE_INTERFACE(QQmlTypesExtensionInterface, "org.qt-project.Qt.QQmlTypesExtensionInterface/1.0")
+Q_DECLARE_INTERFACE(QQmlExtensionInterface, "org.qt-project.Qt.QQmlExtensionInterface/1.0")
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QQMLEXTENSIONINTERFACE_H
diff --git a/src/qml/qml/qqmlextensionplugin.cpp b/src/qml/qml/qqmlextensionplugin.cpp
new file mode 100644
index 0000000000..c3d8f0b34f
--- /dev/null
+++ b/src/qml/qml/qqmlextensionplugin.cpp
@@ -0,0 +1,171 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qqmlextensionplugin.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \since 4.7
+ \class QQmlExtensionPlugin
+ \brief The QQmlExtensionPlugin class provides an abstract base for custom QML extension plugins.
+
+ \ingroup plugins
+
+ QQmlExtensionPlugin is a plugin interface that makes it possible to
+ create QML extensions that can be loaded dynamically into QML applications.
+ These extensions allow custom QML types to be made available to the QML engine.
+
+ To write a QML extension plugin:
+
+ \list
+ \o Subclass QQmlExtensionPlugin, implement registerTypes() method
+ to register types using qmlRegisterType(), and export the class using the Q_EXPORT_PLUGIN2() macro
+ \o Write an appropriate project file for the plugin
+ \o Create a \l{Writing a qmldir file}{qmldir file} to describe the plugin
+ \endlist
+
+ QML extension plugins can be used to provide either application-specific or
+ library-like plugins. Library plugins should limit themselves to registering types,
+ as any manipulation of the engine's root context may cause conflicts
+ or other issues in the library user's code.
+
+
+ \section1 An example
+
+ Suppose there is a new \c TimeModel C++ class that should be made available
+ as a new QML element. It provides the current time through \c hour and \c minute
+ properties, like this:
+
+ \snippet examples/declarative/cppextensions/plugins/plugin.cpp 0
+ \dots
+
+ To make this class available as a QML type, create a plugin that registers
+ this type with a specific \l {QML Modules}{module} using qmlRegisterType(). For this example the plugin
+ module will be named \c com.nokia.TimeExample (as defined in the project
+ file further below).
+
+ \snippet examples/declarative/cppextensions/plugins/plugin.cpp plugin
+ \codeline
+ \snippet examples/declarative/cppextensions/plugins/plugin.cpp export
+
+ This registers the \c TimeModel class with the 1.0 version of this
+ plugin library, as a QML type called \c Time. The Q_ASSERT statement
+ ensures the module is imported correctly by any QML components that use this plugin.
+
+ The project file defines the project as a plugin library and specifies
+ it should be built into the \c com/nokia/TimeExample directory:
+
+ \code
+ TEMPLATE = lib
+ CONFIG += qt plugin
+ QT += declarative
+
+ DESTDIR = com/nokia/TimeExample
+ TARGET = qmlqtimeexampleplugin
+ ...
+ \endcode
+
+ Finally, a \l{Writing a qmldir file}{qmldir file} is required in the \c com/nokia/TimeExample directory
+ that describes the plugin. This directory includes a \c Clock.qml file that
+ should be bundled with the plugin, so it needs to be specified in the \c qmldir
+ file:
+
+ \quotefile examples/declarative/cppextensions/plugins/com/nokia/TimeExample/qmldir
+
+ Once the project is built and installed, the new \c Time element can be
+ used by any QML component that imports the \c com.nokia.TimeExample module:
+
+ \snippet examples/declarative/cppextensions/plugins/plugins.qml 0
+
+ The full source code is available in the \l {declarative/cppextensions/plugins}{plugins example}.
+
+ The \l {Tutorial: Writing QML extensions with C++} also contains a chapter
+ on creating QML plugins.
+
+ \sa QQmlEngine::importPlugin(), {How to Create Qt Plugins}
+*/
+
+/*!
+ \fn void QQmlExtensionPlugin::registerTypes(const char *uri)
+
+ Registers the QML types in the given \a uri. Subclasses should implement
+ this to call qmlRegisterType() for all types which are provided by the extension
+ plugin.
+
+ The \a uri is an identifier for the plugin generated by the QML engine
+ based on the name and path of the extension's plugin library.
+*/
+
+/*!
+ Constructs a QML extension plugin with the given \a parent.
+
+ Note that this constructor is invoked automatically by the
+ Q_EXPORT_PLUGIN2() macro, so there is no need for calling it
+ explicitly.
+*/
+QQmlExtensionPlugin::QQmlExtensionPlugin(QObject *parent)
+ : QObject(parent)
+{
+}
+
+/*!
+ \internal
+ */
+QQmlExtensionPlugin::~QQmlExtensionPlugin()
+{
+}
+
+/*!
+ \fn void QQmlExtensionPlugin::initializeEngine(QQmlEngine *engine, const char *uri)
+
+ Initializes the extension from the \a uri using the \a engine. Here an application
+ plugin might, for example, expose some data or objects to QML,
+ as context properties on the engine's root context.
+*/
+
+void QQmlExtensionPlugin::initializeEngine(QQmlEngine *engine, const char *uri)
+{
+ Q_UNUSED(engine);
+ Q_UNUSED(uri);
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlextensionplugin.h b/src/qml/qml/qqmlextensionplugin.h
new file mode 100644
index 0000000000..91a9e95869
--- /dev/null
+++ b/src/qml/qml/qqmlextensionplugin.h
@@ -0,0 +1,77 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLEXTENSIONPLUGIN_H
+#define QQMLEXTENSIONPLUGIN_H
+
+#include <QtCore/qplugin.h>
+
+#include <QtQml/qqmlextensioninterface.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+
+class QQmlEngine;
+
+class Q_QML_EXPORT QQmlExtensionPlugin : public QObject,
+ public QQmlExtensionInterface
+{
+ Q_OBJECT
+ Q_INTERFACES(QQmlExtensionInterface)
+ Q_INTERFACES(QQmlTypesExtensionInterface)
+public:
+ explicit QQmlExtensionPlugin(QObject *parent = 0);
+ ~QQmlExtensionPlugin();
+
+ virtual void registerTypes(const char *uri) = 0;
+ virtual void initializeEngine(QQmlEngine *engine, const char *uri);
+
+private:
+ Q_DISABLE_COPY(QQmlExtensionPlugin)
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QQMLEXTENSIONPLUGIN_H
diff --git a/src/qml/qml/qqmlglobal_p.h b/src/qml/qml/qqmlglobal_p.h
new file mode 100644
index 0000000000..c41b823e60
--- /dev/null
+++ b/src/qml/qml/qqmlglobal_p.h
@@ -0,0 +1,129 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLGLOBAL_H
+#define QQMLGLOBAL_H
+
+#include <QtCore/qglobal.h>
+#include <QtCore/QObject>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+
+#define DEFINE_BOOL_CONFIG_OPTION(name, var) \
+ static bool name() \
+ { \
+ static enum { Yes, No, Unknown } status = Unknown; \
+ if (status == Unknown) { \
+ QByteArray v = qgetenv(#var); \
+ bool value = !v.isEmpty() && v != "0" && v != "false"; \
+ if (value) status = Yes; \
+ else status = No; \
+ } \
+ return status == Yes; \
+ }
+
+#define FAST_CONNECT(Sender, Signal, Receiver, Method) \
+{ \
+ QObject *sender = (Sender); \
+ QObject *receiver = (Receiver); \
+ const char *signal = (Signal); \
+ const char *method = (Method); \
+ static int signalIdx = -1; \
+ static int methodIdx = -1; \
+ if (signalIdx < 0) { \
+ if (((int)(*signal) - '0') == QSIGNAL_CODE) \
+ signalIdx = sender->metaObject()->indexOfSignal(signal+1); \
+ else \
+ qWarning("FAST_CONNECT: Invalid signal %s. Please make sure you are using the SIGNAL macro.", signal); \
+ } \
+ if (methodIdx < 0) { \
+ int code = ((int)(*method) - '0'); \
+ if (code == QSLOT_CODE) \
+ methodIdx = receiver->metaObject()->indexOfSlot(method+1); \
+ else if (code == QSIGNAL_CODE) \
+ methodIdx = receiver->metaObject()->indexOfSignal(method+1); \
+ else \
+ qWarning("FAST_CONNECT: Invalid method %s. Please make sure you are using the SIGNAL or SLOT macro.", method); \
+ } \
+ QMetaObject::connect(sender, signalIdx, receiver, methodIdx, Qt::DirectConnection); \
+}
+
+struct QQmlGraphics_DerivedObject : public QObject
+{
+ void setParent_noEvent(QObject *parent) {
+ bool sce = d_ptr->sendChildEvents;
+ d_ptr->sendChildEvents = false;
+ setParent(parent);
+ d_ptr->sendChildEvents = sce;
+ }
+};
+
+/*!
+ Returns true if the case of \a fileName is equivalent to the file case of
+ \a fileName on disk, and false otherwise.
+
+ This is used to ensure that the behavior of QML on a case-insensitive file
+ system is the same as on a case-sensitive file system. This function
+ performs a "best effort" attempt to determine the real case of the file.
+ It may have false positives (say the case is correct when it isn't), but it
+ should never have a false negative (say the case is incorrect when it is
+ correct).
+*/
+bool QQml_isFileCaseCorrect(const QString &fileName);
+
+/*!
+ Makes the \a object a child of \a parent. Note that when using this method,
+ neither \a parent nor the object's previous parent (if it had one) will
+ receive ChildRemoved or ChildAdded events.
+*/
+inline void QQml_setParent_noEvent(QObject *object, QObject *parent)
+{
+ static_cast<QQmlGraphics_DerivedObject *>(object)->setParent_noEvent(parent);
+}
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QQMLGLOBAL_H
diff --git a/src/qml/qml/qqmlguard_p.h b/src/qml/qml/qqmlguard_p.h
new file mode 100644
index 0000000000..b4e7408fae
--- /dev/null
+++ b/src/qml/qml/qqmlguard_p.h
@@ -0,0 +1,218 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLGUARD_P_H
+#define QQMLGUARD_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of qapplication_*.cpp, qwidget*.cpp and qfiledialog.cpp. This header
+// file may change from version to version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qglobal.h>
+#include <QtCore/qvariant.h>
+#include <private/qqmldata_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQmlGuardImpl
+{
+public:
+ inline QQmlGuardImpl();
+ inline QQmlGuardImpl(QObject *);
+ inline QQmlGuardImpl(const QQmlGuardImpl &);
+ inline ~QQmlGuardImpl();
+
+ QObject *o;
+ QQmlGuardImpl *next;
+ QQmlGuardImpl **prev;
+
+ inline void addGuard();
+ inline void remGuard();
+};
+
+class QObject;
+template<class T>
+class QQmlGuard : private QQmlGuardImpl
+{
+ friend class QQmlData;
+public:
+ inline QQmlGuard();
+ inline QQmlGuard(T *);
+ inline QQmlGuard(const QQmlGuard<T> &);
+ inline virtual ~QQmlGuard();
+
+ inline QQmlGuard<T> &operator=(const QQmlGuard<T> &o);
+ inline QQmlGuard<T> &operator=(T *);
+
+ inline T *object() const;
+ inline void setObject(T *g);
+
+ inline bool isNull() const
+ { return !o; }
+
+ inline T* operator->() const
+ { return static_cast<T*>(const_cast<QObject*>(o)); }
+ inline T& operator*() const
+ { return *static_cast<T*>(const_cast<QObject*>(o)); }
+ inline operator T*() const
+ { return static_cast<T*>(const_cast<QObject*>(o)); }
+ inline T* data() const
+ { return static_cast<T*>(const_cast<QObject*>(o)); }
+
+protected:
+ virtual void objectDestroyed(T *) {}
+};
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(QQmlGuard<QObject>)
+
+QT_BEGIN_NAMESPACE
+
+QQmlGuardImpl::QQmlGuardImpl()
+: o(0), next(0), prev(0)
+{
+}
+
+QQmlGuardImpl::QQmlGuardImpl(QObject *g)
+: o(g), next(0), prev(0)
+{
+ if (o) addGuard();
+}
+
+QQmlGuardImpl::QQmlGuardImpl(const QQmlGuardImpl &g)
+: o(g.o), next(0), prev(0)
+{
+ if (o) addGuard();
+}
+
+QQmlGuardImpl::~QQmlGuardImpl()
+{
+ if (prev) remGuard();
+ o = 0;
+}
+
+void QQmlGuardImpl::addGuard()
+{
+ Q_ASSERT(!prev);
+
+ if (QObjectPrivate::get(o)->wasDeleted)
+ return;
+
+ QQmlData *data = QQmlData::get(o, true);
+ next = data->guards;
+ if (next) next->prev = &next;
+ data->guards = this;
+ prev = &data->guards;
+}
+
+void QQmlGuardImpl::remGuard()
+{
+ Q_ASSERT(prev);
+
+ if (next) next->prev = prev;
+ *prev = next;
+ next = 0;
+ prev = 0;
+}
+
+template<class T>
+QQmlGuard<T>::QQmlGuard()
+{
+}
+
+template<class T>
+QQmlGuard<T>::QQmlGuard(T *g)
+: QQmlGuardImpl(g)
+{
+}
+
+template<class T>
+QQmlGuard<T>::QQmlGuard(const QQmlGuard<T> &g)
+: QQmlGuardImpl(g)
+{
+}
+
+template<class T>
+QQmlGuard<T>::~QQmlGuard()
+{
+}
+
+template<class T>
+QQmlGuard<T> &QQmlGuard<T>::operator=(const QQmlGuard<T> &g)
+{
+ setObject(g.object());
+ return *this;
+}
+
+template<class T>
+QQmlGuard<T> &QQmlGuard<T>::operator=(T *g)
+{
+ setObject(g);
+ return *this;
+}
+
+template<class T>
+T *QQmlGuard<T>::object() const
+{
+ return static_cast<T *>(o);
+};
+
+template<class T>
+void QQmlGuard<T>::setObject(T *g)
+{
+ if (g != o) {
+ if (prev) remGuard();
+ o = g;
+ if (o) addGuard();
+ }
+}
+
+QT_END_NAMESPACE
+
+#endif // QQMLGUARD_P_H
diff --git a/src/qml/qml/qqmlimageprovider.cpp b/src/qml/qml/qqmlimageprovider.cpp
new file mode 100644
index 0000000000..863093033a
--- /dev/null
+++ b/src/qml/qml/qqmlimageprovider.cpp
@@ -0,0 +1,334 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qqmlimageprovider.h"
+
+QT_BEGIN_NAMESPACE
+
+class QQmlImageProviderPrivate
+{
+public:
+ QQmlImageProvider::ImageType type;
+};
+
+/*!
+ \class QQuickTextureFactory
+ \since 5.0
+ \brief The QQuickTextureFactory class provides an interface for loading custom textures from QML.
+
+ The purpose of the texture factory is to provide a placeholder for a image
+ data that can be converted into an OpenGL texture.
+
+ Creating a texture directly is not possible as there is rarely an OpenGL context
+ available in the thread that is responsible for loading the image data.
+ */
+
+QQuickTextureFactory::QQuickTextureFactory()
+{
+}
+
+QQuickTextureFactory::~QQuickTextureFactory()
+{
+}
+
+
+
+/*!
+ \fn QSGTexture *QQuickTextureFactory::createTexture() const
+
+ This function is called on the scene graph rendering thread to create a QSGTexture
+ instance from the factory.
+
+ QML will internally cache the returned texture as needed. Each call to this
+ function should return a unique instance.
+
+ The OpenGL context used for rendering is bound when this function is called.
+ */
+
+/*!
+ \fn QSize QQuickTextureFactory::textureSize() const
+
+ Returns the size of the texture. This function will be called from arbitrary threads
+ and should not rely on an OpenGL context bound.
+ */
+
+
+/*!
+ \class QQmlImageProvider
+ \since 4.7
+ \brief The QQmlImageProvider class provides an interface for supporting pixmaps and threaded image requests in QML.
+
+ QQmlImageProvider is used to provide advanced image loading features
+ in QML applications. It allows images in QML to be:
+
+ \list
+ \o Loaded using QPixmaps rather than actual image files
+ \o Loaded asynchronously in a separate thread, if imageType() is \l{QQmlImageProvider::ImageType}{ImageType::Image}
+ \endlist
+
+ To specify that an image should be loaded by an image provider, use the
+ \bold {"image:"} scheme for the URL source of the image, followed by the
+ identifiers of the image provider and the requested image. For example:
+
+ \qml
+ Image { source: "image://myimageprovider/image.png" }
+ \endqml
+
+ This specifies that the image should be loaded by the image provider named
+ "myimageprovider", and the image to be loaded is named "image.png". The QML engine
+ invokes the appropriate image provider according to the providers that have
+ been registered through QQmlEngine::addImageProvider().
+
+ Note that the identifiers are case-insensitive, but the rest of the URL will be passed on with
+ preserved case. For example, the below snippet would still specify that the image is loaded by the
+ image provider named "myimageprovider", but it would request a different image than the above snippet
+ ("Image.png" instead of "image.png").
+ \qml
+ Image { source: "image://MyImageProvider/Image.png" }
+ \endqml
+
+ If you want the rest of the URL to be case insensitive, you will have to take care
+ of that yourself inside your image provider.
+
+ \section2 An example
+
+ Here are two images. Their \c source values indicate they should be loaded by
+ an image provider named "colors", and the images to be loaded are "yellow"
+ and "red", respectively:
+
+ \snippet examples/declarative/cppextensions/imageprovider/imageprovider-example.qml 0
+
+ When these images are loaded by QML, it looks for a matching image provider
+ and calls its requestImage() or requestPixmap() method (depending on its
+ imageType()) to load the image. The method is called with the \c id
+ parameter set to "yellow" for the first image, and "red" for the second.
+
+ Here is an image provider implementation that can load the images
+ requested by the above QML. This implementation dynamically
+ generates QPixmap images that are filled with the requested color:
+
+ \snippet examples/declarative/cppextensions/imageprovider/imageprovider.cpp 0
+ \codeline
+ \snippet examples/declarative/cppextensions/imageprovider/imageprovider.cpp 1
+
+ To make this provider accessible to QML, it is registered with the QML engine
+ with a "colors" identifier:
+
+ \code
+ int main(int argc, char *argv[])
+ {
+ ...
+
+ QQmlEngine engine;
+ engine->addImageProvider(QLatin1String("colors"), new ColorPixmapProvider);
+
+ ...
+ }
+ \endcode
+
+ Now the images can be successfully loaded in QML:
+
+ \image imageprovider.png
+
+ A complete example is available in Qt's
+ \l {declarative/cppextensions/imageprovider}{examples/declarative/cppextensions/imageprovider}
+ directory. Note the example registers the provider via a \l{QQmlExtensionPlugin}{plugin}
+ instead of registering it in the application \c main() function as shown above.
+
+
+ \section2 Asynchronous image loading
+
+ Image providers that support QImage loading automatically include support
+ for asychronous loading of images. To enable asynchronous loading for an
+ image source, set the \c asynchronous property to \c true for the relevant
+ \l Image, \l BorderImage or \l AnimatedImage object. When this is enabled,
+ the image request to the provider is run in a low priority thread,
+ allowing image loading to be executed in the background, and reducing the
+ performance impact on the user interface.
+
+ Asynchronous loading is not supported for image providers that provide
+ QPixmap rather than QImage values, as pixmaps can only be created in the
+ main thread. In this case, if \l {Image::}{asynchronous} is set to
+ \c true, the value is ignored and the image is loaded
+ synchronously.
+
+
+ \section2 Image caching
+
+ Images returned by a QQmlImageProvider are automatically cached,
+ similar to any image loaded by the QML engine. When an image with a
+ "image://" prefix is loaded from cache, requestImage() and requestPixmap()
+ will not be called for the relevant image provider. If an image should always
+ be fetched from the image provider, and should not be cached at all, set the
+ \c cache property to \c false for the relevant \l Image, \l BorderImage or
+ \l AnimatedImage object.
+
+ \sa QQmlEngine::addImageProvider()
+*/
+
+/*!
+ \enum QQmlImageProvider::ImageType
+
+ Defines the type of image supported by this image provider.
+
+ \value Image The Image Provider provides QImage images. The
+ requestImage() method will be called for all image requests.
+ \value Pixmap The Image Provider provides QPixmap images. The
+ requestPixmap() method will be called for all image requests.
+ \value Texture The Image Provider provides QSGTextureProvider based images.
+ The requestTexture() method will be called for all image requests. \omitvalue
+*/
+
+/*!
+ Creates an image provider that will provide images of the given \a type.
+*/
+QQmlImageProvider::QQmlImageProvider(ImageType type)
+ : d(new QQmlImageProviderPrivate)
+{
+ d->type = type;
+}
+
+/*!
+ Destroys the QQmlImageProvider
+
+ \note The destructor of your derived class need to be thread safe.
+*/
+QQmlImageProvider::~QQmlImageProvider()
+{
+ delete d;
+}
+
+/*!
+ Returns the image type supported by this provider.
+*/
+QQmlImageProvider::ImageType QQmlImageProvider::imageType() const
+{
+ return d->type;
+}
+
+/*!
+ Implement this method to return the image with \a id. The default
+ implementation returns an empty image.
+
+ The \a id is the requested image source, with the "image:" scheme and
+ provider identifier removed. For example, if the image \l{Image::}{source}
+ was "image://myprovider/icons/home", the given \a id would be "icons/home".
+
+ The \a requestedSize corresponds to the \l {Image::sourceSize} requested by
+ an Image element. If \a requestedSize is a valid size, the image
+ returned should be of that size.
+
+ In all cases, \a size must be set to the original size of the image. This
+ is used to set the \l {Item::}{width} and \l {Item::}{height} of the
+ relevant \l Image if these values have not been set explicitly.
+
+ \note this method may be called by multiple threads, so ensure the
+ implementation of this method is reentrant.
+*/
+QImage QQmlImageProvider::requestImage(const QString &id, QSize *size, const QSize& requestedSize)
+{
+ Q_UNUSED(id);
+ Q_UNUSED(size);
+ Q_UNUSED(requestedSize);
+ if (d->type == Image)
+ qWarning("ImageProvider supports Image type but has not implemented requestImage()");
+ return QImage();
+}
+
+/*!
+ Implement this method to return the pixmap with \a id. The default
+ implementation returns an empty pixmap.
+
+ The \a id is the requested image source, with the "image:" scheme and
+ provider identifier removed. For example, if the image \l{Image::}{source}
+ was "image://myprovider/icons/home", the given \a id would be "icons/home".
+
+ The \a requestedSize corresponds to the \l {Image::sourceSize} requested by
+ an Image element. If \a requestedSize is a valid size, the image
+ returned should be of that size.
+
+ In all cases, \a size must be set to the original size of the image. This
+ is used to set the \l {Item::}{width} and \l {Item::}{height} of the
+ relevant \l Image if these values have not been set explicitly.
+*/
+QPixmap QQmlImageProvider::requestPixmap(const QString &id, QSize *size, const QSize& requestedSize)
+{
+ Q_UNUSED(id);
+ Q_UNUSED(size);
+ Q_UNUSED(requestedSize);
+ if (d->type == Pixmap)
+ qWarning("ImageProvider supports Pixmap type but has not implemented requestPixmap()");
+ return QPixmap();
+}
+
+
+/*!
+ Implement this method to return the texture with \a id. The default
+ implementation returns 0.
+
+ The \a id is the requested image source, with the "image:" scheme and
+ provider identifier removed. For example, if the image \l{Image::}{source}
+ was "image://myprovider/icons/home", the given \a id would be "icons/home".
+
+ The \a requestedSize corresponds to the \l {Image::sourceSize} requested by
+ an Image element. If \a requestedSize is a valid size, the image
+ returned should be of that size.
+
+ In all cases, \a size must be set to the original size of the image. This
+ is used to set the \l {Item::}{width} and \l {Item::}{height} of the
+ relevant \l Image if these values have not been set explicitly.
+
+ \note this method may be called by multiple threads, so ensure the
+ implementation of this method is reentrant.
+*/
+
+QQuickTextureFactory *QQmlImageProvider::requestTexture(const QString &id, QSize *size, const QSize &requestedSize)
+{
+ Q_UNUSED(id);
+ Q_UNUSED(size);
+ Q_UNUSED(requestedSize);
+ if (d->type == Texture)
+ qWarning("ImageProvider supports Texture type but has not implemented requestTexture()");
+ return 0;
+}
+
+QT_END_NAMESPACE
+
diff --git a/src/qml/qml/qqmlimageprovider.h b/src/qml/qml/qqmlimageprovider.h
new file mode 100644
index 0000000000..d59cfc42ca
--- /dev/null
+++ b/src/qml/qml/qqmlimageprovider.h
@@ -0,0 +1,96 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLIMAGEPROVIDER_H
+#define QQMLIMAGEPROVIDER_H
+
+#include <QtQml/qtqmlglobal.h>
+#include <QtGui/qimage.h>
+#include <QtGui/qpixmap.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+
+class QQmlImageProviderPrivate;
+class QSGTexture;
+class QQuickCanvas;
+
+class Q_QML_EXPORT QQuickTextureFactory : public QObject
+{
+public:
+ QQuickTextureFactory();
+ ~QQuickTextureFactory();
+
+ virtual QSGTexture *createTexture(QQuickCanvas *canvas) const = 0;
+ virtual QSize textureSize() const = 0;
+ virtual int textureByteCount() const = 0;
+};
+
+class Q_QML_EXPORT QQmlImageProvider
+{
+public:
+ enum ImageType {
+ Image,
+ Pixmap,
+ Texture,
+ Invalid
+ };
+
+ QQmlImageProvider(ImageType type);
+ virtual ~QQmlImageProvider();
+
+ ImageType imageType() const;
+
+ virtual QImage requestImage(const QString &id, QSize *size, const QSize& requestedSize);
+ virtual QPixmap requestPixmap(const QString &id, QSize *size, const QSize& requestedSize);
+ virtual QQuickTextureFactory *requestTexture(const QString &id, QSize *size, const QSize &requestedSize);
+
+private:
+ QQmlImageProviderPrivate *d;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QQMLIMAGEPROVIDER
diff --git a/src/qml/qml/qqmlimport.cpp b/src/qml/qml/qqmlimport.cpp
new file mode 100644
index 0000000000..6e74536fa3
--- /dev/null
+++ b/src/qml/qml/qqmlimport.cpp
@@ -0,0 +1,1183 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qqmlimport_p.h"
+
+#include <QtCore/qdebug.h>
+#include <QtCore/qdir.h>
+#include <QtCore/qfileinfo.h>
+#include <QtCore/qpluginloader.h>
+#include <QtCore/qlibraryinfo.h>
+#include <QtQml/qqmlextensioninterface.h>
+#include <private/qqmlglobal_p.h>
+#include <private/qqmltypenamecache_p.h>
+#include <private/qqmlengine_p.h>
+
+QT_BEGIN_NAMESPACE
+
+DEFINE_BOOL_CONFIG_OPTION(qmlImportTrace, QML_IMPORT_TRACE)
+DEFINE_BOOL_CONFIG_OPTION(qmlCheckTypes, QML_CHECK_TYPES)
+
+static bool greaterThan(const QString &s1, const QString &s2)
+{
+ return s1 > s2;
+}
+
+QString resolveLocalUrl(const QString &url, const QString &relative)
+{
+ if (relative.contains(QLatin1Char(':'))) {
+ // contains a host name
+ return QUrl(url).resolved(QUrl(relative)).toString();
+ } else if (relative.isEmpty()) {
+ return url;
+ } else if (relative.at(0) == QLatin1Char('/') || !url.contains(QLatin1Char('/'))) {
+ return relative;
+ } else {
+ if (relative == QLatin1String("."))
+ return url.left(url.lastIndexOf(QLatin1Char('/')) + 1);
+ else if (relative.startsWith(QLatin1String("./")))
+ return url.left(url.lastIndexOf(QLatin1Char('/')) + 1) + relative.mid(2);
+ return url.left(url.lastIndexOf(QLatin1Char('/')) + 1) + relative;
+ }
+}
+
+
+
+typedef QMap<QString, QString> StringStringMap;
+Q_GLOBAL_STATIC(StringStringMap, qmlEnginePluginsWithRegisteredTypes); // stores the uri
+
+class QQmlImportedNamespace
+{
+public:
+ struct Data {
+ QString uri;
+ QString url;
+ int majversion;
+ int minversion;
+ bool isLibrary;
+ QQmlDirComponents qmlDirComponents;
+ QQmlDirScripts qmlDirScripts;
+ };
+ QList<Data> imports;
+
+
+ bool find_helper(QQmlTypeLoader *typeLoader, const Data &data, const QString& type, int *vmajor, int *vminor,
+ QQmlType** type_return, QString* url_return,
+ QString *base = 0, bool *typeRecursionDetected = 0);
+ bool find(QQmlTypeLoader *typeLoader, const QString& type, int *vmajor, int *vminor, QQmlType** type_return,
+ QString* url_return, QString *base = 0, QList<QQmlError> *errors = 0);
+};
+
+class QQmlImportsPrivate {
+public:
+ QQmlImportsPrivate(QQmlTypeLoader *loader);
+ ~QQmlImportsPrivate();
+
+ bool importExtension(const QString &absoluteFilePath, const QString &uri,
+ QQmlImportDatabase *database, QQmlDirComponents* components,
+ QQmlDirScripts *scripts,
+ QList<QQmlError> *errors);
+
+ QString resolvedUri(const QString &dir_arg, QQmlImportDatabase *database);
+ bool add(const QQmlDirComponents &qmldircomponentsnetwork,
+ const QString& uri_arg, const QString& prefix,
+ int vmaj, int vmin, QQmlScript::Import::Type importType,
+ QQmlImportDatabase *database, QList<QQmlError> *errors);
+ bool find(const QString& type, int *vmajor, int *vminor,
+ QQmlType** type_return, QString* url_return, QList<QQmlError> *errors);
+
+ QQmlImportedNamespace *findNamespace(const QString& type);
+
+ QUrl baseUrl;
+ QString base;
+ int ref;
+
+ QSet<QString> qmlDirFilesForWhichPluginsHaveBeenLoaded;
+ QQmlImportedNamespace unqualifiedset;
+ QHash<QString,QQmlImportedNamespace* > set;
+ QQmlTypeLoader *typeLoader;
+};
+
+/*!
+\class QQmlImports
+\brief The QQmlImports class encapsulates one QML document's import statements.
+\internal
+*/
+QQmlImports::QQmlImports(const QQmlImports &copy)
+: d(copy.d)
+{
+ ++d->ref;
+}
+
+QQmlImports &
+QQmlImports::operator =(const QQmlImports &copy)
+{
+ ++copy.d->ref;
+ if (--d->ref == 0)
+ delete d;
+ d = copy.d;
+ return *this;
+}
+
+QQmlImports::QQmlImports(QQmlTypeLoader *typeLoader)
+ : d(new QQmlImportsPrivate(typeLoader))
+{
+}
+
+QQmlImports::~QQmlImports()
+{
+ if (--d->ref == 0)
+ delete d;
+}
+
+/*!
+ Sets the base URL to be used for all relative file imports added.
+*/
+void QQmlImports::setBaseUrl(const QUrl& url, const QString &urlString)
+{
+ d->baseUrl = url;
+
+ if (urlString.isEmpty()) {
+ d->base = url.toString();
+ } else {
+ //Q_ASSERT(url.toString() == urlString);
+ d->base = urlString;
+ }
+}
+
+/*!
+ Returns the base URL to be used for all relative file imports added.
+*/
+QUrl QQmlImports::baseUrl() const
+{
+ return d->baseUrl;
+}
+
+void QQmlImports::populateCache(QQmlTypeNameCache *cache, QQmlEngine *engine) const
+{
+ const QQmlImportedNamespace &set = d->unqualifiedset;
+
+ for (int ii = set.imports.count() - 1; ii >= 0; --ii) {
+ const QQmlImportedNamespace::Data &data = set.imports.at(ii);
+ QQmlTypeModule *module = QQmlMetaType::typeModule(data.uri, data.majversion);
+ if (module)
+ cache->m_anonymousImports.append(QQmlTypeModuleVersion(module, data.minversion));
+ }
+
+ for (QHash<QString,QQmlImportedNamespace* >::ConstIterator iter = d->set.begin();
+ iter != d->set.end();
+ ++iter) {
+
+ const QQmlImportedNamespace &set = *iter.value();
+ for (int ii = set.imports.count() - 1; ii >= 0; --ii) {
+ const QQmlImportedNamespace::Data &data = set.imports.at(ii);
+ QQmlTypeModule *module = QQmlMetaType::typeModule(data.uri, data.majversion);
+ if (module) {
+ QQmlTypeNameCache::Import &import = cache->m_namedImports[iter.key()];
+ import.modules.append(QQmlTypeModuleVersion(module, data.minversion));
+ }
+
+ QQmlMetaType::ModuleApi moduleApi = QQmlMetaType::moduleApi(data.uri, data.majversion, data.minversion);
+ if (moduleApi.script || moduleApi.qobject) {
+ QQmlTypeNameCache::Import &import = cache->m_namedImports[iter.key()];
+ QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine);
+ import.moduleApi = ep->moduleApiInstance(moduleApi);
+ }
+ }
+ }
+}
+
+QList<QQmlImports::ScriptReference> QQmlImports::resolvedScripts() const
+{
+ QList<QQmlImports::ScriptReference> scripts;
+
+ const QQmlImportedNamespace &set = d->unqualifiedset;
+
+ for (int ii = set.imports.count() - 1; ii >= 0; --ii) {
+ const QQmlImportedNamespace::Data &data = set.imports.at(ii);
+
+ foreach (const QQmlDirParser::Script &script, data.qmlDirScripts) {
+ ScriptReference ref;
+ ref.nameSpace = script.nameSpace;
+ ref.location = QUrl(data.url).resolved(QUrl(script.fileName));
+ scripts.append(ref);
+ }
+ }
+
+ for (QHash<QString,QQmlImportedNamespace* >::ConstIterator iter = d->set.constBegin();
+ iter != d->set.constEnd();
+ ++iter) {
+ const QQmlImportedNamespace &set = *iter.value();
+
+ for (int ii = set.imports.count() - 1; ii >= 0; --ii) {
+ const QQmlImportedNamespace::Data &data = set.imports.at(ii);
+
+ foreach (const QQmlDirParser::Script &script, data.qmlDirScripts) {
+ ScriptReference ref;
+ ref.nameSpace = script.nameSpace;
+ ref.qualifier = iter.key();
+ ref.location = QUrl(data.url).resolved(QUrl(script.fileName));
+ scripts.append(ref);
+ }
+ }
+ }
+
+ return scripts;
+}
+
+/*!
+ \internal
+
+ The given (namespace qualified) \a type is resolved to either
+ \list
+ \o a QQmlImportedNamespace stored at \a ns_return,
+ \o a QQmlType stored at \a type_return, or
+ \o a component located at \a url_return.
+ \endlist
+
+ If any return pointer is 0, the corresponding search is not done.
+
+ \sa addImport()
+*/
+bool QQmlImports::resolveType(const QString& type,
+ QQmlType** type_return, QString* url_return, int *vmaj, int *vmin,
+ QQmlImportedNamespace** ns_return, QList<QQmlError> *errors) const
+{
+ QQmlImportedNamespace* ns = d->findNamespace(type);
+ if (ns) {
+ if (ns_return)
+ *ns_return = ns;
+ return true;
+ }
+ if (type_return || url_return) {
+ if (d->find(type,vmaj,vmin,type_return,url_return, errors)) {
+ if (qmlImportTrace()) {
+ if (type_return && *type_return && url_return && !url_return->isEmpty())
+ qDebug().nospace() << "QQmlImports(" << qPrintable(baseUrl().toString()) << ")" << "::resolveType: "
+ << type << " => " << (*type_return)->typeName() << " " << *url_return;
+ if (type_return && *type_return)
+ qDebug().nospace() << "QQmlImports(" << qPrintable(baseUrl().toString()) << ")" << "::resolveType: "
+ << type << " => " << (*type_return)->typeName();
+ if (url_return && !url_return->isEmpty())
+ qDebug().nospace() << "QQmlImports(" << qPrintable(baseUrl().toString()) << ")" << "::resolveType: "
+ << type << " => " << *url_return;
+ }
+ return true;
+ }
+ }
+ return false;
+}
+
+/*!
+ \internal
+
+ Searching \e only in the namespace \a ns (previously returned in a call to
+ resolveType(), \a type is found and returned to either
+ a QQmlType stored at \a type_return, or
+ a component located at \a url_return.
+
+ If either return pointer is 0, the corresponding search is not done.
+*/
+bool QQmlImports::resolveType(QQmlImportedNamespace* ns, const QString& type,
+ QQmlType** type_return, QString* url_return,
+ int *vmaj, int *vmin) const
+{
+ return ns->find(d->typeLoader,type,vmaj,vmin,type_return,url_return);
+}
+
+bool QQmlImportedNamespace::find_helper(QQmlTypeLoader *typeLoader, const Data &data, const QString& type, int *vmajor, int *vminor,
+ QQmlType** type_return, QString* url_return,
+ QString *base, bool *typeRecursionDetected)
+{
+ int vmaj = data.majversion;
+ int vmin = data.minversion;
+
+ if (vmaj >= 0 && vmin >= 0) {
+ QString qt = data.uri + QLatin1Char('/') + type;
+ QQmlType *t = QQmlMetaType::qmlType(qt,vmaj,vmin);
+ if (t) {
+ if (vmajor) *vmajor = vmaj;
+ if (vminor) *vminor = vmin;
+ if (type_return)
+ *type_return = t;
+ return true;
+ }
+ }
+
+ const QQmlDirComponents &qmldircomponents = data.qmlDirComponents;
+ bool typeWasDeclaredInQmldir = false;
+ if (!qmldircomponents.isEmpty()) {
+ foreach (const QQmlDirParser::Component &c, qmldircomponents) {
+ if (c.typeName == type) {
+ typeWasDeclaredInQmldir = true;
+ // importing version -1 means import ALL versions
+ if ((vmaj == -1) || (c.majorVersion == vmaj && vmin >= c.minorVersion)) {
+ QString url(data.url + type + QLatin1String(".qml"));
+ QString candidate = resolveLocalUrl(url, c.fileName);
+ if (c.internal && base) {
+ if (resolveLocalUrl(*base, c.fileName) != candidate)
+ continue; // failed attempt to access an internal type
+ }
+ if (base && *base == candidate) {
+ if (typeRecursionDetected)
+ *typeRecursionDetected = true;
+ continue; // no recursion
+ }
+ if (url_return)
+ *url_return = candidate;
+ return true;
+ }
+ }
+ }
+ }
+
+ if (!typeWasDeclaredInQmldir && !data.isLibrary) {
+ // XXX search non-files too! (eg. zip files, see QT-524)
+ QString url(data.url + type + QLatin1String(".qml"));
+ QString file = QQmlEnginePrivate::urlToLocalFileOrQrc(url);
+ if (!typeLoader->absoluteFilePath(file).isEmpty()) {
+ if (base && *base == url) { // no recursion
+ if (typeRecursionDetected)
+ *typeRecursionDetected = true;
+ } else {
+ if (url_return)
+ *url_return = url;
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+QQmlImportsPrivate::QQmlImportsPrivate(QQmlTypeLoader *loader)
+ : ref(1), typeLoader(loader)
+{
+}
+
+QQmlImportsPrivate::~QQmlImportsPrivate()
+{
+ foreach (QQmlImportedNamespace* s, set.values())
+ delete s;
+}
+
+bool QQmlImportsPrivate::importExtension(const QString &absoluteFilePath, const QString &uri,
+ QQmlImportDatabase *database,
+ QQmlDirComponents* components,
+ QQmlDirScripts* scripts,
+ QList<QQmlError> *errors)
+{
+ const QQmlDirParser *qmldirParser = typeLoader->qmlDirParser(absoluteFilePath);
+ if (qmldirParser->hasError()) {
+ if (errors) {
+ const QList<QQmlError> qmldirErrors = qmldirParser->errors(uri);
+ for (int i = 0; i < qmldirErrors.size(); ++i)
+ errors->prepend(qmldirErrors.at(i));
+ }
+ return false;
+ }
+
+ if (qmlImportTrace())
+ qDebug().nospace() << "QQmlImports(" << qPrintable(base) << "::importExtension: "
+ << "loaded " << absoluteFilePath;
+
+ if (! qmlDirFilesForWhichPluginsHaveBeenLoaded.contains(absoluteFilePath)) {
+ qmlDirFilesForWhichPluginsHaveBeenLoaded.insert(absoluteFilePath);
+
+ QString qmldirPath = absoluteFilePath;
+ int slash = absoluteFilePath.lastIndexOf(QLatin1Char('/'));
+ if (slash > 0)
+ qmldirPath.truncate(slash);
+ foreach (const QQmlDirParser::Plugin &plugin, qmldirParser->plugins()) {
+
+ QString resolvedFilePath = database->resolvePlugin(typeLoader, qmldirPath, plugin.path, plugin.name);
+ if (!resolvedFilePath.isEmpty()) {
+ if (!database->importPlugin(resolvedFilePath, uri, errors)) {
+ if (errors) {
+ // XXX TODO: should we leave the import plugin error alone?
+ // Here, we pop it off the top and coalesce it into this error's message.
+ // The reason is that the lower level may add url and line/column numbering information.
+ QQmlError poppedError = errors->takeFirst();
+ QQmlError error;
+ error.setDescription(QQmlImportDatabase::tr("plugin cannot be loaded for module \"%1\": %2").arg(uri).arg(poppedError.description()));
+ error.setUrl(QUrl::fromLocalFile(absoluteFilePath));
+ errors->prepend(error);
+ }
+ return false;
+ }
+ } else {
+ if (errors) {
+ QQmlError error;
+ error.setDescription(QQmlImportDatabase::tr("module \"%1\" plugin \"%2\" not found").arg(uri).arg(plugin.name));
+ error.setUrl(QUrl::fromLocalFile(absoluteFilePath));
+ errors->prepend(error);
+ }
+ return false;
+ }
+ }
+ }
+
+ if (components)
+ *components = qmldirParser->components();
+ if (scripts)
+ *scripts = qmldirParser->scripts();
+
+ return true;
+}
+
+QString QQmlImportsPrivate::resolvedUri(const QString &dir_arg, QQmlImportDatabase *database)
+{
+ QString dir = dir_arg;
+ if (dir.endsWith(QLatin1Char('/')) || dir.endsWith(QLatin1Char('\\')))
+ dir.chop(1);
+
+ QStringList paths = database->fileImportPath;
+ qSort(paths.begin(), paths.end(), greaterThan); // Ensure subdirs preceed their parents.
+
+ QString stableRelativePath = dir;
+ foreach(const QString &path, paths) {
+ if (dir.startsWith(path)) {
+ stableRelativePath = dir.mid(path.length()+1);
+ break;
+ }
+ }
+
+ stableRelativePath.replace(QLatin1Char('\\'), QLatin1Char('/'));
+
+ // remove optional versioning in dot notation from uri
+ int lastSlash = stableRelativePath.lastIndexOf(QLatin1Char('/'));
+ if (lastSlash >= 0) {
+ int versionDot = stableRelativePath.indexOf(QLatin1Char('.'), lastSlash);
+ if (versionDot >= 0)
+ stableRelativePath = stableRelativePath.left(versionDot);
+ }
+
+ stableRelativePath.replace(QLatin1Char('/'), QLatin1Char('.'));
+ return stableRelativePath;
+}
+
+bool QQmlImportsPrivate::add(const QQmlDirComponents &qmldircomponentsnetwork,
+ const QString& uri_arg, const QString& prefix, int vmaj, int vmin,
+ QQmlScript::Import::Type importType,
+ QQmlImportDatabase *database, QList<QQmlError> *errors)
+{
+ static QLatin1String Slash_qmldir("/qmldir");
+ static QLatin1Char Slash('/');
+
+ QQmlDirComponents qmldircomponents = qmldircomponentsnetwork;
+ QQmlDirScripts qmldirscripts;
+ QString uri = uri_arg;
+ QQmlImportedNamespace *s;
+ if (prefix.isEmpty()) {
+ s = &unqualifiedset;
+ } else {
+ s = set.value(prefix);
+ if (!s)
+ set.insert(prefix,(s=new QQmlImportedNamespace));
+ }
+ QString url = uri;
+ bool versionFound = false;
+ if (importType == QQmlScript::Import::Library) {
+
+ Q_ASSERT(vmaj >= 0 && vmin >= 0); // Versions are always specified for libraries
+
+ url.replace(QLatin1Char('.'), Slash);
+ bool found = false;
+ QString dir;
+ QString qmldir;
+
+ // step 1: search for extension with fully encoded version number
+ foreach (const QString &p, database->fileImportPath) {
+ dir = p+Slash+url;
+
+ QFileInfo fi(dir+QString(QLatin1String(".%1.%2")).arg(vmaj).arg(vmin)+QLatin1String("/qmldir"));
+ const QString absoluteFilePath = fi.absoluteFilePath();
+
+ if (fi.isFile()) {
+ found = true;
+
+ const QString absolutePath = fi.absolutePath();
+ if (absolutePath.at(0) == QLatin1Char(':'))
+ url = QLatin1String("qrc://") + absolutePath.mid(1);
+ else
+ url = QUrl::fromLocalFile(fi.absolutePath()).toString();
+ uri = resolvedUri(dir, database);
+ if (!importExtension(absoluteFilePath, uri, database, &qmldircomponents, &qmldirscripts, errors))
+ return false;
+ break;
+ }
+ }
+
+ // TODO: Should this search be omitted if found == true?
+
+ // step 2: search for extension with encoded version major
+ foreach (const QString &p, database->fileImportPath) {
+ dir = p+Slash+url;
+
+ QFileInfo fi(dir+QString(QLatin1String(".%1")).arg(vmaj)+QLatin1String("/qmldir"));
+ const QString absoluteFilePath = fi.absoluteFilePath();
+
+ if (fi.isFile()) {
+ found = true;
+
+ const QString absolutePath = fi.absolutePath();
+ if (absolutePath.at(0) == QLatin1Char(':'))
+ url = QLatin1String("qrc://") + absolutePath.mid(1);
+ else
+ url = QUrl::fromLocalFile(fi.absolutePath()).toString();
+ uri = resolvedUri(dir, database);
+ if (!importExtension(absoluteFilePath, uri, database, &qmldircomponents, &qmldirscripts, errors))
+ return false;
+ break;
+ }
+ }
+
+ if (!found) {
+ // step 3: search for extension without version number
+
+ foreach (const QString &p, database->fileImportPath) {
+ dir = p+Slash+url;
+ qmldir = dir+Slash_qmldir;
+
+ QString absoluteFilePath = typeLoader->absoluteFilePath(qmldir);
+ if (!absoluteFilePath.isEmpty()) {
+ found = true;
+ QString absolutePath = absoluteFilePath.left(absoluteFilePath.lastIndexOf(Slash)+1);
+ if (absolutePath.at(0) == QLatin1Char(':'))
+ url = QLatin1String("qrc://") + absolutePath.mid(1);
+ else
+ url = QUrl::fromLocalFile(absolutePath).toString();
+ uri = resolvedUri(dir, database);
+ if (!importExtension(absoluteFilePath, uri, database, &qmldircomponents, &qmldirscripts, errors))
+ return false;
+ break;
+ }
+ }
+ }
+
+ if (QQmlMetaType::isModule(uri, vmaj, vmin))
+ versionFound = true;
+
+ if (!versionFound && qmldircomponents.isEmpty() && qmldirscripts.isEmpty()) {
+ if (errors) {
+ QQmlError error; // we don't set the url or line or column as these will be set by the loader.
+ if (QQmlMetaType::isAnyModule(uri))
+ error.setDescription(QQmlImportDatabase::tr("module \"%1\" version %2.%3 is not installed").arg(uri_arg).arg(vmaj).arg(vmin));
+ else
+ error.setDescription(QQmlImportDatabase::tr("module \"%1\" is not installed").arg(uri_arg));
+ errors->prepend(error);
+ }
+ return false;
+ }
+ } else {
+ if (importType == QQmlScript::Import::File && qmldircomponents.isEmpty()) {
+ QString importUrl = resolveLocalUrl(base, uri + Slash_qmldir);
+ QString localFileOrQrc = QQmlEnginePrivate::urlToLocalFileOrQrc(importUrl);
+ if (!localFileOrQrc.isEmpty()) {
+ QString dir = QQmlEnginePrivate::urlToLocalFileOrQrc(resolveLocalUrl(base, uri));
+ if (!typeLoader->directoryExists(dir)) {
+ if (errors) {
+ QQmlError error; // we don't set the line or column as these will be set by the loader.
+ error.setDescription(QQmlImportDatabase::tr("\"%1\": no such directory").arg(uri_arg));
+ error.setUrl(QUrl(importUrl));
+ errors->prepend(error);
+ }
+ return false; // local import dirs must exist
+ }
+ uri = resolvedUri(dir, database);
+ if (uri.endsWith(Slash))
+ uri.chop(1);
+ if (!typeLoader->absoluteFilePath(localFileOrQrc).isEmpty()) {
+ if (!importExtension(localFileOrQrc,uri,database,&qmldircomponents,&qmldirscripts,errors))
+ return false;
+ }
+ } else {
+ if (prefix.isEmpty()) {
+ // directory must at least exist for valid import
+ QString localFileOrQrc = QQmlEnginePrivate::urlToLocalFileOrQrc(resolveLocalUrl(base, uri));
+ if (!typeLoader->directoryExists(localFileOrQrc)) {
+ if (errors) {
+ QQmlError error; // we don't set the line or column as these will be set by the loader.
+ if (localFileOrQrc.isEmpty())
+ error.setDescription(QQmlImportDatabase::tr("import \"%1\" has no qmldir and no namespace").arg(uri));
+ else
+ error.setDescription(QQmlImportDatabase::tr("\"%1\": no such directory").arg(uri));
+ error.setUrl(QUrl(importUrl));
+ errors->prepend(error);
+ }
+ return false;
+ }
+ }
+ }
+ }
+
+ url = resolveLocalUrl(base, url);
+ }
+
+ if (!versionFound && (vmaj > -1) && (vmin > -1) && !qmldircomponents.isEmpty()) {
+ int lowest_min = INT_MAX;
+ int highest_min = INT_MIN;
+
+ QList<QQmlDirParser::Component>::const_iterator cend = qmldircomponents.constEnd();
+ for (QList<QQmlDirParser::Component>::const_iterator cit = qmldircomponents.constBegin(); cit != cend; ++cit) {
+ if (cit->majorVersion == vmaj) {
+ lowest_min = qMin(lowest_min, cit->minorVersion);
+ highest_min = qMax(highest_min, cit->minorVersion);
+ }
+ }
+
+ if (lowest_min > vmin || highest_min < vmin) {
+ if (errors) {
+ QQmlError error; // we don't set the url or line or column information, as these will be set by the loader.
+ error.setDescription(QQmlImportDatabase::tr("module \"%1\" version %2.%3 is not installed").arg(uri_arg).arg(vmaj).arg(vmin));
+ errors->prepend(error);
+ }
+ return false;
+ }
+ }
+
+ if (!url.endsWith(Slash))
+ url += Slash;
+
+ QMap<QString, QQmlDirParser::Script> scripts;
+
+ if (!qmldirscripts.isEmpty()) {
+ // Verify that we haven't imported these scripts already
+ QList<QQmlImportedNamespace::Data>::const_iterator end = s->imports.constEnd();
+ for (QList<QQmlImportedNamespace::Data>::const_iterator it = s->imports.constBegin(); it != end; ++it) {
+ if (it->uri == uri) {
+ QQmlError error;
+ error.setDescription(QQmlImportDatabase::tr("\"%1\" is ambiguous. Found in %2 and in %3").arg(uri).arg(url).arg(it->url));
+ errors->prepend(error);
+ return false;
+ }
+ }
+
+ QList<QQmlDirParser::Script>::const_iterator send = qmldirscripts.constEnd();
+ for (QList<QQmlDirParser::Script>::const_iterator sit = qmldirscripts.constBegin(); sit != send; ++sit) {
+ // Only include scripts that match our requested version
+ if (((vmaj == -1) || (sit->majorVersion == vmaj)) &&
+ ((vmin == -1) || (sit->minorVersion <= vmin))) {
+
+ // Load the highest version that matches
+ QMap<QString, QQmlDirParser::Script>::iterator it = scripts.find(sit->nameSpace);
+ if (it == scripts.end() || (it->minorVersion < sit->minorVersion)) {
+ scripts.insert(sit->nameSpace, *sit);
+ }
+ }
+ }
+ }
+
+ QQmlImportedNamespace::Data data;
+ data.uri = uri;
+ data.url = url;
+ data.majversion = vmaj;
+ data.minversion = vmin;
+ data.isLibrary = importType == QQmlScript::Import::Library;
+ data.qmlDirComponents = qmldircomponents;
+ data.qmlDirScripts = scripts.values();
+
+ s->imports.prepend(data);
+
+ return true;
+}
+
+bool QQmlImportsPrivate::find(const QString& type, int *vmajor, int *vminor, QQmlType** type_return,
+ QString* url_return, QList<QQmlError> *errors)
+{
+ QQmlImportedNamespace *s = 0;
+ int slash = type.indexOf(QLatin1Char('/'));
+ if (slash >= 0) {
+ QString namespaceName = type.left(slash);
+ s = set.value(namespaceName);
+ if (!s) {
+ if (errors) {
+ QQmlError error;
+ error.setDescription(QQmlImportDatabase::tr("- %1 is not a namespace").arg(namespaceName));
+ errors->prepend(error);
+ }
+ return false;
+ }
+ int nslash = type.indexOf(QLatin1Char('/'),slash+1);
+ if (nslash > 0) {
+ if (errors) {
+ QQmlError error;
+ error.setDescription(QQmlImportDatabase::tr("- nested namespaces not allowed"));
+ errors->prepend(error);
+ }
+ return false;
+ }
+ } else {
+ s = &unqualifiedset;
+ }
+ QString unqualifiedtype = slash < 0 ? type : type.mid(slash+1); // common-case opt (QString::mid works fine, but slower)
+ if (s) {
+ if (s->find(typeLoader,unqualifiedtype,vmajor,vminor,type_return,url_return, &base, errors))
+ return true;
+ if (s->imports.count() == 1 && !s->imports.at(0).isLibrary && url_return && s != &unqualifiedset) {
+ // qualified, and only 1 url
+ *url_return = resolveLocalUrl(s->imports.at(0).url, unqualifiedtype + QLatin1String(".qml"));
+ return true;
+ }
+ }
+
+ return false;
+}
+
+QQmlImportedNamespace *QQmlImportsPrivate::findNamespace(const QString& type)
+{
+ return set.value(type);
+}
+
+bool QQmlImportedNamespace::find(QQmlTypeLoader *typeLoader, const QString& type, int *vmajor, int *vminor, QQmlType** type_return,
+ QString* url_return, QString *base, QList<QQmlError> *errors)
+{
+ bool typeRecursionDetected = false;
+ for (int i=0; i<imports.count(); ++i) {
+ if (find_helper(typeLoader, imports.at(i), type, vmajor, vminor, type_return, url_return, base, &typeRecursionDetected)) {
+ if (qmlCheckTypes()) {
+ // check for type clashes
+ for (int j = i+1; j<imports.count(); ++j) {
+ if (find_helper(typeLoader, imports.at(j), type, vmajor, vminor, 0, 0, base)) {
+ if (errors) {
+ QString u1 = imports.at(i).url;
+ QString u2 = imports.at(j).url;
+ if (base) {
+ QString b = *base;
+ int slash = b.lastIndexOf(QLatin1Char('/'));
+ if (slash >= 0) {
+ b = b.left(slash+1);
+ QString l = b.left(slash);
+ if (u1.startsWith(b))
+ u1 = u1.mid(b.count());
+ else if (u1 == l)
+ u1 = QQmlImportDatabase::tr("local directory");
+ if (u2.startsWith(b))
+ u2 = u2.mid(b.count());
+ else if (u2 == l)
+ u2 = QQmlImportDatabase::tr("local directory");
+ }
+ }
+
+ QQmlError error;
+ if (u1 != u2) {
+ error.setDescription(QQmlImportDatabase::tr("is ambiguous. Found in %1 and in %2").arg(u1).arg(u2));
+ } else {
+ error.setDescription(QQmlImportDatabase::tr("is ambiguous. Found in %1 in version %2.%3 and %4.%5")
+ .arg(u1)
+ .arg(imports.at(i).majversion).arg(imports.at(i).minversion)
+ .arg(imports.at(j).majversion).arg(imports.at(j).minversion));
+ }
+ errors->prepend(error);
+ }
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+ }
+ if (errors) {
+ QQmlError error;
+ if (typeRecursionDetected)
+ error.setDescription(QQmlImportDatabase::tr("is instantiated recursively"));
+ else
+ error.setDescription(QQmlImportDatabase::tr("is not a type"));
+ errors->prepend(error);
+ }
+ return false;
+}
+
+/*!
+\class QQmlImportDatabase
+\brief The QQmlImportDatabase class manages the QML imports for a QQmlEngine.
+\internal
+*/
+QQmlImportDatabase::QQmlImportDatabase(QQmlEngine *e)
+: engine(e)
+{
+ filePluginPath << QLatin1String(".");
+
+ // Search order is applicationDirPath(), $QML_IMPORT_PATH, QLibraryInfo::ImportsPath
+
+#ifndef QT_NO_SETTINGS
+ QString installImportsPath = QLibraryInfo::location(QLibraryInfo::ImportsPath);
+ addImportPath(installImportsPath);
+#endif // QT_NO_SETTINGS
+
+ // env import paths
+ QByteArray envImportPath = qgetenv("QML_IMPORT_PATH");
+ if (!envImportPath.isEmpty()) {
+#if defined(Q_OS_WIN)
+ QLatin1Char pathSep(';');
+#else
+ QLatin1Char pathSep(':');
+#endif
+ QStringList paths = QString::fromLatin1(envImportPath).split(pathSep, QString::SkipEmptyParts);
+ for (int ii = paths.count() - 1; ii >= 0; --ii)
+ addImportPath(paths.at(ii));
+ }
+
+ addImportPath(QCoreApplication::applicationDirPath());
+}
+
+QQmlImportDatabase::~QQmlImportDatabase()
+{
+}
+
+/*!
+ \internal
+
+ Adds information to \a imports such that subsequent calls to resolveType()
+ will resolve types qualified by \a prefix by considering types found at the given \a uri.
+
+ The uri is either a directory (if importType is FileImport), or a URI resolved using paths
+ added via addImportPath() (if importType is LibraryImport).
+
+ The \a prefix may be empty, in which case the import location is considered for
+ unqualified types.
+
+ The base URL must already have been set with Import::setBaseUrl().
+*/
+bool QQmlImports::addImport(QQmlImportDatabase *importDb,
+ const QString& uri, const QString& prefix, int vmaj, int vmin,
+ QQmlScript::Import::Type importType,
+ const QQmlDirComponents &qmldircomponentsnetwork,
+ QList<QQmlError> *errors)
+{
+ if (qmlImportTrace())
+ qDebug().nospace() << "QQmlImports(" << qPrintable(baseUrl().toString()) << ")" << "::addImport: "
+ << uri << " " << vmaj << '.' << vmin << " "
+ << (importType==QQmlScript::Import::Library? "Library" : "File")
+ << " as " << prefix;
+
+ return d->add(qmldircomponentsnetwork, uri, prefix, vmaj, vmin, importType, importDb, errors);
+}
+
+/*!
+ \internal
+
+ Returns the result of the merge of \a baseName with \a path, \a suffixes, and \a prefix.
+ The \a prefix must contain the dot.
+
+ \a qmldirPath is the location of the qmldir file.
+ */
+QString QQmlImportDatabase::resolvePlugin(QQmlTypeLoader *typeLoader,
+ const QString &qmldirPath, const QString &qmldirPluginPath,
+ const QString &baseName, const QStringList &suffixes,
+ const QString &prefix)
+{
+ QStringList searchPaths = filePluginPath;
+ bool qmldirPluginPathIsRelative = QDir::isRelativePath(qmldirPluginPath);
+ if (!qmldirPluginPathIsRelative)
+ searchPaths.prepend(qmldirPluginPath);
+
+ foreach (const QString &pluginPath, searchPaths) {
+
+ QString resolvedPath;
+ if (pluginPath == QLatin1String(".")) {
+ if (qmldirPluginPathIsRelative && !qmldirPluginPath.isEmpty() && qmldirPluginPath != QLatin1String("."))
+ resolvedPath = QDir::cleanPath(qmldirPath + QLatin1Char('/') + qmldirPluginPath);
+ else
+ resolvedPath = qmldirPath;
+ } else {
+ if (QDir::isRelativePath(pluginPath))
+ resolvedPath = QDir::cleanPath(qmldirPath + QLatin1Char('/') + pluginPath);
+ else
+ resolvedPath = pluginPath;
+ }
+
+ // hack for resources, should probably go away
+ if (resolvedPath.startsWith(QLatin1Char(':')))
+ resolvedPath = QCoreApplication::applicationDirPath();
+
+ if (!resolvedPath.endsWith(QLatin1Char('/')))
+ resolvedPath += QLatin1Char('/');
+
+ foreach (const QString &suffix, suffixes) {
+ QString pluginFileName = prefix;
+
+ pluginFileName += baseName;
+ pluginFileName += suffix;
+
+ QString absolutePath = typeLoader->absoluteFilePath(resolvedPath + pluginFileName);
+ if (!absolutePath.isEmpty())
+ return absolutePath;
+ }
+ }
+
+ if (qmlImportTrace())
+ qDebug() << "QQmlImportDatabase::resolvePlugin: Could not resolve plugin" << baseName
+ << "in" << qmldirPath;
+
+ return QString();
+}
+
+/*!
+ \internal
+
+ Returns the result of the merge of \a baseName with \a dir and the platform suffix.
+
+ \table
+ \header \i Platform \i Valid suffixes
+ \row \i Windows \i \c .dll
+ \row \i Unix/Linux \i \c .so
+ \row \i AIX \i \c .a
+ \row \i HP-UX \i \c .sl, \c .so (HP-UXi)
+ \row \i Mac OS X \i \c .dylib, \c .bundle, \c .so
+ \endtable
+
+ Version number on unix are ignored.
+*/
+QString QQmlImportDatabase::resolvePlugin(QQmlTypeLoader *typeLoader,
+ const QString &qmldirPath, const QString &qmldirPluginPath,
+ const QString &baseName)
+{
+#if defined(Q_OS_WIN32) || defined(Q_OS_WINCE)
+ return resolvePlugin(typeLoader, qmldirPath, qmldirPluginPath, baseName,
+ QStringList()
+# ifdef QT_DEBUG
+ << QLatin1String("d.dll") // try a qmake-style debug build first
+# endif
+ << QLatin1String(".dll"));
+#else
+
+# if defined(Q_OS_DARWIN)
+
+ return resolvePlugin(typeLoader, qmldirPath, qmldirPluginPath, baseName,
+ QStringList()
+# ifdef QT_DEBUG
+ << QLatin1String("_debug.dylib") // try a qmake-style debug build first
+ << QLatin1String(".dylib")
+# else
+ << QLatin1String(".dylib")
+ << QLatin1String("_debug.dylib") // try a qmake-style debug build after
+# endif
+ << QLatin1String(".so")
+ << QLatin1String(".bundle"),
+ QLatin1String("lib"));
+# else // Generic Unix
+ QStringList validSuffixList;
+
+# if defined(Q_OS_HPUX)
+/*
+ See "HP-UX Linker and Libraries User's Guide", section "Link-time Differences between PA-RISC and IPF":
+ "In PA-RISC (PA-32 and PA-64) shared libraries are suffixed with .sl. In IPF (32-bit and 64-bit),
+ the shared libraries are suffixed with .so. For compatibility, the IPF linker also supports the .sl suffix."
+ */
+ validSuffixList << QLatin1String(".sl");
+# if defined __ia64
+ validSuffixList << QLatin1String(".so");
+# endif
+# elif defined(Q_OS_AIX)
+ validSuffixList << QLatin1String(".a") << QLatin1String(".so");
+# elif defined(Q_OS_UNIX)
+ validSuffixList << QLatin1String(".so");
+# endif
+
+ // Examples of valid library names:
+ // libfoo.so
+
+ return resolvePlugin(typeLoader, qmldirPath, qmldirPluginPath, baseName, validSuffixList, QLatin1String("lib"));
+# endif
+
+#endif
+}
+
+/*!
+ \internal
+*/
+QStringList QQmlImportDatabase::pluginPathList() const
+{
+ return filePluginPath;
+}
+
+/*!
+ \internal
+*/
+void QQmlImportDatabase::setPluginPathList(const QStringList &paths)
+{
+ filePluginPath = paths;
+}
+
+/*!
+ \internal
+*/
+void QQmlImportDatabase::addPluginPath(const QString& path)
+{
+ if (qmlImportTrace())
+ qDebug().nospace() << "QQmlImportDatabase::addPluginPath: " << path;
+
+ QUrl url = QUrl(path);
+ if (url.isRelative() || url.scheme() == QLatin1String("file")
+ || (url.scheme().length() == 1 && QFile::exists(path)) ) { // windows path
+ QDir dir = QDir(path);
+ filePluginPath.prepend(dir.canonicalPath());
+ } else {
+ filePluginPath.prepend(path);
+ }
+}
+
+/*!
+ \internal
+*/
+void QQmlImportDatabase::addImportPath(const QString& path)
+{
+ if (qmlImportTrace())
+ qDebug().nospace() << "QQmlImportDatabase::addImportPath: " << path;
+
+ if (path.isEmpty())
+ return;
+
+ QUrl url = QUrl(path);
+ QString cPath;
+
+ if (url.isRelative() || url.scheme() == QLatin1String("file")
+ || (url.scheme().length() == 1 && QFile::exists(path)) ) { // windows path
+ QDir dir = QDir(path);
+ cPath = dir.canonicalPath();
+ } else {
+ cPath = path;
+ cPath.replace(QLatin1Char('\\'), QLatin1Char('/'));
+ }
+
+ if (!cPath.isEmpty()
+ && !fileImportPath.contains(cPath))
+ fileImportPath.prepend(cPath);
+}
+
+/*!
+ \internal
+*/
+QStringList QQmlImportDatabase::importPathList() const
+{
+ return fileImportPath;
+}
+
+/*!
+ \internal
+*/
+void QQmlImportDatabase::setImportPathList(const QStringList &paths)
+{
+ fileImportPath = paths;
+}
+
+/*!
+ \internal
+*/
+bool QQmlImportDatabase::importPlugin(const QString &filePath, const QString &uri, QList<QQmlError> *errors)
+{
+ if (qmlImportTrace())
+ qDebug().nospace() << "QQmlImportDatabase::importPlugin: " << uri << " from " << filePath;
+
+#ifndef QT_NO_LIBRARY
+ QFileInfo fileInfo(filePath);
+ const QString absoluteFilePath = fileInfo.absoluteFilePath();
+
+ bool engineInitialized = initializedPlugins.contains(absoluteFilePath);
+ bool typesRegistered = qmlEnginePluginsWithRegisteredTypes()->contains(absoluteFilePath);
+
+ if (typesRegistered) {
+ Q_ASSERT_X(qmlEnginePluginsWithRegisteredTypes()->value(absoluteFilePath) == uri,
+ "QQmlImportDatabase::importExtension",
+ "Internal error: Plugin imported previously with different uri");
+ }
+
+ if (!engineInitialized || !typesRegistered) {
+ if (!QQml_isFileCaseCorrect(absoluteFilePath)) {
+ if (errors) {
+ QQmlError error;
+ error.setDescription(tr("File name case mismatch for \"%1\"").arg(absoluteFilePath));
+ errors->prepend(error);
+ }
+ return false;
+ }
+ QPluginLoader loader(absoluteFilePath);
+
+ if (!loader.load()) {
+ if (errors) {
+ QQmlError error;
+ error.setDescription(loader.errorString());
+ errors->prepend(error);
+ }
+ return false;
+ }
+
+ QObject *instance = loader.instance();
+ if (QQmlTypesExtensionInterface *iface = qobject_cast<QQmlExtensionInterface *>(instance)) {
+
+ const QByteArray bytes = uri.toUtf8();
+ const char *moduleId = bytes.constData();
+ if (!typesRegistered) {
+
+ // XXX thread this code should probably be protected with a mutex.
+ qmlEnginePluginsWithRegisteredTypes()->insert(absoluteFilePath, uri);
+ iface->registerTypes(moduleId);
+ }
+ if (!engineInitialized) {
+ // things on the engine (eg. adding new global objects) have to be done for every
+ // engine.
+ // XXX protect against double initialization
+ initializedPlugins.insert(absoluteFilePath);
+
+ QQmlExtensionInterface *eiface =
+ qobject_cast<QQmlExtensionInterface *>(instance);
+ if (eiface) {
+ QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine);
+ ep->typeLoader.initializeEngine(eiface, moduleId);
+ }
+ }
+ } else {
+ if (errors) {
+ QQmlError error;
+ error.setDescription(loader.errorString());
+ errors->prepend(error);
+ }
+ return false;
+ }
+ }
+
+ return true;
+#else
+ return false;
+#endif
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlimport_p.h b/src/qml/qml/qqmlimport_p.h
new file mode 100644
index 0000000000..ff19510525
--- /dev/null
+++ b/src/qml/qml/qqmlimport_p.h
@@ -0,0 +1,157 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLIMPORT_P_H
+#define QQMLIMPORT_P_H
+
+#include <QtCore/qurl.h>
+#include <QtCore/qcoreapplication.h>
+#include <QtCore/qset.h>
+#include <QtCore/qstringlist.h>
+#include <private/qqmldirparser_p.h>
+#include <private/qqmlscript_p.h>
+#include <private/qqmlmetatype_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.
+//
+
+QT_BEGIN_NAMESPACE
+
+class QQmlTypeNameCache;
+class QQmlEngine;
+class QDir;
+class QQmlImportedNamespace;
+class QQmlImportsPrivate;
+class QQmlImportDatabase;
+class QQmlTypeLoader;
+
+// Exported for QtQuick1
+class Q_QML_EXPORT QQmlImports
+{
+public:
+ QQmlImports(QQmlTypeLoader *);
+ QQmlImports(const QQmlImports &);
+ ~QQmlImports();
+ QQmlImports &operator=(const QQmlImports &);
+
+ void setBaseUrl(const QUrl &url, const QString &urlString = QString());
+ QUrl baseUrl() const;
+
+ bool resolveType(const QString& type,
+ QQmlType** type_return, QString* url_return,
+ int *version_major, int *version_minor,
+ QQmlImportedNamespace** ns_return,
+ QList<QQmlError> *errors = 0) const;
+ bool resolveType(QQmlImportedNamespace*,
+ const QString& type,
+ QQmlType** type_return, QString* url_return,
+ int *version_major, int *version_minor) const;
+
+ bool addImport(QQmlImportDatabase *,
+ const QString& uri, const QString& prefix, int vmaj, int vmin,
+ QQmlScript::Import::Type importType,
+ const QQmlDirComponents &qmldircomponentsnetwork,
+ QList<QQmlError> *errors);
+
+ void populateCache(QQmlTypeNameCache *cache, QQmlEngine *) const;
+
+ struct ScriptReference
+ {
+ QString nameSpace;
+ QString qualifier;
+ QUrl location;
+ };
+
+ QList<ScriptReference> resolvedScripts() const;
+
+private:
+ friend class QQmlImportDatabase;
+ QQmlImportsPrivate *d;
+};
+
+class QQmlImportDatabase
+{
+ Q_DECLARE_TR_FUNCTIONS(QQmlImportDatabase)
+public:
+ QQmlImportDatabase(QQmlEngine *);
+ ~QQmlImportDatabase();
+
+ bool importPlugin(const QString &filePath, const QString &uri, QList<QQmlError> *errors);
+
+ QStringList importPathList() const;
+ void setImportPathList(const QStringList &paths);
+ void addImportPath(const QString& dir);
+
+ QStringList pluginPathList() const;
+ void setPluginPathList(const QStringList &paths);
+ void addPluginPath(const QString& path);
+
+private:
+ friend class QQmlImportsPrivate;
+ QString resolvePlugin(QQmlTypeLoader *typeLoader,
+ const QString &qmldirPath, const QString &qmldirPluginPath,
+ const QString &baseName, const QStringList &suffixes,
+ const QString &prefix = QString());
+ QString resolvePlugin(QQmlTypeLoader *typeLoader,
+ const QString &qmldirPath, const QString &qmldirPluginPath,
+ const QString &baseName);
+
+
+ // XXX thread
+ QStringList filePluginPath;
+ QStringList fileImportPath;
+
+ QSet<QString> initializedPlugins;
+ QQmlEngine *engine;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQMLIMPORT_P_H
+
diff --git a/src/qml/qml/qqmlincubator.cpp b/src/qml/qml/qqmlincubator.cpp
new file mode 100644
index 0000000000..ee622ba048
--- /dev/null
+++ b/src/qml/qml/qqmlincubator.cpp
@@ -0,0 +1,696 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qqmlincubator.h"
+#include "qqmlcomponent.h"
+#include "qqmlincubator_p.h"
+
+#include "qqmlcompiler_p.h"
+#include "qqmlexpression_p.h"
+
+// XXX TODO
+// - check that the Component.onCompleted behavior is the same as 4.8 in the synchronous and
+// async if nested cases
+void QQmlEnginePrivate::incubate(QQmlIncubator &i, QQmlContextData *forContext)
+{
+ QQmlIncubatorPrivate *p = i.d;
+
+ QQmlIncubator::IncubationMode mode = i.incubationMode();
+
+ if (!incubationController)
+ mode = QQmlIncubator::Synchronous;
+
+ if (mode == QQmlIncubator::AsynchronousIfNested) {
+ mode = QQmlIncubator::Synchronous;
+
+ // Need to find the first constructing context and see if it is asynchronous
+ QQmlIncubatorPrivate *parentIncubator = 0;
+ QQmlContextData *cctxt = forContext;
+ while (cctxt) {
+ if (cctxt->activeVMEData) {
+ parentIncubator = (QQmlIncubatorPrivate *)cctxt->activeVMEData;
+ break;
+ }
+ cctxt = cctxt->parent;
+ }
+
+ if (parentIncubator && parentIncubator->isAsynchronous) {
+ mode = QQmlIncubator::Asynchronous;
+ p->waitingOnMe = parentIncubator;
+ parentIncubator->waitingFor.insert(p);
+ }
+ }
+
+ p->isAsynchronous = (mode != QQmlIncubator::Synchronous);
+
+ inProgressCreations++;
+
+ if (mode == QQmlIncubator::Synchronous) {
+ typedef QQmlIncubatorPrivate IP;
+ QRecursionWatcher<IP, &IP::recursion> watcher(p);
+
+ p->changeStatus(QQmlIncubator::Loading);
+
+ if (!watcher.hasRecursed()) {
+ QQmlVME::Interrupt i;
+ p->incubate(i);
+ }
+ } else {
+ incubatorList.insert(p);
+ incubatorCount++;
+
+ p->vmeGuard.guard(&p->vme);
+ p->changeStatus(QQmlIncubator::Loading);
+
+ if (incubationController)
+ incubationController->incubatingObjectCountChanged(incubatorCount);
+ }
+}
+
+/*!
+Sets the engine's incubation \a controller. The engine can only have one active controller
+and it does not take ownership of it.
+
+\sa incubationController()
+*/
+void QQmlEngine::setIncubationController(QQmlIncubationController *controller)
+{
+ Q_D(QQmlEngine);
+ if (d->incubationController)
+ d->incubationController->d = 0;
+ d->incubationController = controller;
+ if (controller) controller->d = d;
+}
+
+/*!
+Returns the currently set incubation controller, or 0 if no controller has been set.
+
+\sa setIncubationController()
+*/
+QQmlIncubationController *QQmlEngine::incubationController() const
+{
+ Q_D(const QQmlEngine);
+ return d->incubationController;
+}
+
+QQmlIncubatorPrivate::QQmlIncubatorPrivate(QQmlIncubator *q,
+ QQmlIncubator::IncubationMode m)
+: q(q), status(QQmlIncubator::Null), mode(m), isAsynchronous(false), progress(Execute),
+ result(0), component(0), vme(this), waitingOnMe(0)
+{
+}
+
+QQmlIncubatorPrivate::~QQmlIncubatorPrivate()
+{
+}
+
+void QQmlIncubatorPrivate::clear()
+{
+ if (next.isInList()) {
+ next.remove();
+ Q_ASSERT(component);
+ QQmlEnginePrivate *enginePriv = QQmlEnginePrivate::get(component->engine);
+ component->release();
+ component = 0;
+ enginePriv->incubatorCount--;
+ QQmlIncubationController *controller = enginePriv->incubationController;
+ if (controller)
+ controller->incubatingObjectCountChanged(enginePriv->incubatorCount);
+ } else if (component) {
+ component->release();
+ component = 0;
+ }
+ if (!rootContext.isNull()) {
+ rootContext->activeVMEData = 0;
+ rootContext = 0;
+ }
+
+ if (nextWaitingFor.isInList()) {
+ Q_ASSERT(waitingOnMe);
+ nextWaitingFor.remove();
+ waitingOnMe = 0;
+ }
+}
+
+/*!
+\class QQmlIncubationController
+\brief QQmlIncubationController instances drive the progress of QQmlIncubators
+
+In order to behave asynchronously and not introduce stutters or freezes in an application,
+the process of creating objects a QQmlIncubators must be driven only during the
+application's idle time. QQmlIncubationController allows the application to control
+exactly when, how often and for how long this processing occurs.
+
+A QQmlIncubationController derived instance should be created and set on a
+QQmlEngine by calling the QQmlEngine::setIncubationController() method.
+Processing is then controlled by calling the QQmlIncubationController::incubateFor()
+or QQmlIncubationController::incubateWhile() methods as dictated by the application's
+requirements.
+
+For example, this is an example of a incubation controller that will incubate for a maximum
+of 5 milliseconds out of every 16 milliseconds.
+
+\code
+class PeriodicIncubationController : public QObject,
+ public QQmlIncubationController
+{
+public:
+ PeriodicIncubationController() {
+ startTimer(16);
+ }
+
+protected:
+ virtual void timerEvent(QTimerEvent *) {
+ incubateFor(5);
+ }
+};
+\endcode
+
+Although the previous example would work, it is not optimal. Real world incubation
+controllers should try and maximize the amount of idle time they consume - rather
+than a static amount like 5 milliseconds - while not disturbing the application.
+*/
+
+/*!
+Create a new incubation controller.
+*/
+QQmlIncubationController::QQmlIncubationController()
+: d(0)
+{
+}
+
+/*! \internal */
+QQmlIncubationController::~QQmlIncubationController()
+{
+ if (d) QQmlEnginePrivate::get(d)->setIncubationController(0);
+ d = 0;
+}
+
+/*!
+Return the QQmlEngine this incubation controller is set on, or 0 if it
+has not been set on any engine.
+*/
+QQmlEngine *QQmlIncubationController::engine() const
+{
+ return QQmlEnginePrivate::get(d);
+}
+
+/*!
+Return the number of objects currently incubating.
+*/
+int QQmlIncubationController::incubatingObjectCount() const
+{
+ if (d)
+ return d->incubatorCount;
+ else
+ return 0;
+}
+
+/*!
+Called when the number of incubating objects changes. \a incubatingObjectCount is the
+new number of incubating objects.
+
+The default implementation does nothing.
+*/
+void QQmlIncubationController::incubatingObjectCountChanged(int incubatingObjectCount)
+{
+ Q_UNUSED(incubatingObjectCount);
+}
+
+void QQmlIncubatorPrivate::incubate(QQmlVME::Interrupt &i)
+{
+ if (!component)
+ return;
+ typedef QQmlIncubatorPrivate IP;
+ QRecursionWatcher<IP, &IP::recursion> watcher(this);
+
+ QQmlEngine *engine = component->engine;
+ QQmlEnginePrivate *enginePriv = QQmlEnginePrivate::get(engine);
+
+ bool guardOk = vmeGuard.isOK();
+ vmeGuard.clear();
+
+ if (!guardOk) {
+ QQmlError error;
+ error.setUrl(component->url);
+ error.setDescription(QQmlComponent::tr("Object destroyed during incubation"));
+ errors << error;
+ progress = QQmlIncubatorPrivate::Completed;
+
+ goto finishIncubate;
+ }
+
+ if (progress == QQmlIncubatorPrivate::Execute) {
+ enginePriv->referenceScarceResources();
+ QObject *tresult = vme.execute(&errors, i);
+ enginePriv->dereferenceScarceResources();
+
+ if (watcher.hasRecursed())
+ return;
+
+ result = tresult;
+ if (errors.isEmpty() && result == 0)
+ goto finishIncubate;
+
+ if (result) {
+ QQmlData *ddata = QQmlData::get(result);
+ Q_ASSERT(ddata);
+ ddata->indestructible = true;
+
+ q->setInitialState(result);
+ }
+
+ if (watcher.hasRecursed())
+ return;
+
+ if (errors.isEmpty())
+ progress = QQmlIncubatorPrivate::Completing;
+ else
+ progress = QQmlIncubatorPrivate::Completed;
+
+ changeStatus(calculateStatus());
+
+ if (watcher.hasRecursed())
+ return;
+
+ if (i.shouldInterrupt())
+ goto finishIncubate;
+ }
+
+ if (progress == QQmlIncubatorPrivate::Completing) {
+ do {
+ if (watcher.hasRecursed())
+ return;
+
+ QQmlContextData *ctxt = vme.complete(i);
+ if (ctxt) {
+ rootContext = ctxt;
+ progress = QQmlIncubatorPrivate::Completed;
+ goto finishIncubate;
+ }
+ } while (!i.shouldInterrupt());
+ }
+
+finishIncubate:
+ if (progress == QQmlIncubatorPrivate::Completed && waitingFor.isEmpty()) {
+ typedef QQmlIncubatorPrivate IP;
+
+ QQmlIncubatorPrivate *isWaiting = waitingOnMe;
+ clear();
+
+ if (isWaiting) {
+ QRecursionWatcher<IP, &IP::recursion> watcher(isWaiting);
+ changeStatus(calculateStatus());
+ if (!watcher.hasRecursed())
+ isWaiting->incubate(i);
+ } else {
+ changeStatus(calculateStatus());
+ }
+
+ enginePriv->inProgressCreations--;
+
+ if (0 == enginePriv->inProgressCreations) {
+ while (enginePriv->erroredBindings) {
+ enginePriv->warning(enginePriv->erroredBindings->error);
+ enginePriv->erroredBindings->removeError();
+ }
+ }
+ } else {
+ vmeGuard.guard(&vme);
+ }
+}
+
+/*!
+Incubate objects for \a msecs, or until there are no more objects to incubate.
+*/
+void QQmlIncubationController::incubateFor(int msecs)
+{
+ if (!d || d->incubatorCount == 0)
+ return;
+
+ QQmlVME::Interrupt i(msecs * 1000000);
+ i.reset();
+ do {
+ QQmlIncubatorPrivate *p = (QQmlIncubatorPrivate*)d->incubatorList.first();
+ p->incubate(i);
+ } while (d && d->incubatorCount != 0 && !i.shouldInterrupt());
+}
+
+/*!
+Incubate objects while the bool pointed to by \a flag is true, or until there are no
+more objects to incubate.
+
+Generally this method is used in conjunction with a thread or a UNIX signal that sets
+the bool pointed to by \a flag to false when it wants incubation to be interrupted.
+*/
+void QQmlIncubationController::incubateWhile(bool *flag)
+{
+ if (!d || d->incubatorCount == 0)
+ return;
+
+ QQmlVME::Interrupt i(flag);
+ do {
+ QQmlIncubatorPrivate *p = (QQmlIncubatorPrivate*)d->incubatorList.first();
+ p->incubate(i);
+ } while (d && d->incubatorCount != 0 && !i.shouldInterrupt());
+}
+
+/*!
+\class QQmlIncubator
+\brief The QQmlIncubator class allows QML objects to be created asynchronously.
+
+Creating QML objects - like delegates in a view, or a new page in an application - can take
+a noticable amount of time, especially on resource constrained mobile devices. When an
+application uses QQmlComponent::create() directly, the QML object instance is created
+synchronously which, depending on the complexity of the object, can cause noticable pauses or
+stutters in the application.
+
+The use of QQmlIncubator gives more control over the creation of a QML object,
+including allowing it to be created asynchronously using application idle time. The following
+example shows a simple use of QQmlIncubator.
+
+\code
+QQmlIncubator incubator;
+component->create(incubator);
+
+while (incubator.isReady()) {
+ QCoreApplication::processEvents(QEventLoop::AllEvents, 50);
+}
+
+QObject *object = incubator.object();
+\endcode
+
+Asynchronous incubators are controlled by a QQmlIncubationController that is
+set on the QQmlEngine, which lets the engine know when the application is idle and
+incubating objects should be processed. If an incubation controller is not set on the
+QQmlEngine, QQmlIncubator creates objects synchronously regardless of the
+specified IncubationMode.
+
+QQmlIncubator supports three incubation modes:
+\list
+\i Synchronous The creation occurs synchronously. That is, once the
+QQmlComponent::create() call returns, the incubator will already be in either the
+Error or Ready state. A synchronous incubator has no real advantage compared to using
+the synchronous creation methods on QQmlComponent directly, but it may simplify an
+application's implementation to use the same API for both synchronous and asynchronous
+creations.
+
+\i Asynchronous (default) The creation occurs asynchronously, assuming a
+QQmlIncubatorController is set on the QQmlEngine.
+
+The incubator will remain in the Loading state until either the creation is complete or an error
+occurs. The statusChanged() callback can be used to be notified of status changes.
+
+Applications should use the Asynchronous incubation mode to create objects that are not needed
+immediately. For example, the ListView element uses Asynchronous incubation to create objects
+that are slightly off screen while the list is being scrolled. If, during asynchronous creation,
+the object is needed immediately the QQmlIncubator::forceCompletion() method can be called
+to complete the creation process synchronously.
+
+\i AsynchronousIfNested The creation will occur asynchronously if part of a nested asynchronous
+creation, or synchronously if not.
+
+In most scenarios where a QML element or component wants the appearance of a synchronous
+instantiation, it should use this mode.
+
+This mode is best explained with an example. When the ListView element is first created, it needs
+to populate itself with an initial set of delegates to show. If the ListView was 400 pixels high,
+and each delegate was 100 pixels high, it would need to create four initial delegate instances. If
+the ListView used the Asynchronous incubation mode, the ListView would always be created empty and
+then, sometime later, the four initial elements would appear.
+
+Conversely, if the ListView was to use the Synchronous incubation mode it would behave correctly
+but it may introduce stutters into the application. As QML would have to stop and instantiate the
+ListView's delegates synchronously, if the ListView was part of a QML component that was being
+instantiated asynchronously this would undo much of the benefit of asynchronous instantiation.
+
+The AsynchronousIfNested mode reconciles this problem. By using AsynchronousIfNested, the ListView
+delegates are instantiated asynchronously if the ListView itself is already part of an asynchronous
+instantiation, and synchronously otherwise. In the case of a nested asynchronous instantiation, the
+outer asynchronous instantiation will not complete until after all the nested instantiations have also
+completed. This ensures that by the time the outer asynchronous instantitation completes, inner
+elements like ListView have already completed loading their initial delegates.
+
+It is almost always incorrect to use the Synchronous incubation mode - elements or components that
+want the appearance of synchronous instantiation, but without the downsides of introducing freezes
+or stutters into the application, should use the AsynchronousIfNested incubation mode.
+\endlist
+*/
+
+/*!
+Create a new incubator with the specified \a mode
+*/
+QQmlIncubator::QQmlIncubator(IncubationMode mode)
+: d(new QQmlIncubatorPrivate(this, mode))
+{
+}
+
+/*! \internal */
+QQmlIncubator::~QQmlIncubator()
+{
+ clear();
+
+ delete d; d = 0;
+}
+
+/*!
+\enum QQmlIncubator::IncubationMode
+
+Specifies the mode the incubator operates in. Regardless of the incubation mode, a
+QQmlIncubator will behave synchronously if the QQmlEngine does not have
+a QQmlIncubationController set.
+
+\value Asynchronous The object will be created asynchronously.
+\value AsynchronousIfNested If the object is being created in a context that is already part
+of an asynchronous creation, this incubator will join that existing incubation and execute
+asynchronously. The existing incubation will not become Ready until both it and this
+incubation have completed. Otherwise, the incubation will execute synchronously.
+\value Synchronous The object will be created synchronously.
+*/
+
+/*!
+\enum QQmlIncubator::Status
+
+Specifies the status of the QQmlIncubator.
+
+\value Null Incubation is not in progress. Call QQmlComponent::create() to begin incubating.
+\value Ready The object is fully created and can be accessed by calling object().
+\value Loading The object is in the process of being created.
+\value Error An error occurred. The errors can be access by calling errors().
+*/
+
+/*!
+Clears the incubator. Any in-progress incubation is aborted. If the incubator is in the
+Ready state, the created object is \b not deleted.
+*/
+void QQmlIncubator::clear()
+{
+ typedef QQmlIncubatorPrivate IP;
+ QRecursionWatcher<IP, &IP::recursion> watcher(d);
+
+ Status s = status();
+
+ if (s == Null)
+ return;
+
+ QQmlEnginePrivate *enginePriv = 0;
+ if (s == Loading) {
+ Q_ASSERT(d->component);
+ enginePriv = QQmlEnginePrivate::get(d->component->engine);
+ if (d->result) d->result->deleteLater();
+ d->result = 0;
+ }
+
+ d->clear();
+
+ d->vme.reset();
+ d->vmeGuard.clear();
+
+ Q_ASSERT(d->component == 0);
+ Q_ASSERT(d->waitingOnMe == 0);
+ Q_ASSERT(d->waitingFor.isEmpty());
+ Q_ASSERT(!d->nextWaitingFor.isInList());
+
+ d->errors.clear();
+ d->progress = QQmlIncubatorPrivate::Execute;
+ d->result = 0;
+
+ if (s == Loading) {
+ Q_ASSERT(enginePriv);
+
+ enginePriv->inProgressCreations--;
+ if (0 == enginePriv->inProgressCreations) {
+ while (enginePriv->erroredBindings) {
+ enginePriv->warning(enginePriv->erroredBindings->error);
+ enginePriv->erroredBindings->removeError();
+ }
+ }
+ }
+
+ d->changeStatus(Null);
+}
+
+/*!
+Force any in-progress incubation to finish synchronously. Once this call
+returns, the incubator will not be in the Loading state.
+*/
+void QQmlIncubator::forceCompletion()
+{
+ QQmlVME::Interrupt i;
+ while (Loading == status()) {
+ while (Loading == status() && !d->waitingFor.isEmpty())
+ static_cast<QQmlIncubatorPrivate *>(d->waitingFor.first())->incubate(i);
+ if (Loading == status())
+ d->incubate(i);
+ }
+}
+
+/*!
+Returns true if the incubator's status() is Null.
+*/
+bool QQmlIncubator::isNull() const
+{
+ return status() == Null;
+}
+
+/*!
+Returns true if the incubator's status() is Ready.
+*/
+bool QQmlIncubator::isReady() const
+{
+ return status() == Ready;
+}
+
+/*!
+Returns true if the incubator's status() is Error.
+*/
+bool QQmlIncubator::isError() const
+{
+ return status() == Error;
+}
+
+/*!
+Returns true if the incubator's status() is Loading.
+*/
+bool QQmlIncubator::isLoading() const
+{
+ return status() == Loading;
+}
+
+/*!
+Return the list of errors encountered while incubating the object.
+*/
+QList<QQmlError> QQmlIncubator::errors() const
+{
+ return d->errors;
+}
+
+/*!
+Return the incubation mode passed to the QQmlIncubator constructor.
+*/
+QQmlIncubator::IncubationMode QQmlIncubator::incubationMode() const
+{
+ return d->mode;
+}
+
+/*!
+Return the current status of the incubator.
+*/
+QQmlIncubator::Status QQmlIncubator::status() const
+{
+ return d->status;
+}
+
+/*!
+Return the incubated object if the status is Ready, otherwise 0.
+*/
+QObject *QQmlIncubator::object() const
+{
+ if (status() != Ready) return 0;
+ else return d->result;
+}
+
+/*!
+Called when the status of the incubator changes. \a status is the new status.
+
+The default implementation does nothing.
+*/
+void QQmlIncubator::statusChanged(Status status)
+{
+ Q_UNUSED(status);
+}
+
+/*!
+Called after the object is first created, but before property bindings are
+evaluated and, if applicable, QQmlParserStatus::componentComplete() is
+called. This is equivalent to the point between QQmlComponent::beginCreate()
+and QQmlComponent::endCreate(), and can be used to assign initial values
+to the object's properties.
+
+The default implementation does nothing.
+*/
+void QQmlIncubator::setInitialState(QObject *object)
+{
+ Q_UNUSED(object);
+}
+
+void QQmlIncubatorPrivate::changeStatus(QQmlIncubator::Status s)
+{
+ if (s == status)
+ return;
+
+ status = s;
+ q->statusChanged(status);
+}
+
+QQmlIncubator::Status QQmlIncubatorPrivate::calculateStatus() const
+{
+ if (!errors.isEmpty())
+ return QQmlIncubator::Error;
+ else if (result && progress == QQmlIncubatorPrivate::Completed &&
+ waitingFor.isEmpty())
+ return QQmlIncubator::Ready;
+ else if (component)
+ return QQmlIncubator::Loading;
+ else
+ return QQmlIncubator::Null;
+}
+
diff --git a/src/qml/qml/qqmlincubator.h b/src/qml/qml/qqmlincubator.h
new file mode 100644
index 0000000000..5d8ae7d6c3
--- /dev/null
+++ b/src/qml/qml/qqmlincubator.h
@@ -0,0 +1,129 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLINCUBATOR_H
+#define QQMLINCUBATOR_H
+
+#include <QtQml/qqmlerror.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+
+class QQmlEngine;
+
+class QQmlIncubatorPrivate;
+class Q_QML_EXPORT QQmlIncubator
+{
+ Q_DISABLE_COPY(QQmlIncubator)
+public:
+ enum IncubationMode {
+ Asynchronous,
+ AsynchronousIfNested,
+ Synchronous
+ };
+ enum Status {
+ Null,
+ Ready,
+ Loading,
+ Error
+ };
+
+ QQmlIncubator(IncubationMode = Asynchronous);
+ virtual ~QQmlIncubator();
+
+ void clear();
+ void forceCompletion();
+
+ bool isNull() const;
+ bool isReady() const;
+ bool isError() const;
+ bool isLoading() const;
+
+ QList<QQmlError> errors() const;
+
+ IncubationMode incubationMode() const;
+
+ Status status() const;
+
+ QObject *object() const;
+
+protected:
+ virtual void statusChanged(Status);
+ virtual void setInitialState(QObject *);
+
+private:
+ friend class QQmlComponent;
+ friend class QQmlEnginePrivate;
+ friend class QQmlIncubatorPrivate;
+ QQmlIncubatorPrivate *d;
+};
+
+class QQmlEnginePrivate;
+class Q_QML_EXPORT QQmlIncubationController
+{
+ Q_DISABLE_COPY(QQmlIncubationController)
+public:
+ QQmlIncubationController();
+ virtual ~QQmlIncubationController();
+
+ QQmlEngine *engine() const;
+ int incubatingObjectCount() const;
+
+ void incubateFor(int msecs);
+ void incubateWhile(bool *flag);
+
+protected:
+ virtual void incubatingObjectCountChanged(int);
+
+private:
+ friend class QQmlEngine;
+ friend class QQmlEnginePrivate;
+ friend class QQmlIncubatorPrivate;
+ QQmlEnginePrivate *d;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QQMLINCUBATOR_H
diff --git a/src/qml/qml/qqmlincubator_p.h b/src/qml/qml/qqmlincubator_p.h
new file mode 100644
index 0000000000..0dec34a8d5
--- /dev/null
+++ b/src/qml/qml/qqmlincubator_p.h
@@ -0,0 +1,106 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLINCUBATOR_P_H
+#define QQMLINCUBATOR_P_H
+
+#include <private/qintrusivelist_p.h>
+#include <private/qqmlvme_p.h>
+#include <private/qrecursionwatcher_p.h>
+#include <private/qqmlengine_p.h>
+#include <private/qqmlcontext_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.
+//
+
+QT_BEGIN_NAMESPACE
+
+class QQmlCompiledData;
+class QQmlIncubator;
+class QQmlIncubatorPrivate : public QQmlEnginePrivate::Incubator
+{
+public:
+ QQmlIncubatorPrivate(QQmlIncubator *q, QQmlIncubator::IncubationMode m);
+ ~QQmlIncubatorPrivate();
+
+ QQmlIncubator *q;
+
+ QQmlIncubator::Status calculateStatus() const;
+ void changeStatus(QQmlIncubator::Status);
+ QQmlIncubator::Status status;
+
+ QQmlIncubator::IncubationMode mode;
+ bool isAsynchronous;
+
+ QList<QQmlError> errors;
+
+ enum Progress { Execute, Completing, Completed };
+ Progress progress;
+
+ QQmlGuard<QObject> result;
+ QQmlGuardedContextData rootContext;
+ QQmlCompiledData *component;
+ QQmlVME vme;
+ QQmlVMEGuard vmeGuard;
+
+ QQmlIncubatorPrivate *waitingOnMe;
+ typedef QQmlEnginePrivate::Incubator QIPBase;
+ QIntrusiveList<QIPBase, &QIPBase::nextWaitingFor> waitingFor;
+
+ QRecursionNode recursion;
+
+ void clear();
+
+ void incubate(QQmlVME::Interrupt &i);
+};
+
+QT_END_NAMESPACE
+
+#endif // QQMLINCUBATOR_P_H
+
diff --git a/src/qml/qml/qqmlinfo.cpp b/src/qml/qml/qqmlinfo.cpp
new file mode 100644
index 0000000000..53145737d8
--- /dev/null
+++ b/src/qml/qml/qqmlinfo.cpp
@@ -0,0 +1,192 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qqmlinfo.h"
+
+#include "qqmldata_p.h"
+#include "qqmlcontext.h"
+#include "qqmlcontext_p.h"
+#include "qqmlmetatype_p.h"
+#include "qqmlengine_p.h"
+
+#include <QCoreApplication>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \fn QQmlInfo qmlInfo(const QObject *object)
+ \relates QQmlEngine
+
+ Prints warning messages that include the file and line number for the
+ specified QML \a object.
+
+ When QML types display warning messages, it improves traceability
+ if they include the QML file and line number on which the
+ particular instance was instantiated.
+
+ To include the file and line number, an object must be passed. If
+ the file and line number is not available for that instance
+ (either it was not instantiated by the QML engine or location
+ information is disabled), "unknown location" will be used instead.
+
+ For example,
+
+ \code
+ qmlInfo(object) << tr("component property is a write-once property");
+ \endcode
+
+ prints
+
+ \code
+ QML MyCustomType (unknown location): component property is a write-once property
+ \endcode
+*/
+
+class QQmlInfoPrivate
+{
+public:
+ QQmlInfoPrivate() : ref (1), object(0) {}
+
+ int ref;
+ const QObject *object;
+ QString buffer;
+ QList<QQmlError> errors;
+};
+
+QQmlInfo::QQmlInfo(QQmlInfoPrivate *p)
+: QDebug(&p->buffer), d(p)
+{
+ nospace();
+}
+
+QQmlInfo::QQmlInfo(const QQmlInfo &other)
+: QDebug(other), d(other.d)
+{
+ d->ref++;
+}
+
+QQmlInfo::~QQmlInfo()
+{
+ if (0 == --d->ref) {
+ QList<QQmlError> errors = d->errors;
+
+ QQmlEngine *engine = 0;
+
+ if (!d->buffer.isEmpty()) {
+ QQmlError error;
+
+ QObject *object = const_cast<QObject *>(d->object);
+
+ if (object) {
+ engine = qmlEngine(d->object);
+ QString typeName;
+ QQmlType *type = QQmlMetaType::qmlType(object->metaObject());
+ if (type) {
+ typeName = type->qmlTypeName();
+ int lastSlash = typeName.lastIndexOf(QLatin1Char('/'));
+ if (lastSlash != -1)
+ typeName = typeName.mid(lastSlash+1);
+ } else {
+ typeName = QString::fromUtf8(object->metaObject()->className());
+ int marker = typeName.indexOf(QLatin1String("_QMLTYPE_"));
+ if (marker != -1)
+ typeName = typeName.left(marker);
+
+ marker = typeName.indexOf(QLatin1String("_QML_"));
+ if (marker != -1) {
+ typeName = typeName.left(marker);
+ typeName += QLatin1Char('*');
+ type = QQmlMetaType::qmlType(QMetaType::type(typeName.toLatin1()));
+ if (type) {
+ typeName = type->qmlTypeName();
+ int lastSlash = typeName.lastIndexOf(QLatin1Char('/'));
+ if (lastSlash != -1)
+ typeName = typeName.mid(lastSlash+1);
+ }
+ }
+ }
+
+ d->buffer.prepend(QLatin1String("QML ") + typeName + QLatin1String(": "));
+
+ QQmlData *ddata = QQmlData::get(object, false);
+ if (ddata && ddata->outerContext && !ddata->outerContext->url.isEmpty()) {
+ error.setUrl(ddata->outerContext->url);
+ error.setLine(ddata->lineNumber);
+ error.setColumn(ddata->columnNumber);
+ }
+ }
+
+ error.setDescription(d->buffer);
+
+ errors.prepend(error);
+ }
+
+ QQmlEnginePrivate::warning(engine, errors);
+
+ delete d;
+ }
+}
+
+QQmlInfo qmlInfo(const QObject *me)
+{
+ QQmlInfoPrivate *d = new QQmlInfoPrivate;
+ d->object = me;
+ return QQmlInfo(d);
+}
+
+QQmlInfo qmlInfo(const QObject *me, const QQmlError &error)
+{
+ QQmlInfoPrivate *d = new QQmlInfoPrivate;
+ d->object = me;
+ d->errors << error;
+ return QQmlInfo(d);
+}
+
+QQmlInfo qmlInfo(const QObject *me, const QList<QQmlError> &errors)
+{
+ QQmlInfoPrivate *d = new QQmlInfoPrivate;
+ d->object = me;
+ d->errors = errors;
+ return QQmlInfo(d);
+}
+
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlinfo.h b/src/qml/qml/qqmlinfo.h
new file mode 100644
index 0000000000..92d6d72e8b
--- /dev/null
+++ b/src/qml/qml/qqmlinfo.h
@@ -0,0 +1,103 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLINFO_H
+#define QQMLINFO_H
+
+#include <QtCore/qdebug.h>
+#include <QtCore/qurl.h>
+#include <QtQml/qqmlerror.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+
+class QQmlInfoPrivate;
+class Q_QML_EXPORT QQmlInfo : public QDebug
+{
+public:
+ QQmlInfo(const QQmlInfo &);
+ ~QQmlInfo();
+
+ inline QQmlInfo &operator<<(QChar t) { QDebug::operator<<(t); return *this; }
+ inline QQmlInfo &operator<<(bool t) { QDebug::operator<<(t); return *this; }
+ inline QQmlInfo &operator<<(char t) { QDebug::operator<<(t); return *this; }
+ inline QQmlInfo &operator<<(signed short t) { QDebug::operator<<(t); return *this; }
+ inline QQmlInfo &operator<<(unsigned short t) { QDebug::operator<<(t); return *this; }
+ inline QQmlInfo &operator<<(signed int t) { QDebug::operator<<(t); return *this; }
+ inline QQmlInfo &operator<<(unsigned int t) { QDebug::operator<<(t); return *this; }
+ inline QQmlInfo &operator<<(signed long t) { QDebug::operator<<(t); return *this; }
+ inline QQmlInfo &operator<<(unsigned long t) { QDebug::operator<<(t); return *this; }
+ inline QQmlInfo &operator<<(qint64 t) { QDebug::operator<<(t); return *this; }
+ inline QQmlInfo &operator<<(quint64 t) { QDebug::operator<<(t); return *this; }
+ inline QQmlInfo &operator<<(float t) { QDebug::operator<<(t); return *this; }
+ inline QQmlInfo &operator<<(double t) { QDebug::operator<<(t); return *this; }
+ inline QQmlInfo &operator<<(const char* t) { QDebug::operator<<(t); return *this; }
+ inline QQmlInfo &operator<<(const QString & t) { QDebug::operator<<(t.toLocal8Bit().constData()); return *this; }
+ inline QQmlInfo &operator<<(const QStringRef & t) { return operator<<(t.toString()); }
+ inline QQmlInfo &operator<<(const QLatin1String &t) { QDebug::operator<<(t.latin1()); return *this; }
+ inline QQmlInfo &operator<<(const QByteArray & t) { QDebug::operator<<(t); return *this; }
+ inline QQmlInfo &operator<<(const void * t) { QDebug::operator<<(t); return *this; }
+ inline QQmlInfo &operator<<(QTextStreamFunction f) { QDebug::operator<<(f); return *this; }
+ inline QQmlInfo &operator<<(QTextStreamManipulator m) { QDebug::operator<<(m); return *this; }
+#ifndef QT_NO_DEBUG_STREAM
+ inline QQmlInfo &operator<<(const QUrl &t) { static_cast<QDebug &>(*this) << t; return *this; }
+#endif
+
+private:
+ friend Q_QML_EXPORT QQmlInfo qmlInfo(const QObject *me);
+ friend Q_QML_EXPORT QQmlInfo qmlInfo(const QObject *me, const QQmlError &error);
+ friend Q_QML_EXPORT QQmlInfo qmlInfo(const QObject *me, const QList<QQmlError> &errors);
+
+ QQmlInfo(QQmlInfoPrivate *);
+ QQmlInfoPrivate *d;
+};
+
+Q_QML_EXPORT QQmlInfo qmlInfo(const QObject *me);
+Q_QML_EXPORT QQmlInfo qmlInfo(const QObject *me, const QQmlError &error);
+Q_QML_EXPORT QQmlInfo qmlInfo(const QObject *me, const QList<QQmlError> &errors);
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QQMLINFO_H
diff --git a/src/qml/qml/qqmlinstruction.cpp b/src/qml/qml/qqmlinstruction.cpp
new file mode 100644
index 0000000000..72f04c9d61
--- /dev/null
+++ b/src/qml/qml/qqmlinstruction.cpp
@@ -0,0 +1,278 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qqmlinstruction_p.h"
+
+#include "qqmlcompiler_p.h"
+
+#include <QtCore/qdebug.h>
+
+QT_BEGIN_NAMESPACE
+
+void QQmlCompiledData::dump(QQmlInstruction *instr, int idx)
+{
+#ifdef QT_NO_DEBUG_STREAM
+ Q_UNUSED(instr)
+ Q_UNUSED(idx)
+#else
+ switch (instructionType(instr)) {
+ case QQmlInstruction::Init:
+ qWarning().nospace() << idx << "\t\t" << "INIT\t\t\t" << instr->init.bindingsSize << "\t" << instr->init.parserStatusSize << "\t" << instr->init.contextCache << "\t" << instr->init.compiledBinding;
+ break;
+ case QQmlInstruction::DeferInit:
+ qWarning().nospace() << idx << "\t\t" << "DEFER_INIT\t\t" << instr->deferInit.bindingsSize << "\t" << instr->deferInit.parserStatusSize;
+ break;
+ case QQmlInstruction::Done:
+ qWarning().nospace() << idx << "\t\t" << "DONE";
+ break;
+ case QQmlInstruction::CreateCppObject:
+ qWarning().nospace() << idx << "\t\t" << "CREATECPP\t\t\t" << instr->create.type << "\t\t\t" << types.at(instr->create.type).className;
+ break;
+ case QQmlInstruction::CreateQMLObject:
+ qWarning().nospace() << idx << "\t\t" << "CREATEQML\t\t\t" << instr->createQml.type << "\t" << instr->createQml.bindingBits << "\t\t" << types.at(instr->createQml.type).className;
+ break;
+ case QQmlInstruction::CompleteQMLObject:
+ qWarning().nospace() << idx << "\t\t" << "COMPLETEQML";
+ break;
+ case QQmlInstruction::CreateSimpleObject:
+ qWarning().nospace() << idx << "\t\t" << "CREATE_SIMPLE\t\t" << instr->createSimple.typeSize;
+ break;
+ case QQmlInstruction::SetId:
+ qWarning().nospace() << idx << "\t\t" << "SETID\t\t\t" << instr->setId.value << "\t\t\t" << primitives.at(instr->setId.value);
+ break;
+ case QQmlInstruction::SetDefault:
+ qWarning().nospace() << idx << "\t\t" << "SET_DEFAULT";
+ break;
+ case QQmlInstruction::CreateComponent:
+ qWarning().nospace() << idx << "\t\t" << "CREATE_COMPONENT\t" << instr->createComponent.count;
+ break;
+ case QQmlInstruction::StoreMetaObject:
+ qWarning().nospace() << idx << "\t\t" << "STORE_META\t\t" << instr->storeMeta.data;
+ break;
+ case QQmlInstruction::StoreFloat:
+ qWarning().nospace() << idx << "\t\t" << "STORE_FLOAT\t\t" << instr->storeFloat.propertyIndex << "\t" << instr->storeFloat.value;
+ break;
+ case QQmlInstruction::StoreDouble:
+ qWarning().nospace() << idx << "\t\t" << "STORE_DOUBLE\t\t" << instr->storeDouble.propertyIndex << "\t" << instr->storeDouble.value;
+ break;
+ case QQmlInstruction::StoreDoubleQList:
+ qWarning().nospace() << idx << "\t\t" << "STORE_DOUBLE_QLIST\t\t" << instr->storeDouble.propertyIndex << "\t" << instr->storeDouble.value;
+ break;
+ case QQmlInstruction::StoreInteger:
+ qWarning().nospace() << idx << "\t\t" << "STORE_INTEGER\t\t" << instr->storeInteger.propertyIndex << "\t" << instr->storeInteger.value;
+ break;
+ case QQmlInstruction::StoreIntegerQList:
+ qWarning().nospace() << idx << "\t\t" << "STORE_INTEGER_QLIST\t\t" << instr->storeInteger.propertyIndex << "\t" << instr->storeInteger.value;
+ break;
+ case QQmlInstruction::StoreBool:
+ qWarning().nospace() << idx << "\t\t" << "STORE_BOOL\t\t" << instr->storeBool.propertyIndex << "\t" << instr->storeBool.value;
+ break;
+ case QQmlInstruction::StoreBoolQList:
+ qWarning().nospace() << idx << "\t\t" << "STORE_BOOL_QLIST\t\t" << instr->storeBool.propertyIndex << "\t" << instr->storeBool.value;
+ break;
+ case QQmlInstruction::StoreString:
+ qWarning().nospace() << idx << "\t\t" << "STORE_STRING\t\t" << instr->storeString.propertyIndex << "\t" << instr->storeString.value << "\t\t" << primitives.at(instr->storeString.value);
+ break;
+ case QQmlInstruction::StoreStringList:
+ qWarning().nospace() << idx << "\t\t" << "STORE_STRINGLIST\t\t" << instr->storeString.propertyIndex << "\t" << instr->storeString.value << "\t\t" << primitives.at(instr->storeString.value);
+ break;
+ case QQmlInstruction::StoreStringQList:
+ qWarning().nospace() << idx << "\t\t" << "STORE_STRING_QLIST\t\t" << instr->storeString.propertyIndex << "\t" << instr->storeString.value << "\t\t" << primitives.at(instr->storeString.value);
+ break;
+ case QQmlInstruction::StoreTrString:
+ qWarning().nospace() << idx << "\t\t" << "STORE_TR_STRING\t" << instr->storeTrString.propertyIndex << "\t" << instr->storeTrString.context << "\t" << instr->storeTrString.text << "\t" << instr->storeTrString.comment << "\t" << instr->storeTrString.n;
+ break;
+ case QQmlInstruction::StoreTrIdString:
+ qWarning().nospace() << idx << "\t\t" << "STORE_TRID_STRING\t" << instr->storeTrIdString.propertyIndex << "\t" << instr->storeTrIdString.text << "\t" << instr->storeTrIdString.n;
+ break;
+ case QQmlInstruction::StoreByteArray:
+ qWarning().nospace() << idx << "\t\t" << "STORE_BYTEARRAY" << instr->storeByteArray.propertyIndex << "\t" << instr->storeByteArray.value << "\t\t" << datas.at(instr->storeByteArray.value);
+ break;
+ case QQmlInstruction::StoreUrl:
+ qWarning().nospace() << idx << "\t\t" << "STORE_URL\t\t" << instr->storeUrl.propertyIndex << "\t" << instr->storeUrl.value << "\t\t" << urls.at(instr->storeUrl.value);
+ break;
+ case QQmlInstruction::StoreUrlQList:
+ qWarning().nospace() << idx << "\t\t" << "STORE_URL_QLIST\t\t" << instr->storeUrl.propertyIndex << "\t" << instr->storeUrl.value << "\t\t" << urls.at(instr->storeUrl.value);
+ break;
+ case QQmlInstruction::StoreColor:
+ qWarning().nospace() << idx << "\t\t" << "STORE_COLOR\t\t" << instr->storeColor.propertyIndex << "\t\t\t" << QString::number(instr->storeColor.value, 16);
+ break;
+ case QQmlInstruction::StoreDate:
+ qWarning().nospace() << idx << "\t\t" << "STORE_DATE\t\t" << instr->storeDate.propertyIndex << "\t" << instr->storeDate.value;
+ break;
+ case QQmlInstruction::StoreTime:
+ qWarning().nospace() << idx << "\t\t" << "STORE_TIME\t\t" << instr->storeTime.propertyIndex;
+ break;
+ case QQmlInstruction::StoreDateTime:
+ qWarning().nospace() << idx << "\t\t" << "STORE_DATETIME\t\t" << instr->storeDateTime.propertyIndex;
+ break;
+ case QQmlInstruction::StorePoint:
+ qWarning().nospace() << idx << "\t\t" << "STORE_POINT\t\t" << instr->storePoint.propertyIndex << "\t" << instr->storePoint.point.xp << "\t" << instr->storePoint.point.yp;
+ break;
+ case QQmlInstruction::StorePointF:
+ qWarning().nospace() << idx << "\t\t" << "STORE_POINTF\t\t" << instr->storePointF.propertyIndex << "\t" << instr->storePointF.point.xp << "\t" << instr->storePointF.point.yp;
+ break;
+ case QQmlInstruction::StoreSize:
+ qWarning().nospace() << idx << "\t\t" << "STORE_SIZE\t\t" << instr->storeSize.propertyIndex << "\t" << instr->storeSize.size.wd << "\t" << instr->storeSize.size.ht;
+ break;
+ case QQmlInstruction::StoreSizeF:
+ qWarning().nospace() << idx << "\t\t" << "STORE_SIZEF\t\t" << instr->storeSizeF.propertyIndex << "\t" << instr->storeSizeF.size.wd << "\t" << instr->storeSizeF.size.ht;
+ break;
+ case QQmlInstruction::StoreRect:
+ qWarning().nospace() << idx << "\t\t" << "STORE_RECT\t\t" << instr->storeRect.propertyIndex << "\t" << instr->storeRect.rect.x1 << "\t" << instr->storeRect.rect.y1 << "\t" << instr->storeRect.rect.x2 << "\t" << instr->storeRect.rect.y2;
+ break;
+ case QQmlInstruction::StoreRectF:
+ qWarning().nospace() << idx << "\t\t" << "STORE_RECTF\t\t" << instr->storeRectF.propertyIndex << "\t" << instr->storeRectF.rect.xp << "\t" << instr->storeRectF.rect.yp << "\t" << instr->storeRectF.rect.w << "\t" << instr->storeRectF.rect.h;
+ break;
+ case QQmlInstruction::StoreVector3D:
+ qWarning().nospace() << idx << "\t\t" << "STORE_VECTOR3D\t\t" << instr->storeVector3D.propertyIndex << "\t" << instr->storeVector3D.vector.xp << "\t" << instr->storeVector3D.vector.yp << "\t" << instr->storeVector3D.vector.zp;
+ break;
+ case QQmlInstruction::StoreVector4D:
+ qWarning().nospace() << idx << "\t\t" << "STORE_VECTOR4D\t\t" << instr->storeVector4D.propertyIndex << "\t" << instr->storeVector4D.vector.xp << "\t" << instr->storeVector4D.vector.yp << "\t" << instr->storeVector4D.vector.zp << "\t" << instr->storeVector4D.vector.wp;
+ break;
+ case QQmlInstruction::StoreVariant:
+ qWarning().nospace() << idx << "\t\t" << "STORE_VARIANT\t\t" << instr->storeString.propertyIndex << "\t" << instr->storeString.value << "\t\t" << primitives.at(instr->storeString.value);
+ break;
+ case QQmlInstruction::StoreVariantInteger:
+ qWarning().nospace() << idx << "\t\t" << "STORE_VARIANT_INTEGER\t\t" << instr->storeInteger.propertyIndex << "\t" << instr->storeInteger.value;
+ break;
+ case QQmlInstruction::StoreVariantDouble:
+ qWarning().nospace() << idx << "\t\t" << "STORE_VARIANT_DOUBLE\t\t" << instr->storeDouble.propertyIndex << "\t" << instr->storeDouble.value;
+ break;
+ case QQmlInstruction::StoreVariantBool:
+ qWarning().nospace() << idx << "\t\t" << "STORE_VARIANT_BOOL\t\t" << instr->storeBool.propertyIndex << "\t" << instr->storeBool.value;
+ break;
+ case QQmlInstruction::StoreObject:
+ qWarning().nospace() << idx << "\t\t" << "STORE_OBJECT\t\t" << instr->storeObject.propertyIndex;
+ break;
+ case QQmlInstruction::StoreVariantObject:
+ qWarning().nospace() << idx << "\t\t" << "STORE_VARIANT_OBJECT\t" << instr->storeObject.propertyIndex;
+ break;
+ case QQmlInstruction::StoreInterface:
+ qWarning().nospace() << idx << "\t\t" << "STORE_INTERFACE\t\t" << instr->storeObject.propertyIndex;
+ break;
+ case QQmlInstruction::StoreSignal:
+ qWarning().nospace() << idx << "\t\t" << "STORE_SIGNAL\t\t" << instr->storeSignal.signalIndex << "\t" << instr->storeSignal.value << "\t\t" << primitives.at(instr->storeSignal.value);
+ break;
+ case QQmlInstruction::StoreImportedScript:
+ qWarning().nospace() << idx << "\t\t" << "STORE_IMPORTED_SCRIPT\t" << instr->storeScript.value;
+ break;
+ case QQmlInstruction::StoreScriptString:
+ qWarning().nospace() << idx << "\t\t" << "STORE_SCRIPT_STRING\t" << instr->storeScriptString.propertyIndex << "\t" << instr->storeScriptString.value << "\t" << instr->storeScriptString.scope << "\t" << instr->storeScriptString.bindingId;
+ break;
+ case QQmlInstruction::AssignSignalObject:
+ qWarning().nospace() << idx << "\t\t" << "ASSIGN_SIGNAL_OBJECT\t" << instr->assignSignalObject.signal << "\t\t\t" << primitives.at(instr->assignSignalObject.signal);
+ break;
+ case QQmlInstruction::AssignCustomType:
+ qWarning().nospace() << idx << "\t\t" << "ASSIGN_CUSTOMTYPE\t" << instr->assignCustomType.propertyIndex << "\t" << instr->assignCustomType.primitive << "\t" << instr->assignCustomType.type;
+ break;
+ case QQmlInstruction::InitV8Bindings:
+ qWarning().nospace() << idx << "\t\t" << "INIT_V8_BINDING\t" << instr->initV8Bindings.programIndex << "\t" << instr->initV8Bindings.line;
+ break;
+ case QQmlInstruction::StoreBinding:
+ qWarning().nospace() << idx << "\t\t" << "STORE_BINDING\t" << instr->assignBinding.property.coreIndex << "\t" << instr->assignBinding.value << "\t" << instr->assignBinding.context;
+ break;
+ case QQmlInstruction::StoreBindingOnAlias:
+ qWarning().nospace() << idx << "\t\t" << "STORE_BINDING_ALIAS\t" << instr->assignBinding.property.coreIndex << "\t" << instr->assignBinding.value << "\t" << instr->assignBinding.context;
+ break;
+ case QQmlInstruction::StoreV4Binding:
+ qWarning().nospace() << idx << "\t\t" << "STORE_COMPILED_BINDING\t" << instr->assignV4Binding.property << "\t" << instr->assignV4Binding.value << "\t" << instr->assignV4Binding.context;
+ break;
+ case QQmlInstruction::StoreV8Binding:
+ qWarning().nospace() << idx << "\t\t" << "STORE_V8_BINDING\t" << instr->assignBinding.property.coreIndex << "\t" << instr->assignBinding.value << "\t" << instr->assignBinding.context;
+ break;
+ case QQmlInstruction::StoreValueSource:
+ qWarning().nospace() << idx << "\t\t" << "STORE_VALUE_SOURCE\t" << instr->assignValueSource.property.coreIndex << "\t" << instr->assignValueSource.castValue;
+ break;
+ case QQmlInstruction::StoreValueInterceptor:
+ qWarning().nospace() << idx << "\t\t" << "STORE_VALUE_INTERCEPTOR\t" << instr->assignValueInterceptor.property.coreIndex << "\t" << instr->assignValueInterceptor.castValue;
+ break;
+ case QQmlInstruction::BeginObject:
+ qWarning().nospace() << idx << "\t\t" << "BEGIN\t\t\t" << instr->begin.castValue;
+ break;
+ case QQmlInstruction::StoreObjectQList:
+ qWarning().nospace() << idx << "\t\t" << "STORE_OBJECT_QLIST";
+ break;
+ case QQmlInstruction::AssignObjectList:
+ qWarning().nospace() << idx << "\t\t" << "ASSIGN_OBJECT_LIST";
+ break;
+ case QQmlInstruction::FetchAttached:
+ qWarning().nospace() << idx << "\t\t" << "FETCH_ATTACHED\t\t" << instr->fetchAttached.id;
+ break;
+ case QQmlInstruction::FetchQList:
+ qWarning().nospace() << idx << "\t\t" << "FETCH_QLIST\t\t" << instr->fetch.property;
+ break;
+ case QQmlInstruction::FetchObject:
+ qWarning().nospace() << idx << "\t\t" << "FETCH\t\t\t" << instr->fetch.property;
+ break;
+ case QQmlInstruction::FetchValueType:
+ qWarning().nospace() << idx << "\t\t" << "FETCH_VALUE\t\t" << instr->fetchValue.property << "\t" << instr->fetchValue.type << "\t" << instr->fetchValue.bindingSkipList;
+ break;
+ case QQmlInstruction::PopFetchedObject:
+ qWarning().nospace() << idx << "\t\t" << "POP";
+ break;
+ case QQmlInstruction::PopQList:
+ qWarning().nospace() << idx << "\t\t" << "POP_QLIST";
+ break;
+ case QQmlInstruction::PopValueType:
+ qWarning().nospace() << idx << "\t\t" << "POP_VALUE\t\t" << instr->fetchValue.property << "\t" << instr->fetchValue.type;
+ break;
+ case QQmlInstruction::Defer:
+ qWarning().nospace() << idx << "\t\t" << "DEFER" << "\t\t\t" << instr->defer.deferCount;
+ break;
+ default:
+ qWarning().nospace() << idx << "\t\t" << "XXX UNKNOWN INSTRUCTION" << "\t" << instructionType(instr);
+ break;
+ }
+#endif // QT_NO_DEBUG_STREAM
+}
+
+int QQmlInstruction::size(Type type)
+{
+#define QML_RETURN_INSTR_SIZE(I, FMT) case I: return QQmlInstructionMeta<(int)I>::Size;
+ switch (type) {
+ FOR_EACH_QML_INSTR(QML_RETURN_INSTR_SIZE)
+ default: return 0;
+ }
+#undef QML_RETURN_INSTR_SIZE
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlinstruction_p.h b/src/qml/qml/qqmlinstruction_p.h
new file mode 100644
index 0000000000..b7533aca68
--- /dev/null
+++ b/src/qml/qml/qqmlinstruction_p.h
@@ -0,0 +1,558 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLINSTRUCTION_P_H
+#define QQMLINSTRUCTION_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qglobal.h>
+#include <private/qqmlpropertycache_p.h>
+
+QT_BEGIN_NAMESPACE
+
+#define FOR_EACH_QML_INSTR(F) \
+ F(Init, init) \
+ F(DeferInit, deferInit) \
+ F(Done, common) \
+ F(CreateCppObject, create) \
+ F(CreateQMLObject, createQml) \
+ F(CompleteQMLObject, completeQml) \
+ F(CreateSimpleObject, createSimple) \
+ F(SetId, setId) \
+ F(SetDefault, common) \
+ F(CreateComponent, createComponent) \
+ F(StoreMetaObject, storeMeta) \
+ F(StoreVariant, storeString) \
+ F(StoreVariantInteger, storeInteger) \
+ F(StoreVariantDouble, storeDouble) \
+ F(StoreVariantBool, storeBool) \
+ F(StoreVar, storeString) \
+ F(StoreVarInteger, storeInteger) \
+ F(StoreVarDouble, storeDouble) \
+ F(StoreVarBool, storeBool) \
+ F(StoreString, storeString) \
+ F(StoreStringList, storeString) \
+ F(StoreStringQList, storeString) \
+ F(StoreTrString, storeTrString) \
+ F(StoreTrIdString, storeTrIdString) \
+ F(StoreByteArray, storeByteArray) \
+ F(StoreUrl, storeUrl) \
+ F(StoreUrlQList, storeUrl) \
+ F(StoreFloat, storeFloat) \
+ F(StoreDouble, storeDouble) \
+ F(StoreDoubleQList, storeDouble) \
+ F(StoreBool, storeBool) \
+ F(StoreBoolQList, storeBool) \
+ F(StoreInteger, storeInteger) \
+ F(StoreIntegerQList, storeInteger) \
+ F(StoreColor, storeColor) \
+ F(StoreDate, storeDate) \
+ F(StoreTime, storeTime) \
+ F(StoreDateTime, storeDateTime) \
+ F(StorePoint, storePoint) \
+ F(StorePointF, storePointF) \
+ F(StoreSize, storeSize) \
+ F(StoreSizeF, storeSizeF) \
+ F(StoreRect, storeRect) \
+ F(StoreRectF, storeRectF) \
+ F(StoreVector3D, storeVector3D) \
+ F(StoreVector4D, storeVector4D) \
+ F(StoreObject, storeObject) \
+ F(AssignCustomType, assignCustomType) \
+ F(AssignSignalObject, assignSignalObject) \
+ F(StoreSignal, storeSignal) \
+ F(StoreImportedScript, storeScript) \
+ F(StoreScriptString, storeScriptString) \
+ F(BeginObject, begin) \
+ F(InitV8Bindings, initV8Bindings) \
+ F(StoreBinding, assignBinding) \
+ F(StoreBindingOnAlias, assignBinding) \
+ F(StoreV8Binding, assignBinding) \
+ F(StoreV4Binding, assignV4Binding) \
+ F(StoreValueSource, assignValueSource) \
+ F(StoreValueInterceptor, assignValueInterceptor) \
+ F(StoreObjectQList, common) \
+ F(AssignObjectList, assignObjectList) \
+ F(StoreVariantObject, storeObject) \
+ F(StoreVarObject, storeObject) \
+ F(StoreInterface, storeObject) \
+ F(FetchAttached, fetchAttached) \
+ F(FetchQList, fetchQmlList) \
+ F(FetchObject, fetch) \
+ F(PopQList, common) \
+ F(Defer, defer) \
+ F(PopFetchedObject, common) \
+ F(FetchValueType, fetchValue) \
+ F(PopValueType, fetchValue)
+
+#if defined(Q_CC_GNU) && (!defined(Q_CC_INTEL) || __INTEL_COMPILER >= 1200)
+# define QML_THREADED_VME_INTERPRETER
+#endif
+
+#ifdef Q_ALIGNOF
+# define QML_INSTR_ALIGN_MASK (Q_ALIGNOF(QQmlInstruction) - 1)
+#else
+# define QML_INSTR_ALIGN_MASK (sizeof(void *) - 1)
+#endif
+
+#ifdef QML_THREADED_VME_INTERPRETER
+# define QML_INSTR_HEADER void *code;
+#else
+# define QML_INSTR_HEADER quint8 instructionType;
+#endif
+
+#define QML_INSTR_ENUM(I, FMT) I,
+#define QML_INSTR_SIZE(I, FMT) ((sizeof(QQmlInstruction::instr_##FMT) + QML_INSTR_ALIGN_MASK) & ~QML_INSTR_ALIGN_MASK)
+
+class QQmlCompiledData;
+union QQmlInstruction
+{
+ enum Type {
+ FOR_EACH_QML_INSTR(QML_INSTR_ENUM)
+ };
+
+ struct instr_common {
+ QML_INSTR_HEADER
+ };
+ struct instr_init {
+ QML_INSTR_HEADER
+ int bindingsSize;
+ int parserStatusSize;
+ int contextCache;
+ int compiledBinding;
+ int objectStackSize;
+ int listStackSize;
+ };
+ struct instr_deferInit {
+ QML_INSTR_HEADER
+ int bindingsSize;
+ int parserStatusSize;
+ int objectStackSize;
+ int listStackSize;
+ };
+ struct instr_createQml {
+ QML_INSTR_HEADER
+ int type;
+ int bindingBits;
+ bool isRoot;
+ };
+ struct instr_completeQml {
+ QML_INSTR_HEADER
+ ushort column;
+ ushort line;
+ bool isRoot;
+ };
+ struct instr_create {
+ QML_INSTR_HEADER
+ int type;
+ int data;
+ ushort column;
+ ushort line;
+ bool isRoot;
+ };
+ struct instr_createSimple {
+ QML_INSTR_HEADER
+ void (*create)(void *);
+ int typeSize;
+ int type;
+ ushort column;
+ ushort line;
+ };
+ struct instr_storeMeta {
+ QML_INSTR_HEADER
+ int data;
+ int aliasData;
+ int propertyCache;
+ };
+ struct instr_setId {
+ QML_INSTR_HEADER
+ int value;
+ int index;
+ };
+ struct instr_assignValueSource {
+ QML_INSTR_HEADER
+ QQmlPropertyRawData property;
+ int owner;
+ int castValue;
+ };
+ struct instr_assignValueInterceptor {
+ QML_INSTR_HEADER
+ QQmlPropertyRawData property;
+ int owner;
+ int castValue;
+ };
+ struct instr_initV8Bindings {
+ QML_INSTR_HEADER
+ ushort programIndex;
+ ushort line;
+ };
+ struct instr_assignV4Binding {
+ QML_INSTR_HEADER
+ unsigned int property;
+ int value;
+ short context;
+ short owner;
+ bool isRoot;
+ ushort line;
+ ushort column;
+ };
+ struct instr_assignBinding {
+ QML_INSTR_HEADER
+ QQmlPropertyRawData property;
+ int value;
+ short context;
+ short owner;
+ bool isRoot;
+ ushort line;
+ ushort column;
+ };
+ struct instr_fetch {
+ QML_INSTR_HEADER
+ int property;
+ ushort line;
+ };
+ struct instr_fetchValue {
+ QML_INSTR_HEADER
+ int property;
+ int type;
+ quint32 bindingSkipList;
+ };
+ struct instr_fetchQmlList {
+ QML_INSTR_HEADER
+ int property;
+ int type;
+ };
+ struct instr_begin {
+ QML_INSTR_HEADER
+ int castValue;
+ };
+ struct instr_storeFloat {
+ QML_INSTR_HEADER
+ int propertyIndex;
+ float value;
+ };
+ struct instr_storeDouble {
+ QML_INSTR_HEADER
+ int propertyIndex;
+ double value;
+ };
+ struct instr_storeInteger {
+ QML_INSTR_HEADER
+ int propertyIndex;
+ int value;
+ };
+ struct instr_storeBool {
+ QML_INSTR_HEADER
+ int propertyIndex;
+ bool value;
+ };
+ struct instr_storeString {
+ QML_INSTR_HEADER
+ int propertyIndex;
+ int value;
+ };
+ struct instr_storeTrString {
+ QML_INSTR_HEADER
+ int propertyIndex;
+ int context;
+ int text;
+ int comment;
+ int n;
+ };
+ struct instr_storeTrIdString {
+ QML_INSTR_HEADER
+ int propertyIndex;
+ int text;
+ int n;
+ };
+ struct instr_storeByteArray {
+ QML_INSTR_HEADER
+ int propertyIndex;
+ int value;
+ };
+ struct instr_storeScriptString {
+ QML_INSTR_HEADER
+ int propertyIndex;
+ int value;
+ int scope;
+ int bindingId;
+ ushort line;
+ ushort column;
+ };
+ struct instr_storeScript {
+ QML_INSTR_HEADER
+ int value;
+ };
+ struct instr_storeUrl {
+ QML_INSTR_HEADER
+ int propertyIndex;
+ int value;
+ };
+ struct instr_storeColor {
+ QML_INSTR_HEADER
+ int propertyIndex;
+ unsigned int value;
+ };
+ struct instr_storeDate {
+ QML_INSTR_HEADER
+ int propertyIndex;
+ int value;
+ };
+ struct instr_storeTime {
+ QML_INSTR_HEADER
+ int propertyIndex;
+ struct QTime {
+ int mds;
+#if defined(Q_OS_WINCE)
+ int startTick;
+#endif
+ } time;
+ };
+ struct instr_storeDateTime {
+ QML_INSTR_HEADER
+ int propertyIndex;
+ int date;
+ instr_storeTime::QTime time;
+ };
+ struct instr_storeRect {
+ QML_INSTR_HEADER
+ int propertyIndex;
+ struct QRect {
+ int x1;
+ int y1;
+ int x2;
+ int y2;
+ } rect;
+ };
+ struct instr_storeRectF {
+ QML_INSTR_HEADER
+ int propertyIndex;
+ struct QRectF {
+ qreal xp;
+ qreal yp;
+ qreal w;
+ qreal h;
+ } rect;
+ };
+ struct instr_storeObject {
+ QML_INSTR_HEADER
+ int propertyIndex;
+ ushort line;
+ };
+ struct instr_assignCustomType {
+ QML_INSTR_HEADER
+ int propertyIndex;
+ int primitive;
+ int type;
+ ushort line;
+ };
+ struct instr_storeSignal {
+ QML_INSTR_HEADER
+ int signalIndex;
+ int value;
+ short context;
+ ushort line;
+ ushort column;
+ };
+ struct instr_assignSignalObject {
+ QML_INSTR_HEADER
+ int signal;
+ ushort line;
+ };
+ struct instr_createComponent {
+ QML_INSTR_HEADER
+ int count;
+ int endLine;
+ int metaObject;
+ ushort column;
+ ushort line;
+ bool isRoot;
+ };
+ struct instr_fetchAttached {
+ QML_INSTR_HEADER
+ int id;
+ ushort line;
+ };
+ struct instr_defer {
+ QML_INSTR_HEADER
+ int deferCount;
+ };
+ struct instr_assignObjectList {
+ QML_INSTR_HEADER
+ ushort line;
+ };
+ struct instr_storePoint {
+ QML_INSTR_HEADER
+ int propertyIndex;
+ struct QPoint {
+ int xp;
+ int yp;
+ } point;
+ };
+ struct instr_storePointF {
+ QML_INSTR_HEADER
+ int propertyIndex;
+ struct QPointF {
+ qreal xp;
+ qreal yp;
+ } point;
+ };
+ struct instr_storeSize {
+ QML_INSTR_HEADER
+ int propertyIndex;
+ struct QSize {
+ int wd;
+ int ht;
+ } size;
+ };
+ struct instr_storeSizeF {
+ QML_INSTR_HEADER
+ int propertyIndex;
+ struct QSizeF {
+ qreal wd;
+ qreal ht;
+ } size;
+ };
+ struct instr_storeVector3D {
+ QML_INSTR_HEADER
+ int propertyIndex;
+ struct QVector3D {
+ float xp;
+ float yp;
+ float zp;
+ } vector;
+ };
+ struct instr_storeVector4D {
+ QML_INSTR_HEADER
+ int propertyIndex;
+ struct QVector4D {
+ float xp;
+ float yp;
+ float zp;
+ float wp;
+ } vector;
+ };
+
+ instr_common common;
+ instr_init init;
+ instr_deferInit deferInit;
+ instr_create create;
+ instr_createQml createQml;
+ instr_completeQml completeQml;
+ instr_createSimple createSimple;
+ instr_storeMeta storeMeta;
+ instr_setId setId;
+ instr_assignValueSource assignValueSource;
+ instr_assignValueInterceptor assignValueInterceptor;
+ instr_initV8Bindings initV8Bindings;
+ instr_assignV4Binding assignV4Binding;
+ instr_assignBinding assignBinding;
+ instr_fetch fetch;
+ instr_fetchValue fetchValue;
+ instr_fetchQmlList fetchQmlList;
+ instr_begin begin;
+ instr_storeFloat storeFloat;
+ instr_storeDouble storeDouble;
+ instr_storeInteger storeInteger;
+ instr_storeBool storeBool;
+ instr_storeString storeString;
+ instr_storeTrString storeTrString;
+ instr_storeTrIdString storeTrIdString;
+ instr_storeByteArray storeByteArray;
+ instr_storeScriptString storeScriptString;
+ instr_storeScript storeScript;
+ instr_storeUrl storeUrl;
+ instr_storeColor storeColor;
+ instr_storeDate storeDate;
+ instr_storeTime storeTime;
+ instr_storeDateTime storeDateTime;
+ instr_storePoint storePoint;
+ instr_storePointF storePointF;
+ instr_storeSize storeSize;
+ instr_storeSizeF storeSizeF;
+ instr_storeRect storeRect;
+ instr_storeRectF storeRectF;
+ instr_storeVector3D storeVector3D;
+ instr_storeVector4D storeVector4D;
+ instr_storeObject storeObject;
+ instr_assignCustomType assignCustomType;
+ instr_storeSignal storeSignal;
+ instr_assignSignalObject assignSignalObject;
+ instr_createComponent createComponent;
+ instr_fetchAttached fetchAttached;
+ instr_defer defer;
+ instr_assignObjectList assignObjectList;
+
+ static int size(Type type);
+};
+
+template<int N>
+struct QQmlInstructionMeta {
+};
+
+#define QML_INSTR_META_TEMPLATE(I, FMT) \
+ template<> struct QQmlInstructionMeta<(int)QQmlInstruction::I> { \
+ 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; } \
+ };
+FOR_EACH_QML_INSTR(QML_INSTR_META_TEMPLATE);
+#undef QML_INSTR_META_TEMPLATE
+
+template<int Instr>
+class QQmlInstructionData : public QQmlInstructionMeta<Instr>::DataType
+{
+};
+
+QT_END_NAMESPACE
+
+#endif // QQMLINSTRUCTION_P_H
diff --git a/src/qml/qml/qqmlintegercache.cpp b/src/qml/qml/qqmlintegercache.cpp
new file mode 100644
index 0000000000..88ea3af2de
--- /dev/null
+++ b/src/qml/qml/qqmlintegercache.cpp
@@ -0,0 +1,82 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qqmlintegercache_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QQmlIntegerCache::QQmlIntegerCache()
+{
+}
+
+QQmlIntegerCache::~QQmlIntegerCache()
+{
+}
+
+QString QQmlIntegerCache::findId(int value) const
+{
+ for (StringCache::ConstIterator iter = stringCache.begin();
+ iter != stringCache.end(); ++iter) {
+ if (iter.value() == value)
+ return iter.key();
+ }
+ return QString();
+}
+
+void QQmlIntegerCache::reserve(int size)
+{
+ stringCache.reserve(size);
+}
+
+void QQmlIntegerCache::add(const QString &id, int value)
+{
+ Q_ASSERT(!stringCache.contains(id));
+
+ stringCache.insert(id, value);
+}
+
+int QQmlIntegerCache::value(const QString &id)
+{
+ int *rv = stringCache.value(id);
+ return rv?*rv:-1;
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlintegercache_p.h b/src/qml/qml/qqmlintegercache_p.h
new file mode 100644
index 0000000000..317a86b45a
--- /dev/null
+++ b/src/qml/qml/qqmlintegercache_p.h
@@ -0,0 +1,97 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLINTEGERCACHE_P_H
+#define QQMLINTEGERCACHE_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qqmlrefcount_p.h>
+#include <private/qhashedstring_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQmlType;
+class QQmlEngine;
+class QQmlIntegerCache : public QQmlRefCount
+{
+public:
+ QQmlIntegerCache();
+ virtual ~QQmlIntegerCache();
+
+ inline int count() const;
+ void add(const QString &, int);
+ void reserve(int);
+
+ int value(const QString &);
+ inline int value(const QHashedV8String &);
+
+ QString findId(int value) const;
+
+private:
+ typedef QStringHash<int> StringCache;
+ StringCache stringCache;
+};
+
+int QQmlIntegerCache::value(const QHashedV8String &name)
+{
+ int *result = stringCache.value(name);
+ return result?*result:-1;
+}
+
+int QQmlIntegerCache::count() const
+{
+ return stringCache.count();
+}
+
+QT_END_NAMESPACE
+
+#endif // QQMLINTEGERCACHE_P_H
+
diff --git a/src/qml/qml/qqmllist.cpp b/src/qml/qml/qqmllist.cpp
new file mode 100644
index 0000000000..00fd805ee0
--- /dev/null
+++ b/src/qml/qml/qqmllist.cpp
@@ -0,0 +1,417 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qqmllist.h"
+#include "qqmllist_p.h"
+#include "qqmlengine_p.h"
+#include "qqmlproperty_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QQmlListReferencePrivate::QQmlListReferencePrivate()
+: propertyType(-1), refCount(1)
+{
+}
+
+QQmlListReference QQmlListReferencePrivate::init(const QQmlListProperty<QObject> &prop, int propType, QQmlEngine *engine)
+{
+ QQmlListReference rv;
+
+ if (!prop.object) return rv;
+
+ QQmlEnginePrivate *p = engine?QQmlEnginePrivate::get(engine):0;
+
+ int listType = p?p->listType(propType):QQmlMetaType::listType(propType);
+ if (listType == -1) return rv;
+
+ rv.d = new QQmlListReferencePrivate;
+ rv.d->object = prop.object;
+ rv.d->elementType = p?p->rawMetaObjectForType(listType):QQmlMetaType::qmlType(listType)->baseMetaObject();
+ rv.d->property = prop;
+ rv.d->propertyType = propType;
+
+ return rv;
+}
+
+void QQmlListReferencePrivate::addref()
+{
+ Q_ASSERT(refCount > 0);
+ ++refCount;
+}
+
+void QQmlListReferencePrivate::release()
+{
+ Q_ASSERT(refCount > 0);
+ --refCount;
+ if (!refCount)
+ delete this;
+}
+
+/*!
+\class QQmlListReference
+\since 4.7
+\module QtQml
+\brief The QQmlListReference class allows the manipulation of QQmlListProperty properties.
+
+QQmlListReference allows C++ programs to read from, and assign values to a QML list property in a
+simple and type safe way. A QQmlListReference can be created by passing an object and property
+name or through a QQmlProperty instance. These two are equivalant:
+
+\code
+QQmlListReference ref1(object, "children");
+
+QQmlProperty ref2(object, "children");
+QQmlListReference ref2 = qvariant_cast<QQmlListReference>(ref2.read());
+\endcode
+
+Not all QML list properties support all operations. A set of methods, canAppend(), canAt(), canClear() and
+canCount() allow programs to query whether an operation is supported on a given property.
+
+QML list properties are typesafe. Only QObject's that derive from the correct base class can be assigned to
+the list. The listElementType() method can be used to query the QMetaObject of the QObject type supported.
+Attempting to add objects of the incorrect type to a list property will fail.
+
+Like with normal lists, when accessing a list element by index, it is the callers responsibility to ensure
+that it does not request an out of range element using the count() method before calling at().
+*/
+
+/*!
+Constructs an invalid instance.
+*/
+QQmlListReference::QQmlListReference()
+: d(0)
+{
+}
+
+/*!
+Constructs a QQmlListReference for \a object's \a property. If \a property is not a list
+property, an invalid QQmlListReference is created. If \a object is destroyed after
+the reference is constructed, it will automatically become invalid. That is, it is safe to hold
+QQmlListReference instances even after \a object is deleted.
+
+Passing \a engine is required to access some QML created list properties. If in doubt, and an engine
+is available, pass it.
+*/
+QQmlListReference::QQmlListReference(QObject *object, const char *property, QQmlEngine *engine)
+: d(0)
+{
+ if (!object || !property) return;
+
+ QQmlPropertyData local;
+ QQmlPropertyData *data =
+ QQmlPropertyCache::property(engine, object, QLatin1String(property), local);
+
+ if (!data || !data->isQList()) return;
+
+ QQmlEnginePrivate *p = engine?QQmlEnginePrivate::get(engine):0;
+
+ int listType = p?p->listType(data->propType):QQmlMetaType::listType(data->propType);
+ if (listType == -1) return;
+
+ d = new QQmlListReferencePrivate;
+ d->object = object;
+ d->elementType = p?p->rawMetaObjectForType(listType):QQmlMetaType::qmlType(listType)->baseMetaObject();
+ d->propertyType = data->propType;
+
+ void *args[] = { &d->property, 0 };
+ QMetaObject::metacall(object, QMetaObject::ReadProperty, data->coreIndex, args);
+}
+
+/*! \internal */
+QQmlListReference::QQmlListReference(const QQmlListReference &o)
+: d(o.d)
+{
+ if (d) d->addref();
+}
+
+/*! \internal */
+QQmlListReference &QQmlListReference::operator=(const QQmlListReference &o)
+{
+ if (o.d) o.d->addref();
+ if (d) d->release();
+ d = o.d;
+ return *this;
+}
+
+/*! \internal */
+QQmlListReference::~QQmlListReference()
+{
+ if (d) d->release();
+}
+
+/*!
+Returns true if the instance refers to a valid list property, otherwise false.
+*/
+bool QQmlListReference::isValid() const
+{
+ return d && d->object;
+}
+
+/*!
+Returns the list property's object. Returns 0 if the reference is invalid.
+*/
+QObject *QQmlListReference::object() const
+{
+ if (isValid()) return d->object;
+ else return 0;
+}
+
+/*!
+Returns the QMetaObject for the elements stored in the list property. Returns 0 if the reference
+is invalid.
+
+The QMetaObject can be used ahead of time to determine whether a given instance can be added
+to a list.
+*/
+const QMetaObject *QQmlListReference::listElementType() const
+{
+ if (isValid()) return d->elementType;
+ else return 0;
+}
+
+/*!
+Returns true if the list property can be appended to, otherwise false. Returns false if the
+reference is invalid.
+
+\sa append()
+*/
+bool QQmlListReference::canAppend() const
+{
+ return (isValid() && d->property.append);
+}
+
+/*!
+Returns true if the list property can queried by index, otherwise false. Returns false if the
+reference is invalid.
+
+\sa at()
+*/
+bool QQmlListReference::canAt() const
+{
+ return (isValid() && d->property.at);
+}
+
+/*!
+Returns true if the list property can be cleared, otherwise false. Returns false if the
+reference is invalid.
+
+\sa clear()
+*/
+bool QQmlListReference::canClear() const
+{
+ return (isValid() && d->property.clear);
+}
+
+/*!
+Returns true if the list property can be queried for its element count, otherwise false.
+Returns false if the reference is invalid.
+
+\sa count()
+*/
+bool QQmlListReference::canCount() const
+{
+ return (isValid() && d->property.count);
+}
+
+/*!
+Appends \a object to the list. Returns true if the operation succeeded, otherwise false.
+
+\sa canAppend()
+*/
+bool QQmlListReference::append(QObject *object) const
+{
+ if (!canAppend()) return false;
+
+ if (object && !QQmlPropertyPrivate::canConvert(object->metaObject(), d->elementType))
+ return false;
+
+ d->property.append(&d->property, object);
+
+ return true;
+}
+
+/*!
+Returns the list element at \a index, or 0 if the operation failed.
+
+\sa canAt()
+*/
+QObject *QQmlListReference::at(int index) const
+{
+ if (!canAt()) return 0;
+
+ return d->property.at(&d->property, index);
+}
+
+/*!
+Clears the list. Returns true if the operation succeeded, otherwise false.
+
+\sa canClear()
+*/
+bool QQmlListReference::clear() const
+{
+ if (!canClear()) return false;
+
+ d->property.clear(&d->property);
+
+ return true;
+}
+
+/*!
+Returns the number of objects in the list, or 0 if the operation failed.
+*/
+int QQmlListReference::count() const
+{
+ if (!canCount()) return 0;
+
+ return d->property.count(&d->property);
+}
+
+/*!
+\class QQmlListProperty
+\since 4.7
+\brief The QQmlListProperty class allows applications to expose list-like
+properties to QML.
+
+QML has many list properties, where more than one object value can be assigned.
+The use of a list property from QML looks like this:
+
+\code
+FruitBasket {
+ fruit: [
+ Apple {},
+ Orange{},
+ Banana{}
+ ]
+}
+\endcode
+
+The QQmlListProperty encapsulates a group of function pointers that represet the
+set of actions QML can perform on the list - adding items, retrieving items and
+clearing the list. In the future, additional operations may be supported. All
+list properties must implement the append operation, but the rest are optional.
+
+To provide a list property, a C++ class must implement the operation callbacks,
+and then return an appropriate QQmlListProperty value from the property getter.
+List properties should have no setter. In the example above, the Q_PROPERTY()
+declarative will look like this:
+
+\code
+Q_PROPERTY(QQmlListProperty<Fruit> fruit READ fruit);
+\endcode
+
+QML list properties are typesafe - in this case \c {Fruit} is a QObject type that
+\c {Apple}, \c {Orange} and \c {Banana} all derive from.
+
+\note QQmlListProperty can only be used for lists of QObject-derived object pointers.
+
+\sa {Object and List Property Types}
+
+*/
+
+/*!
+\fn QQmlListProperty::QQmlListProperty()
+\internal
+*/
+
+/*!
+\fn QQmlListProperty::QQmlListProperty(QObject *object, QList<T *> &list)
+
+Convenience constructor for making a QQmlListProperty value from an existing
+QList \a list. The \a list reference must remain valid for as long as \a object
+exists. \a object must be provided.
+
+Generally this constructor should not be used in production code, as a
+writable QList violates QML's memory management rules. However, this constructor
+can very useful while prototyping.
+*/
+
+/*!
+\fn QQmlListProperty::QQmlListProperty(QObject *object, void *data, AppendFunction append,
+ CountFunction count = 0, AtFunction at = 0,
+ ClearFunction clear = 0)
+
+Construct a QQmlListProperty from a set of operation functions. An opaque \a data handle
+may be passed which can be accessed from within the operation functions. The list property
+remains valid while \a object exists.
+
+The \a append operation is compulsory and must be provided, while the \a count, \a at and
+\a clear methods are optional.
+*/
+
+/*!
+\typedef QQmlListProperty::AppendFunction
+
+Synonym for \c {void (*)(QQmlListProperty<T> *property, T *value)}.
+
+Append the \a value to the list \a property.
+*/
+
+/*!
+\typedef QQmlListProperty::CountFunction
+
+Synonym for \c {int (*)(QQmlListProperty<T> *property)}.
+
+Return the number of elements in the list \a property.
+*/
+
+/*!
+\fn bool QQmlListProperty::operator==(const QQmlListProperty &other) const
+
+Returns true if this QQmlListProperty is equal to \a other, otherwise false.
+*/
+
+/*!
+\typedef QQmlListProperty::AtFunction
+
+Synonym for \c {T *(*)(QQmlListProperty<T> *property, int index)}.
+
+Return the element at position \a index in the list \a property.
+*/
+
+/*!
+\typedef QQmlListProperty::ClearFunction
+
+Synonym for \c {void (*)(QQmlListProperty<T> *property)}.
+
+Clear the list \a property.
+*/
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmllist.h b/src/qml/qml/qqmllist.h
new file mode 100644
index 0000000000..3f23cedbc2
--- /dev/null
+++ b/src/qml/qml/qqmllist.h
@@ -0,0 +1,151 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLLIST_H
+#define QQMLLIST_H
+
+#include <QtQml/qtqmlglobal.h>
+#include <QtCore/qlist.h>
+#include <QtCore/qvariant.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+
+class QObject;
+struct QMetaObject;
+
+#ifndef QQMLLISTPROPERTY
+#define QQMLLISTPROPERTY
+template<typename T>
+class QQmlListProperty {
+public:
+ typedef void (*AppendFunction)(QQmlListProperty<T> *, T*);
+ typedef int (*CountFunction)(QQmlListProperty<T> *);
+ typedef T *(*AtFunction)(QQmlListProperty<T> *, int);
+ typedef void (*ClearFunction)(QQmlListProperty<T> *);
+
+ QQmlListProperty()
+ : object(0), data(0), append(0), count(0), at(0), clear(0), dummy1(0), dummy2(0) {}
+ QQmlListProperty(QObject *o, QList<T *> &list)
+ : object(o), data(&list), append(qlist_append), count(qlist_count), at(qlist_at),
+ clear(qlist_clear), dummy1(0), dummy2(0) {}
+ QQmlListProperty(QObject *o, void *d, AppendFunction a, CountFunction c = 0, AtFunction t = 0,
+ ClearFunction r = 0)
+ : object(o), data(d), append(a), count(c), at(t), clear(r), dummy1(0), dummy2(0) {}
+
+ bool operator==(const QQmlListProperty &o) const {
+ return object == o.object &&
+ data == o.data &&
+ append == o.append &&
+ count == o.count &&
+ at == o.at &&
+ clear == o.clear;
+ }
+
+ QObject *object;
+ void *data;
+
+ AppendFunction append;
+
+ CountFunction count;
+ AtFunction at;
+
+ ClearFunction clear;
+
+ void *dummy1;
+ void *dummy2;
+
+private:
+ static void qlist_append(QQmlListProperty *p, T *v) {
+ reinterpret_cast<QList<T *> *>(p->data)->append(v);
+ }
+ static int qlist_count(QQmlListProperty *p) {
+ return reinterpret_cast<QList<T *> *>(p->data)->count();
+ }
+ static T *qlist_at(QQmlListProperty *p, int idx) {
+ return reinterpret_cast<QList<T *> *>(p->data)->at(idx);
+ }
+ static void qlist_clear(QQmlListProperty *p) {
+ return reinterpret_cast<QList<T *> *>(p->data)->clear();
+ }
+};
+#endif
+
+class QQmlEngine;
+class QQmlListReferencePrivate;
+class Q_QML_EXPORT QQmlListReference
+{
+public:
+ QQmlListReference();
+ QQmlListReference(QObject *, const char *property, QQmlEngine * = 0);
+ QQmlListReference(const QQmlListReference &);
+ QQmlListReference &operator=(const QQmlListReference &);
+ ~QQmlListReference();
+
+ bool isValid() const;
+
+ QObject *object() const;
+ const QMetaObject *listElementType() const;
+
+ bool canAppend() const;
+ bool canAt() const;
+ bool canClear() const;
+ bool canCount() const;
+
+ bool append(QObject *) const;
+ QObject *at(int) const;
+ bool clear() const;
+ int count() const;
+
+private:
+ friend class QQmlListReferencePrivate;
+ QQmlListReferencePrivate* d;
+};
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(QQmlListReference)
+
+QT_END_HEADER
+
+#endif // QQMLLIST_H
diff --git a/src/qml/qml/qqmllist_p.h b/src/qml/qml/qqmllist_p.h
new file mode 100644
index 0000000000..0fe0ed3d44
--- /dev/null
+++ b/src/qml/qml/qqmllist_p.h
@@ -0,0 +1,85 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLLIST_P_H
+#define QQMLLIST_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 "qqmllist.h"
+#include "qqmlguard_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QQmlListReferencePrivate
+{
+public:
+ QQmlListReferencePrivate();
+
+ static QQmlListReference init(const QQmlListProperty<QObject> &, int, QQmlEngine *);
+
+ QQmlGuard<QObject> object;
+ const QMetaObject *elementType;
+ QQmlListProperty<QObject> property;
+ int propertyType;
+
+ void addref();
+ void release();
+ int refCount;
+
+ static inline QQmlListReferencePrivate *get(QQmlListReference *ref) {
+ return ref->d;
+ }
+};
+
+
+QT_END_NAMESPACE
+
+#endif // QQMLLIST_P_H
diff --git a/src/qml/qml/qqmllocale.cpp b/src/qml/qml/qqmllocale.cpp
new file mode 100644
index 0000000000..4dc30f27ea
--- /dev/null
+++ b/src/qml/qml/qqmllocale.cpp
@@ -0,0 +1,1123 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qqmllocale_p.h"
+#include "qqmlengine_p.h"
+#include <private/qqmlcontext_p.h>
+#include <private/qjsconverter_impl_p.h>
+#include <QtCore/qnumeric.h>
+#include <QtCore/qdatetime.h>
+
+#include <private/qlocale_p.h>
+#include <private/qlocale_data_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QV8LocaleDataResource : public QV8ObjectResource
+{
+ V8_RESOURCE_TYPE(LocaleDataType)
+public:
+ QV8LocaleDataResource(QV8Engine *e) : QV8ObjectResource(e) {}
+ QLocale locale;
+};
+
+#define GET_LOCALE_DATA_RESOURCE(OBJECT) \
+QV8LocaleDataResource *r = v8_resource_cast<QV8LocaleDataResource>(OBJECT); \
+if (!r) \
+ V8THROW_ERROR("Not a valid Locale object")
+
+static bool isLocaleObject(v8::Handle<v8::Value> val)
+{
+ if (!val->IsObject())
+ return false;
+
+ v8::Handle<v8::Object> localeObj = val->ToObject();
+ return localeObj->Has(v8::String::New("nativeLanguageName")); //XXX detect locale object properly
+}
+
+//--------------
+// Date extension
+
+static const char *dateToLocaleStringFunction =
+ "(function(toLocaleStringFunc) { "
+ " var orig_toLocaleString;"
+ " orig_toLocaleString = Date.prototype.toLocaleString;"
+ " Date.prototype.toLocaleString = (function() {"
+ " var val = toLocaleStringFunc.apply(this, arguments);"
+ " if (val == undefined) val = orig_toLocaleString.call(this);"
+ " return val;"
+ " })"
+ "})";
+
+static const char *dateToLocaleTimeStringFunction =
+ "(function(toLocaleTimeStringFunc) { "
+ " var orig_toLocaleTimeString;"
+ " orig_toLocaleTimeString = Date.prototype.toLocaleTimeString;"
+ " Date.prototype.toLocaleTimeString = (function() {"
+ " var val = toLocaleTimeStringFunc.apply(this, arguments);"
+ " if (val == undefined) val = orig_toLocaleTimeString.call(this);"
+ " return val;"
+ " })"
+ "})";
+
+static const char *dateToLocaleDateStringFunction =
+ "(function(toLocaleDateStringFunc) { "
+ " var orig_toLocaleDateString;"
+ " orig_toLocaleDateString = Date.prototype.toLocaleDateString;"
+ " Date.prototype.toLocaleDateString = (function() {"
+ " var val = toLocaleDateStringFunc.apply(this, arguments);"
+ " if (val == undefined) val = orig_toLocaleDateString.call(this);"
+ " return val;"
+ " })"
+ "})";
+
+
+static const char *dateFromLocaleStringFunction =
+ "(function(fromLocaleStringFunc) { "
+ " Date.fromLocaleString = (function() {"
+ " return fromLocaleStringFunc.apply(null, arguments);"
+ " })"
+ "})";
+
+static const char *dateFromLocaleTimeStringFunction =
+ "(function(fromLocaleTimeStringFunc) { "
+ " Date.fromLocaleTimeString = (function() {"
+ " return fromLocaleTimeStringFunc.apply(null, arguments);"
+ " })"
+ "})";
+
+static const char *dateFromLocaleDateStringFunction =
+ "(function(fromLocaleDateStringFunc) { "
+ " Date.fromLocaleDateString = (function() {"
+ " return fromLocaleDateStringFunc.apply(null, arguments);"
+ " })"
+ "})";
+
+
+static void registerFunction(QV8Engine *engine, const char *script, v8::InvocationCallback func)
+{
+ v8::Local<v8::Script> registerScript = v8::Script::New(v8::String::New(script), 0, 0, v8::Handle<v8::String>(), v8::Script::NativeMode);
+ v8::Local<v8::Value> result = registerScript->Run();
+ Q_ASSERT(result->IsFunction());
+ v8::Local<v8::Function> registerFunc = v8::Local<v8::Function>::Cast(result);
+ v8::Handle<v8::Value> args = V8FUNCTION(func, engine);
+ registerFunc->Call(v8::Local<v8::Object>::Cast(registerFunc), 1, &args);
+}
+
+void QQmlDateExtension::registerExtension(QV8Engine *engine)
+{
+ registerFunction(engine, dateToLocaleStringFunction, toLocaleString);
+ registerFunction(engine, dateToLocaleTimeStringFunction, toLocaleTimeString);
+ registerFunction(engine, dateToLocaleDateStringFunction, toLocaleDateString);
+ registerFunction(engine, dateFromLocaleStringFunction, fromLocaleString);
+ registerFunction(engine, dateFromLocaleTimeStringFunction, fromLocaleTimeString);
+ registerFunction(engine, dateFromLocaleDateStringFunction, fromLocaleDateString);
+}
+
+v8::Handle<v8::Value> QQmlDateExtension::toLocaleString(const v8::Arguments& args)
+{
+ if (args.Length() > 2)
+ return v8::Undefined();
+
+ if (!args.This()->IsDate())
+ return v8::Undefined();
+
+ QDateTime dt = QV8Engine::qtDateTimeFromJsDate(v8::Handle<v8::Date>::Cast(args.This())->NumberValue());
+
+ if (args.Length() == 0) {
+ // Use QLocale for standard toLocaleString() function
+ QLocale locale;
+ return QJSConverter::toString(locale.toString(dt));
+ }
+
+ if (!isLocaleObject(args[0]))
+ return v8::Undefined(); // Use the default Date toLocaleString()
+
+ GET_LOCALE_DATA_RESOURCE(args[0]->ToObject());
+
+ QLocale::FormatType enumFormat = QLocale::LongFormat;
+ QString formattedDt;
+ if (args.Length() == 2) {
+ if (args[1]->IsString()) {
+ QString format = r->engine->toVariant(args[1], -1).toString();
+ formattedDt = r->locale.toString(dt, format);
+ } else if (args[1]->IsNumber()) {
+ quint32 intFormat = args[1]->ToNumber()->Value();
+ QLocale::FormatType format = QLocale::FormatType(intFormat);
+ formattedDt = r->locale.toString(dt, format);
+ } else {
+ V8THROW_ERROR("Locale: Date.toLocaleString(): Invalid datetime format");
+ }
+ } else {
+ formattedDt = r->locale.toString(dt, enumFormat);
+ }
+
+ return r->engine->toString(formattedDt);
+}
+
+v8::Handle<v8::Value> QQmlDateExtension::toLocaleTimeString(const v8::Arguments& args)
+{
+ if (args.Length() > 2)
+ return v8::Undefined();
+
+ if (!args.This()->IsDate())
+ return v8::Undefined();
+
+ QDateTime dt = QV8Engine::qtDateTimeFromJsDate(v8::Handle<v8::Date>::Cast(args.This())->NumberValue());
+ QTime time = dt.time();
+
+ if (args.Length() == 0) {
+ // Use QLocale for standard toLocaleString() function
+ QLocale locale;
+ return QJSConverter::toString(locale.toString(time));
+ }
+
+ if (!isLocaleObject(args[0]))
+ return v8::Undefined(); // Use the default Date toLocaleTimeString()
+
+ GET_LOCALE_DATA_RESOURCE(args[0]->ToObject());
+
+ QLocale::FormatType enumFormat = QLocale::LongFormat;
+ QString formattedTime;
+ if (args.Length() == 2) {
+ if (args[1]->IsString()) {
+ QString format = r->engine->toVariant(args[1], -1).toString();
+ formattedTime = r->locale.toString(time, format);
+ } else if (args[1]->IsNumber()) {
+ quint32 intFormat = args[1]->ToNumber()->Value();
+ QLocale::FormatType format = QLocale::FormatType(intFormat);
+ formattedTime = r->locale.toString(time, format);
+ } else {
+ V8THROW_ERROR("Locale: Date.toLocaleTimeString(): Invalid time format");
+ }
+ } else {
+ formattedTime = r->locale.toString(time, enumFormat);
+ }
+
+ return r->engine->toString(formattedTime);
+}
+
+v8::Handle<v8::Value> QQmlDateExtension::toLocaleDateString(const v8::Arguments& args)
+{
+ if (args.Length() > 2)
+ return v8::Undefined();
+
+ if (!args.This()->IsDate())
+ return v8::Undefined();
+
+ QDateTime dt = QV8Engine::qtDateTimeFromJsDate(v8::Handle<v8::Date>::Cast(args.This())->NumberValue());
+ QDate date = dt.date();
+
+ if (args.Length() == 0) {
+ // Use QLocale for standard toLocaleString() function
+ QLocale locale;
+ return QJSConverter::toString(locale.toString(date));
+ }
+
+ if (!isLocaleObject(args[0]))
+ return v8::Undefined(); // Use the default Date toLocaleDateString()
+
+ GET_LOCALE_DATA_RESOURCE(args[0]->ToObject());
+
+ QLocale::FormatType enumFormat = QLocale::LongFormat;
+ QString formattedDate;
+ if (args.Length() == 2) {
+ if (args[1]->IsString()) {
+ QString format = r->engine->toVariant(args[1], -1).toString();
+ formattedDate = r->locale.toString(date, format);
+ } else if (args[1]->IsNumber()) {
+ quint32 intFormat = args[1]->ToNumber()->Value();
+ QLocale::FormatType format = QLocale::FormatType(intFormat);
+ formattedDate = r->locale.toString(date, format);
+ } else {
+ V8THROW_ERROR("Locale: Date.loLocaleDateString(): Invalid date format");
+ }
+ } else {
+ formattedDate = r->locale.toString(date, enumFormat);
+ }
+
+ return r->engine->toString(formattedDate);
+}
+
+v8::Handle<v8::Value> QQmlDateExtension::fromLocaleString(const v8::Arguments& args)
+{
+ if (args.Length() == 1 && args[0]->IsString()) {
+ QLocale locale;
+ QString dateString = QJSConverter::toString(args[0]->ToString());
+ QDateTime dt = locale.toDateTime(dateString);
+ return QJSConverter::toDateTime(dt);
+ }
+
+ if (args.Length() < 1 || args.Length() > 3 || !isLocaleObject(args[0]))
+ V8THROW_ERROR("Locale: Date.fromLocaleString(): Invalid arguments");
+
+ GET_LOCALE_DATA_RESOURCE(args[0]->ToObject());
+
+ QLocale::FormatType enumFormat = QLocale::LongFormat;
+ QDateTime dt;
+ QString dateString = r->engine->toString(args[1]->ToString());
+ if (args.Length() == 3) {
+ if (args[2]->IsString()) {
+ QString format = r->engine->toString(args[2]->ToString());
+ dt = r->locale.toDateTime(dateString, format);
+ } else if (args[2]->IsNumber()) {
+ quint32 intFormat = args[2]->ToNumber()->Value();
+ QLocale::FormatType format = QLocale::FormatType(intFormat);
+ dt = r->locale.toDateTime(dateString, format);
+ } else {
+ V8THROW_ERROR("Locale: Date.fromLocaleString(): Invalid datetime format");
+ }
+ } else {
+ dt = r->locale.toDateTime(dateString, enumFormat);
+ }
+
+ return QJSConverter::toDateTime(dt);
+}
+
+v8::Handle<v8::Value> QQmlDateExtension::fromLocaleTimeString(const v8::Arguments& args)
+{
+ if (args.Length() == 1 && args[0]->IsString()) {
+ QLocale locale;
+ QString timeString = QJSConverter::toString(args[0]->ToString());
+ QTime time = locale.toTime(timeString);
+ QDateTime dt = QDateTime::currentDateTime();
+ dt.setTime(time);
+ return QJSConverter::toDateTime(dt);
+ }
+
+ if (args.Length() < 1 || args.Length() > 3 || !isLocaleObject(args[0]))
+ V8THROW_ERROR("Locale: Date.fromLocaleTimeString(): Invalid arguments");
+
+ GET_LOCALE_DATA_RESOURCE(args[0]->ToObject());
+
+ QLocale::FormatType enumFormat = QLocale::LongFormat;
+ QTime tm;
+ QString dateString = r->engine->toString(args[1]->ToString());
+ if (args.Length() == 3) {
+ if (args[2]->IsString()) {
+ QString format = r->engine->toString(args[2]->ToString());
+ tm = r->locale.toTime(dateString, format);
+ } else if (args[2]->IsNumber()) {
+ quint32 intFormat = args[2]->ToNumber()->Value();
+ QLocale::FormatType format = QLocale::FormatType(intFormat);
+ tm = r->locale.toTime(dateString, format);
+ } else {
+ V8THROW_ERROR("Locale: Date.fromLocaleTimeString(): Invalid datetime format");
+ }
+ } else {
+ tm = r->locale.toTime(dateString, enumFormat);
+ }
+
+ QDateTime dt = QDateTime::currentDateTime();
+ dt.setTime(tm);
+
+ return QJSConverter::toDateTime(dt);
+}
+
+v8::Handle<v8::Value> QQmlDateExtension::fromLocaleDateString(const v8::Arguments& args)
+{
+ if (args.Length() == 1 && args[0]->IsString()) {
+ QLocale locale;
+ QString dateString = QJSConverter::toString(args[0]->ToString());
+ QDate date = locale.toDate(dateString);
+ return QJSConverter::toDateTime(QDateTime(date));
+ }
+
+ if (args.Length() < 1 || args.Length() > 3 || !isLocaleObject(args[0]))
+ V8THROW_ERROR("Locale: Date.fromLocaleDateString(): Invalid arguments");
+
+ GET_LOCALE_DATA_RESOURCE(args[0]->ToObject());
+
+ QLocale::FormatType enumFormat = QLocale::LongFormat;
+ QDate dt;
+ QString dateString = r->engine->toString(args[1]->ToString());
+ if (args.Length() == 3) {
+ if (args[2]->IsString()) {
+ QString format = r->engine->toString(args[2]->ToString());
+ dt = r->locale.toDate(dateString, format);
+ } else if (args[2]->IsNumber()) {
+ quint32 intFormat = args[2]->ToNumber()->Value();
+ QLocale::FormatType format = QLocale::FormatType(intFormat);
+ dt = r->locale.toDate(dateString, format);
+ } else {
+ V8THROW_ERROR("Locale: Date.fromLocaleDateString(): Invalid datetime format");
+ }
+ } else {
+ dt = r->locale.toDate(dateString, enumFormat);
+ }
+
+ return QJSConverter::toDateTime(QDateTime(dt));
+}
+
+//-----------------
+// Number extension
+
+static const char *numberToLocaleStringFunction =
+ "(function(toLocaleStringFunc) { "
+ " var orig_toLocaleString;"
+ " orig_toLocaleString = Number.prototype.toLocaleString;"
+ " Number.prototype.toLocaleString = (function() {"
+ " var val = toLocaleStringFunc.apply(this, arguments);"
+ " if (val == undefined) val = orig_toLocaleString.call(this);"
+ " return val;"
+ " })"
+ "})";
+
+static const char *numberToLocaleCurrencyStringFunction =
+ "(function(toLocaleCurrencyStringFunc) { "
+ " Number.prototype.toLocaleCurrencyString = (function() {"
+ " return toLocaleCurrencyStringFunc.apply(this, arguments);"
+ " })"
+ "})";
+
+static const char *numberFromLocaleStringFunction =
+ "(function(fromLocaleStringFunc) { "
+ " Number.fromLocaleString = (function() {"
+ " return fromLocaleStringFunc.apply(null, arguments);"
+ " })"
+ "})";
+
+
+void QQmlNumberExtension::registerExtension(QV8Engine *engine)
+{
+ registerFunction(engine, numberToLocaleStringFunction, toLocaleString);
+ registerFunction(engine, numberToLocaleCurrencyStringFunction, toLocaleCurrencyString);
+ registerFunction(engine, numberFromLocaleStringFunction, fromLocaleString);
+}
+
+v8::Handle<v8::Value> QQmlNumberExtension::toLocaleString(const v8::Arguments& args)
+{
+ if (args.Length() > 3)
+ V8THROW_ERROR("Locale: Number.toLocaleString(): Invalid arguments");
+
+ double number = args.This()->ToNumber()->Value();
+
+ if (args.Length() == 0) {
+ // Use QLocale for standard toLocaleString() function
+ QLocale locale;
+ return QJSConverter::toString(locale.toString(number));
+ }
+
+ if (!isLocaleObject(args[0]))
+ return v8::Undefined(); // Use the default Number toLocaleString()
+
+ GET_LOCALE_DATA_RESOURCE(args[0]->ToObject());
+
+ uint16_t format = 'f';
+ if (args.Length() > 1) {
+ if (!args[1]->IsString())
+ V8THROW_ERROR("Locale: Number.toLocaleString(): Invalid arguments");
+ v8::Local<v8::String> fs = args[1]->ToString();
+ if (!fs.IsEmpty() && fs->Length())
+ format = fs->GetCharacter(0);
+ }
+ int prec = 2;
+ if (args.Length() > 2) {
+ if (!args[2]->IsNumber())
+ V8THROW_ERROR("Locale: Number.toLocaleString(): Invalid arguments");
+ prec = args[2]->IntegerValue();
+ }
+
+ return r->engine->toString(r->locale.toString(number, (char)format, prec));
+}
+
+v8::Handle<v8::Value> QQmlNumberExtension::toLocaleCurrencyString(const v8::Arguments& args)
+{
+ if (args.Length() > 2)
+ V8THROW_ERROR("Locale: Number.toLocaleCurrencyString(): Invalid arguments");
+
+ double number = args.This()->ToNumber()->Value();
+
+ if (args.Length() == 0) {
+ // Use QLocale for standard toLocaleString() function
+ QLocale locale;
+ return QJSConverter::toString(locale.toString(number));
+ }
+
+ if (!isLocaleObject(args[0]))
+ V8THROW_ERROR("Locale: Number.toLocaleCurrencyString(): Invalid arguments");
+
+ GET_LOCALE_DATA_RESOURCE(args[0]->ToObject());
+
+ QString symbol;
+ if (args.Length() > 1) {
+ if (!args[1]->IsString())
+ V8THROW_ERROR("Locale: Number.toLocaleString(): Invalid arguments");
+ symbol = r->engine->toString(args[1]->ToString());
+ }
+
+ return r->engine->toString(r->locale.toCurrencyString(number, symbol));
+}
+
+v8::Handle<v8::Value> QQmlNumberExtension::fromLocaleString(const v8::Arguments& args)
+{
+ if (args.Length() < 1 || args.Length() > 2)
+ V8THROW_ERROR("Locale: Number.fromLocaleString(): Invalid arguments");
+
+ int numberIdx = 0;
+ QLocale locale;
+
+ if (args.Length() == 2) {
+ if (!isLocaleObject(args[0]))
+ V8THROW_ERROR("Locale: Number.fromLocaleString(): Invalid arguments");
+
+ GET_LOCALE_DATA_RESOURCE(args[0]->ToObject());
+ locale = r->locale;
+
+ numberIdx = 1;
+ }
+
+ v8::Local<v8::String> ns = args[numberIdx]->ToString();
+ if (ns.IsEmpty() || ns->Length() == 0)
+ return v8::Number::New(Q_QNAN);
+
+ bool ok = false;
+ double val = locale.toDouble(QJSConverter::toString(ns), &ok);
+
+ if (!ok)
+ V8THROW_ERROR("Locale: Number.fromLocaleString(): Invalid format")
+
+ return v8::Number::New(val);
+}
+
+//--------------
+// Locale object
+
+static v8::Handle<v8::Value> locale_get_firstDayOfWeek(v8::Local<v8::String>, const v8::AccessorInfo &info)
+{
+ GET_LOCALE_DATA_RESOURCE(info.This());
+ return v8::Integer::New(r->locale.firstDayOfWeek());
+}
+
+static v8::Handle<v8::Value> locale_get_measurementSystem(v8::Local<v8::String>, const v8::AccessorInfo &info)
+{
+ GET_LOCALE_DATA_RESOURCE(info.This());
+ return v8::Integer::New(r->locale.measurementSystem());
+}
+
+static v8::Handle<v8::Value> locale_get_textDirection(v8::Local<v8::String>, const v8::AccessorInfo &info)
+{
+ GET_LOCALE_DATA_RESOURCE(info.This());
+ return v8::Integer::New(r->locale.textDirection());
+}
+
+static v8::Handle<v8::Value> locale_get_weekDays(v8::Local<v8::String>, const v8::AccessorInfo &info)
+{
+ GET_LOCALE_DATA_RESOURCE(info.This());
+
+ QList<Qt::DayOfWeek> days = r->locale.weekdays();
+
+ v8::Handle<v8::Array> result = v8::Array::New(days.size());
+ for (int i = 0; i < days.size(); ++i) {
+ int day = days.at(i);
+ if (day == 7) // JS Date days in range 0(Sunday) to 6(Saturday)
+ day = 0;
+ result->Set(i, v8::Integer::New(day));
+ }
+
+ return result;
+}
+
+static v8::Handle<v8::Value> locale_get_uiLanguages(v8::Local<v8::String>, const v8::AccessorInfo &info)
+{
+ GET_LOCALE_DATA_RESOURCE(info.This());
+
+ QStringList langs = r->locale.uiLanguages();
+ v8::Handle<v8::Array> result = v8::Array::New(langs.size());
+ for (int i = 0; i < langs.size(); ++i) {
+ result->Set(i, r->engine->toString(langs.at(i)));
+ }
+
+ return result;
+}
+
+static v8::Handle<v8::Value> locale_currencySymbol(const v8::Arguments &args)
+{
+ GET_LOCALE_DATA_RESOURCE(args.This());
+
+ if (args.Length() > 1)
+ V8THROW_ERROR("Locale: currencySymbol(): Invalid arguments");
+
+ QLocale::CurrencySymbolFormat format = QLocale::CurrencySymbol;
+ if (args.Length() == 1) {
+ quint32 intFormat = args[0]->ToNumber()->Value();
+ format = QLocale::CurrencySymbolFormat(intFormat);
+ }
+
+ return r->engine->toString(r->locale.currencySymbol(format));
+}
+
+#define LOCALE_FORMAT(FUNC) \
+static v8::Handle<v8::Value> locale_ ##FUNC (const v8::Arguments &args) { \
+ GET_LOCALE_DATA_RESOURCE(args.This());\
+ if (args.Length() > 1) \
+ V8THROW_ERROR("Locale: " #FUNC "(): Invalid arguments"); \
+ QLocale::FormatType format = QLocale::LongFormat;\
+ if (args.Length() == 1) { \
+ quint32 intFormat = args[0]->Uint32Value(); \
+ format = QLocale::FormatType(intFormat); \
+ } \
+ return r->engine->toString(r->locale. FUNC (format)); \
+}
+
+LOCALE_FORMAT(dateTimeFormat)
+LOCALE_FORMAT(timeFormat)
+LOCALE_FORMAT(dateFormat)
+
+// +1 added to idx because JS is 0-based, whereas QLocale months begin at 1.
+#define LOCALE_FORMATTED_MONTHNAME(VARIABLE) \
+static v8::Handle<v8::Value> locale_ ## VARIABLE (const v8::Arguments &args) {\
+ GET_LOCALE_DATA_RESOURCE(args.This()); \
+ if (args.Length() < 1 || args.Length() > 2) \
+ V8THROW_ERROR("Locale: " #VARIABLE "(): Invalid arguments"); \
+ QLocale::FormatType enumFormat = QLocale::LongFormat; \
+ int idx = args[0]->IntegerValue() + 1; \
+ if (idx < 1 || idx > 12) \
+ V8THROW_ERROR("Locale: Invalid month"); \
+ QString name; \
+ if (args.Length() == 2) { \
+ if (args[1]->IsNumber()) { \
+ quint32 intFormat = args[1]->IntegerValue(); \
+ QLocale::FormatType format = QLocale::FormatType(intFormat); \
+ name = r->locale. VARIABLE(idx, format); \
+ } else { \
+ V8THROW_ERROR("Locale: Invalid datetime format"); \
+ } \
+ } else { \
+ name = r->locale. VARIABLE(idx, enumFormat); \
+ } \
+ return r->engine->toString(name); \
+}
+
+// 0 -> 7 as Qt::Sunday is 7, but Sunday is 0 in JS Date
+#define LOCALE_FORMATTED_DAYNAME(VARIABLE) \
+static v8::Handle<v8::Value> locale_ ## VARIABLE (const v8::Arguments &args) {\
+ GET_LOCALE_DATA_RESOURCE(args.This()); \
+ if (args.Length() < 1 || args.Length() > 2) \
+ V8THROW_ERROR("Locale: " #VARIABLE "(): Invalid arguments"); \
+ QLocale::FormatType enumFormat = QLocale::LongFormat; \
+ int idx = args[0]->IntegerValue(); \
+ if (idx < 0 || idx > 7) \
+ V8THROW_ERROR("Locale: Invalid day"); \
+ if (idx == 0) idx = 7; \
+ QString name; \
+ if (args.Length() == 2) { \
+ if (args[1]->IsNumber()) { \
+ quint32 intFormat = args[1]->ToNumber()->Value(); \
+ QLocale::FormatType format = QLocale::FormatType(intFormat); \
+ name = r->locale. VARIABLE(idx, format); \
+ } else { \
+ V8THROW_ERROR("Locale: Invalid datetime format"); \
+ } \
+ } else { \
+ name = r->locale. VARIABLE(idx, enumFormat); \
+ } \
+ return r->engine->toString(name); \
+}
+
+
+#define LOCALE_REGISTER_FORMATTED_NAME_FUNCTION(FT, VARIABLE, ENGINE) \
+ FT->PrototypeTemplate()->Set(v8::String::New( #VARIABLE ), V8FUNCTION(locale_ ## VARIABLE, ENGINE));
+
+LOCALE_FORMATTED_MONTHNAME(monthName)
+LOCALE_FORMATTED_MONTHNAME(standaloneMonthName)
+LOCALE_FORMATTED_DAYNAME(dayName)
+LOCALE_FORMATTED_DAYNAME(standaloneDayName)
+
+#define LOCALE_STRING_PROPERTY(VARIABLE) static v8::Handle<v8::Value> locale_get_ ## VARIABLE (v8::Local<v8::String>, const v8::AccessorInfo &info) \
+{ \
+ GET_LOCALE_DATA_RESOURCE(info.This()); \
+ return r->engine->toString(r->locale. VARIABLE());\
+}
+
+#define LOCALE_REGISTER_STRING_ACCESSOR(FT, VARIABLE) \
+ FT ->PrototypeTemplate()->SetAccessor( v8::String::New( #VARIABLE ), locale_get_ ## VARIABLE )
+
+
+LOCALE_STRING_PROPERTY(name)
+LOCALE_STRING_PROPERTY(nativeLanguageName)
+LOCALE_STRING_PROPERTY(nativeCountryName)
+LOCALE_STRING_PROPERTY(decimalPoint)
+LOCALE_STRING_PROPERTY(groupSeparator)
+LOCALE_STRING_PROPERTY(percent)
+LOCALE_STRING_PROPERTY(zeroDigit)
+LOCALE_STRING_PROPERTY(negativeSign)
+LOCALE_STRING_PROPERTY(positiveSign)
+LOCALE_STRING_PROPERTY(exponential)
+LOCALE_STRING_PROPERTY(amText)
+LOCALE_STRING_PROPERTY(pmText)
+
+class QV8LocaleDataDeletable : public QV8Engine::Deletable
+{
+public:
+ QV8LocaleDataDeletable(QV8Engine *engine);
+ ~QV8LocaleDataDeletable();
+
+ v8::Persistent<v8::Function> constructor;
+};
+
+QV8LocaleDataDeletable::QV8LocaleDataDeletable(QV8Engine *engine)
+{
+ v8::HandleScope handle_scope;
+ v8::Context::Scope scope(engine->context());
+
+ v8::Local<v8::FunctionTemplate> ft = v8::FunctionTemplate::New();
+ ft->InstanceTemplate()->SetHasExternalResource(true);
+
+ LOCALE_REGISTER_STRING_ACCESSOR(ft, name);
+ LOCALE_REGISTER_STRING_ACCESSOR(ft, nativeLanguageName);
+ LOCALE_REGISTER_STRING_ACCESSOR(ft, nativeCountryName);
+ LOCALE_REGISTER_STRING_ACCESSOR(ft, decimalPoint);
+ LOCALE_REGISTER_STRING_ACCESSOR(ft, groupSeparator);
+ LOCALE_REGISTER_STRING_ACCESSOR(ft, percent);
+ LOCALE_REGISTER_STRING_ACCESSOR(ft, zeroDigit);
+ LOCALE_REGISTER_STRING_ACCESSOR(ft, negativeSign);
+ LOCALE_REGISTER_STRING_ACCESSOR(ft, positiveSign);
+ LOCALE_REGISTER_STRING_ACCESSOR(ft, exponential);
+ LOCALE_REGISTER_STRING_ACCESSOR(ft, amText);
+ LOCALE_REGISTER_STRING_ACCESSOR(ft, pmText);
+
+ ft->PrototypeTemplate()->Set(v8::String::New("currencySymbol"), V8FUNCTION(locale_currencySymbol, engine));
+
+ ft->PrototypeTemplate()->Set(v8::String::New("dateTimeFormat"), V8FUNCTION(locale_dateTimeFormat, engine));
+ ft->PrototypeTemplate()->Set(v8::String::New("dateFormat"), V8FUNCTION(locale_dateFormat, engine));
+ ft->PrototypeTemplate()->Set(v8::String::New("timeFormat"), V8FUNCTION(locale_timeFormat, engine));
+
+ LOCALE_REGISTER_FORMATTED_NAME_FUNCTION(ft, monthName, engine);
+ LOCALE_REGISTER_FORMATTED_NAME_FUNCTION(ft, standaloneMonthName, engine);
+ LOCALE_REGISTER_FORMATTED_NAME_FUNCTION(ft, dayName, engine);
+ LOCALE_REGISTER_FORMATTED_NAME_FUNCTION(ft, standaloneDayName, engine);
+
+ ft->PrototypeTemplate()->SetAccessor(v8::String::New("firstDayOfWeek"), locale_get_firstDayOfWeek);
+ ft->PrototypeTemplate()->SetAccessor(v8::String::New("weekDays"), locale_get_weekDays);
+ ft->PrototypeTemplate()->SetAccessor(v8::String::New("measurementSystem"), locale_get_measurementSystem);
+ ft->PrototypeTemplate()->SetAccessor(v8::String::New("textDirection"), locale_get_textDirection);
+ ft->PrototypeTemplate()->SetAccessor(v8::String::New("uiLanguages"), locale_get_uiLanguages);
+
+ constructor = qPersistentNew(ft->GetFunction());
+}
+
+QV8LocaleDataDeletable::~QV8LocaleDataDeletable()
+{
+ qPersistentDispose(constructor);
+}
+
+V8_DEFINE_EXTENSION(QV8LocaleDataDeletable, localeV8Data);
+
+/*!
+ \qmlclass Locale QQmlLocale
+ \inqmlmodule QtQuick 2
+ \brief The Locale object provides locale specific properties and formatted data.
+
+ The Locale object is created via the \l{QML:Qt::locale()}{Qt.locale()} function. It cannot be created
+ directly.
+
+ The \l{QML:Qt::locale()}{Qt.locale()} function returns a JS Locale object representing the
+ locale with the specified name, which has the format
+ "language[_territory][.codeset][@modifier]" or "C".
+
+ Locale supports the concept of a default locale, which is
+ determined from the system's locale settings at application
+ startup. If no parameter is passed to Qt.locale() the default
+ locale object is returned.
+
+ The Locale object provides a number of functions and properties
+ providing data for the specified locale.
+
+ The Locale object may also be passed to the \l Date and \l Number toLocaleString()
+ and fromLocaleString() methods in order to convert to/from strings using
+ the specified locale.
+
+ This example shows the current date formatted for the German locale:
+
+ \code
+ import QtQuick 2.0
+
+ Text {
+ text: "The date is: " + Date().toLocaleString(Qt.locale("de_DE"))
+ }
+ \endcode
+
+ The following example displays the specified number
+ in the correct format for the default locale:
+
+ \code
+ import QtQuick 2.0
+
+ Text {
+ text: "The value is: " + Number(23443.34).toLocaleString(Qt.locale())
+ }
+ \endcode
+
+ QtQuick Locale's data is based on Common Locale Data Repository v1.8.1.
+
+ The double-to-string and string-to-double conversion functions are
+ covered by the following licenses:
+
+ \legalese
+ Copyright (c) 1991 by AT&T.
+
+ Permission to use, copy, modify, and distribute this software for any
+ purpose without fee is hereby granted, provided that this entire notice
+ is included in all copies of any software which is or includes a copy
+ or modification of this software and in all copies of the supporting
+ documentation for such software.
+
+ THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ WARRANTY. IN PARTICULAR, NEITHER THE AUTHOR NOR AT&T MAKES ANY
+ REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+
+ This product includes software developed by the University of
+ California, Berkeley and its contributors.
+
+ \sa {QtQuick2::Date}{Date} {QtQuick2::Number}{Number}
+*/
+
+QQmlLocale::QQmlLocale()
+{
+}
+
+QQmlLocale::~QQmlLocale()
+{
+}
+
+v8::Handle<v8::Value> QQmlLocale::locale(QV8Engine *v8engine, const QString &locale)
+{
+ QV8LocaleDataDeletable *d = localeV8Data(v8engine);
+ v8::Local<v8::Object> v8Value = d->constructor->NewInstance();
+ QV8LocaleDataResource *r = new QV8LocaleDataResource(v8engine);
+ if (locale.isEmpty())
+ r->locale = QLocale();
+ else
+ r->locale = QLocale(locale);
+ v8Value->SetExternalResource(r);
+
+ return v8Value;
+}
+
+static const char *localeCompareFunction =
+ "(function(localeCompareFunc) { "
+ " var orig_localeCompare;"
+ " orig_localeCompare = String.prototype.localeCompare;"
+ " String.prototype.localeCompare = (function() {"
+ " var val = localeCompareFunc.apply(this, arguments);"
+ " if (val == undefined) val = orig_localeCompare.call(this);"
+ " return val;"
+ " })"
+ "})";
+
+void QQmlLocale::registerStringLocaleCompare(QV8Engine *engine)
+{
+ registerFunction(engine, localeCompareFunction, localeCompare);
+}
+
+v8::Handle<v8::Value> QQmlLocale::localeCompare(const v8::Arguments &args)
+{
+ if (args.Length() != 1 || (!args[0]->IsString() && !args[0]->IsStringObject()))
+ return v8::Undefined();
+
+ if (!args.This()->IsString() && !args.This()->IsStringObject())
+ return v8::Undefined();
+
+ QString thisString = QJSConverter::toString(args.This()->ToString());
+ QString thatString = QJSConverter::toString(args[0]->ToString());
+
+ return v8::Integer::New(QString::localeAwareCompare(thisString, thatString));
+}
+
+/*!
+ \enum QtQuick2::Locale::FormatType
+
+ This enumeration describes the types of format that can be used when
+ converting Date objects to strings.
+
+ \value LongFormat The long version of day and month names; for
+ example, returning "January" as a month name.
+
+ \value ShortFormat The short version of day and month names; for
+ example, returning "Jan" as a month name.
+
+ \value NarrowFormat A special version of day and month names for
+ use when space is limited; for example, returning "J" as a month
+ name. Note that the narrow format might contain the same text for
+ different months and days or it can even be an empty string if the
+ locale doesn't support narrow names, so you should avoid using it
+ for date formatting. Also, for the system locale this format is
+ the same as ShortFormat.
+*/
+
+/*!
+ \qmlproperty string QtQuick2::Locale::name
+
+ Holds the language and country of this locale as a
+ string of the form "language_country", where
+ language is a lowercase, two-letter ISO 639 language code,
+ and country is an uppercase, two- or three-letter ISO 3166 country code.
+*/
+
+/*!
+ \qmlproperty string QtQuick2::Locale::decimalPoint
+
+ Holds the decimal point character of this locale.
+*/
+
+/*!
+ \qmlproperty string QtQuick2::Locale::groupSeparator
+
+ Holds the group separator character of this locale.
+*/
+
+/*!
+ \qmlproperty string QtQuick2::Locale::percent
+
+ Holds the percent character of this locale.
+*/
+
+
+/*!
+ \qmlproperty string QtQuick2::Locale::zeroDigit
+
+ Holds Returns the zero digit character of this locale.
+*/
+
+/*!
+ \qmlproperty string QtQuick2::Locale::negativeSign
+
+ Holds the negative sign character of this locale.
+*/
+
+/*!
+ \qmlproperty string QtQuick2::Locale::positiveSign
+
+ Holds the positive sign character of this locale.
+*/
+
+/*!
+ \qmlproperty string QtQuick2::Locale::exponential
+
+ Holds the exponential character of this locale.
+*/
+
+/*!
+ \qmlmethod string QtQuick2::Locale::dateTimeFormat(type)
+
+ Returns the date time format used for the current locale.
+ \a type specifies the FormatType to return.
+
+ \sa {QtQuick2::Date}{Date}
+*/
+
+/*!
+ \qmlmethod string QtQuick2::Locale::dateFormat(type)
+
+ Returns the date format used for the current locale.
+ \a type specifies the FormatType to return.
+
+ \sa {QtQuick2::Date}{Date}
+*/
+
+/*!
+ \qmlmethod string QtQuick2::Locale::timeFormat(type)
+
+ Returns the time format used for the current locale.
+ \a type specifies the FormatType to return.
+
+ \sa {QtQuick2::Date}{Date}
+*/
+
+/*!
+ \qmlmethod string QtQuick2::Locale::monthName(month, type)
+
+ Returns the localized name of \a month (0-11), in the optional
+ \l FortmatType specified by \a type.
+
+ \note the QLocale C++ API expects a range of (1-12), however Locale.monthName()
+ expects 0-11 as per the JS Date object.
+
+ \sa dayName(), standaloneMonthName()
+*/
+
+/*!
+ \qmlmethod string QtQuick2::Locale::standaloneMonthName(month, type)
+
+ Returns the localized name of \a month (0-11) that is used as a
+ standalone text, in the optional \l FormatType specified by \a type.
+
+ If the locale information doesn't specify the standalone month
+ name then return value is the same as in monthName().
+
+ \note the QLocale C++ API expects a range of (1-12), however Locale.standaloneMonthName()
+ expects 0-11 as per the JS Date object.
+
+ \sa monthName(), standaloneDayName()
+*/
+
+/*!
+ \qmlmethod string QtQuick2::Locale::dayName(day, type)
+
+ Returns the localized name of the \a day (where 0 represents
+ Sunday, 1 represents Monday and so on), in the optional
+ \l FormatType specified by \a type.
+
+ \sa monthName(), standaloneDayName()
+*/
+
+/*!
+ \qmlmethod string QtQuick2::Locale::standaloneDayName(day, type)
+
+ Returns the localized name of the \a day (where 0 represents
+ Sunday, 1 represents Monday and so on) that is used as a
+ standalone text, in the \l FormatType specified by \a type.
+
+ If the locale information does not specify the standalone day
+ name then return value is the same as in dayName().
+
+ \sa dayName(), standaloneMonthName()
+*/
+
+/*!
+ \qmlproperty enumeration QtQuick2::Locale::firstDayOfWeek
+
+ Holds the first day of the week according to the current locale.
+
+ \list
+ \o Locale.Sunday = 0
+ \o Locale.Monday = 1
+ \o Locale.Tuesday = 2
+ \o Locale.Wednesday = 3
+ \o Locale.Thursday = 4
+ \o Locale.Friday = 5
+ \o Locale.Saturday = 6
+ \endlist
+
+ \note that these values match the JS Date API which is different
+ from the Qt C++ API where Qt::Sunday = 7.
+*/
+
+/*!
+ \qmlproperty Array<int> QtQuick2::Locale::weekDays
+
+ Holds an array of days that are considered week days according to the current locale,
+ where Sunday is 0 and Saturday is 6.
+
+ \sa firstDayOfWeek
+*/
+
+/*!
+ \qmlproperty Array<string> QtQuick2::Locale::uiLanguages
+
+ Returns an ordered list of locale names for translation purposes in
+ preference order.
+
+ The return value represents locale names that the user expects to see the
+ UI translation in.
+
+ The first item in the list is the most preferred one.
+*/
+
+/*!
+ \qmlproperty enumeration QtQuick2::Locale::textDirection
+
+ Holds the text direction of the language:
+ \list
+ \o Qt.LeftToRight
+ \o Qt.RightToLeft
+ \endlist
+*/
+
+/*!
+ \qmlproperty string QtQuick2::Locale::amText
+
+ The localized name of the "AM" suffix for times specified using the conventions of the 12-hour clock.
+*/
+
+/*!
+ \qmlproperty string QtQuick2::Locale::pmText
+
+ The localized name of the "PM" suffix for times specified using the conventions of the 12-hour clock.
+*/
+
+/*!
+ \qmlmethod string QtQuick2::Locale::currencySymbol(format)
+
+ Returns the currency symbol for the specified \a format:
+ \list
+ \o Locale.CurrencyIsoCode a ISO-4217 code of the currency.
+ \o Locale.CurrencySymbol a currency symbol.
+ \o Locale.CurrencyDisplayName a user readable name of the currency.
+ \endlist
+ \sa Number::toLocaleCurrencyString()
+*/
+
+/*!
+ \qmlproperty string QtQuick2::Locale::nativeLanguageName
+
+ Holds a native name of the language for the locale. For example
+ "Schwiizertüütsch" for Swiss-German locale.
+
+ \sa nativeCountryName
+*/
+
+/*!
+ \qmlproperty string QtQuick2::Locale::nativeCountryName
+
+ Holds a native name of the country for the locale. For example
+ "España" for Spanish/Spain locale.
+
+ \sa nativeLanguageName
+*/
+
+/*!
+ \qmlproperty enumeration QtQuick2::Locale::measurementSystem
+
+ This property defines which units are used for measurement.
+
+ \list
+ \o Locale.MetricSystem This value indicates metric units, such as meters,
+ centimeters and millimeters.
+ \o Locale.ImperialSystem This value indicates imperial units, such as inches and
+ miles. There are several distinct imperial systems in the world; this
+ value stands for the official United States imperial units.
+ \endlist
+*/
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmllocale_p.h b/src/qml/qml/qqmllocale_p.h
new file mode 100644
index 0000000000..2763ce4fc3
--- /dev/null
+++ b/src/qml/qml/qqmllocale_p.h
@@ -0,0 +1,135 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLLOCALE_H
+#define QQMLLOCALE_H
+
+#include <qqml.h>
+
+#include <QtCore/qlocale.h>
+#include <QtCore/qobject.h>
+#include <private/qv8engine_p.h>
+
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+
+class QQmlDateExtension
+{
+public:
+ static void registerExtension(QV8Engine *engine);
+
+private:
+ static v8::Handle<v8::Value> toLocaleString(const v8::Arguments& args);
+ static v8::Handle<v8::Value> toLocaleTimeString(const v8::Arguments& args);
+ static v8::Handle<v8::Value> toLocaleDateString(const v8::Arguments& args);
+ static v8::Handle<v8::Value> fromLocaleString(const v8::Arguments& args);
+ static v8::Handle<v8::Value> fromLocaleTimeString(const v8::Arguments& args);
+ static v8::Handle<v8::Value> fromLocaleDateString(const v8::Arguments& args);
+};
+
+
+class QQmlNumberExtension
+{
+public:
+ static void registerExtension(QV8Engine *engine);
+
+private:
+ static v8::Handle<v8::Value> toLocaleString(const v8::Arguments& args);
+ static v8::Handle<v8::Value> fromLocaleString(const v8::Arguments& args);
+ static v8::Handle<v8::Value> toLocaleCurrencyString(const v8::Arguments& args);
+};
+
+
+class Q_AUTOTEST_EXPORT QQmlLocale
+{
+ Q_GADGET
+ Q_ENUMS(MeasurementSystem)
+ Q_ENUMS(FormatType)
+ Q_ENUMS(CurrencySymbolFormat)
+ Q_ENUMS(DayOfWeek)
+
+public:
+ ~QQmlLocale();
+
+ enum MeasurementSystem {
+ MetricSystem = QLocale::MetricSystem,
+ ImperialSystem = QLocale::ImperialSystem
+ };
+ enum FormatType {
+ LongFormat = QLocale::LongFormat,
+ ShortFormat = QLocale::ShortFormat,
+ NarrowFormat = QLocale::NarrowFormat
+ };
+ enum CurrencySymbolFormat {
+ CurrencyIsoCode = QLocale::CurrencyIsoCode,
+ CurrencySymbol = QLocale::CurrencySymbol,
+ CurrencyDisplayName = QLocale::CurrencyDisplayName
+ };
+ // Qt defines Sunday as 7, but JS Date assigns Sunday 0
+ enum DayOfWeek {
+ Sunday = 0,
+ Monday = Qt::Monday,
+ Tuesday = Qt::Tuesday,
+ Wednesday = Qt::Wednesday,
+ Thursday = Qt::Thursday,
+ Friday = Qt::Friday,
+ Saturday = Qt::Saturday
+ };
+
+ static v8::Handle<v8::Value> locale(QV8Engine *v8engine, const QString &lang);
+
+ static void registerStringLocaleCompare(QV8Engine *engine);
+
+private:
+ QQmlLocale();
+
+ static v8::Handle<v8::Value> localeCompare(const v8::Arguments &args);
+};
+
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/qml/qml/qqmlmetatype.cpp b/src/qml/qml/qqmlmetatype.cpp
new file mode 100644
index 0000000000..2061530dc5
--- /dev/null
+++ b/src/qml/qml/qqmlmetatype.cpp
@@ -0,0 +1,1359 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtQml/qqmlprivate.h>
+#include "qqmlmetatype_p.h"
+
+#include <private/qqmlproxymetaobject_p.h>
+#include <private/qqmlcustomparser_p.h>
+#include <private/qqmlguard_p.h>
+#include <private/qhashedstring_p.h>
+
+#include <QtCore/qdebug.h>
+#include <QtCore/qstringlist.h>
+#include <QtCore/qmetaobject.h>
+#include <QtCore/qbitarray.h>
+#include <QtCore/qreadwritelock.h>
+#include <QtCore/private/qmetaobject_p.h>
+
+#include <qmetatype.h>
+#include <qobjectdefs.h>
+#include <qbytearray.h>
+#include <qreadwritelock.h>
+#include <qstring.h>
+#include <qstringlist.h>
+#include <qvector.h>
+
+#include <ctype.h>
+
+QT_BEGIN_NAMESPACE
+
+struct QQmlMetaTypeData
+{
+ QQmlMetaTypeData();
+ ~QQmlMetaTypeData();
+ QList<QQmlType *> types;
+ typedef QHash<int, QQmlType *> Ids;
+ Ids idToType;
+ typedef QHash<QString, QQmlType *> Names;
+ Names nameToType;
+ typedef QHash<const QMetaObject *, QQmlType *> MetaObjects;
+ MetaObjects metaObjectToType;
+ typedef QHash<int, QQmlMetaType::StringConverter> StringConverters;
+ StringConverters stringConverters;
+
+ struct VersionedUri {
+ VersionedUri()
+ : majorVersion(0) {}
+ VersionedUri(const QString &uri, int majorVersion)
+ : uri(uri), majorVersion(majorVersion) {}
+ bool operator==(const VersionedUri &other) const {
+ return other.majorVersion == majorVersion && other.uri == uri;
+ }
+ QString uri;
+ int majorVersion;
+ };
+ typedef QHash<VersionedUri, QQmlTypeModule *> TypeModules;
+ TypeModules uriToModule;
+
+ struct ModuleApiList {
+ ModuleApiList() : sorted(true) {}
+ QList<QQmlMetaType::ModuleApi> moduleApis;
+ bool sorted;
+ };
+ typedef QHash<QString, ModuleApiList> ModuleApis;
+ ModuleApis moduleApis;
+ int moduleApiCount;
+
+ QBitArray objects;
+ QBitArray interfaces;
+ QBitArray lists;
+
+ QList<QQmlPrivate::AutoParentFunction> parentFunctions;
+};
+
+class QQmlTypeModulePrivate
+{
+public:
+ QQmlTypeModulePrivate()
+ : minMinorVersion(INT_MAX), maxMinorVersion(0) {}
+
+ QQmlMetaTypeData::VersionedUri uri;
+
+ int minMinorVersion;
+ int maxMinorVersion;
+
+ void add(QQmlType *);
+
+ QStringHash<QList<QQmlType *> > typeHash;
+ QList<QQmlType *> types;
+};
+
+Q_GLOBAL_STATIC(QQmlMetaTypeData, metaTypeData)
+Q_GLOBAL_STATIC(QReadWriteLock, metaTypeDataLock)
+
+static uint qHash(const QQmlMetaTypeData::VersionedUri &v)
+{
+ return qHash(v.uri) ^ qHash(v.majorVersion);
+}
+
+QQmlMetaTypeData::QQmlMetaTypeData()
+: moduleApiCount(0)
+{
+}
+
+QQmlMetaTypeData::~QQmlMetaTypeData()
+{
+ for (int i = 0; i < types.count(); ++i)
+ delete types.at(i);
+}
+
+class QQmlTypePrivate
+{
+public:
+ QQmlTypePrivate();
+
+ void init() const;
+ void initEnums() const;
+
+ bool m_isInterface : 1;
+ const char *m_iid;
+ QString m_module;
+ QString m_name;
+ QString m_elementName;
+ int m_version_maj;
+ int m_version_min;
+ int m_typeId; int m_listId;
+ int m_revision;
+ mutable bool m_containsRevisionedAttributes;
+ mutable QQmlType *m_superType;
+
+ int m_allocationSize;
+ void (*m_newFunc)(void *);
+ QString m_noCreationReason;
+
+ const QMetaObject *m_baseMetaObject;
+ QQmlAttachedPropertiesFunc m_attachedPropertiesFunc;
+ const QMetaObject *m_attachedPropertiesType;
+ int m_attachedPropertiesId;
+ int m_parserStatusCast;
+ int m_propertyValueSourceCast;
+ int m_propertyValueInterceptorCast;
+ QObject *(*m_extFunc)(QObject *);
+ const QMetaObject *m_extMetaObject;
+ int m_index;
+ QQmlCustomParser *m_customParser;
+ mutable volatile bool m_isSetup:1;
+ mutable volatile bool m_isEnumSetup:1;
+ mutable bool m_haveSuperType:1;
+ mutable QList<QQmlProxyMetaObject::ProxyData> m_metaObjects;
+ mutable QStringHash<int> m_enums;
+
+ static QHash<const QMetaObject *, int> m_attachedPropertyIds;
+};
+
+QHash<const QMetaObject *, int> QQmlTypePrivate::m_attachedPropertyIds;
+
+QQmlTypePrivate::QQmlTypePrivate()
+: m_isInterface(false), m_iid(0), m_typeId(0), m_listId(0), m_revision(0), m_containsRevisionedAttributes(false),
+ m_superType(0), m_allocationSize(0), m_newFunc(0), m_baseMetaObject(0), m_attachedPropertiesFunc(0),
+ m_attachedPropertiesType(0), m_parserStatusCast(-1), m_propertyValueSourceCast(-1),
+ m_propertyValueInterceptorCast(-1), m_extFunc(0), m_extMetaObject(0), m_index(-1), m_customParser(0),
+ m_isSetup(false), m_isEnumSetup(false), m_haveSuperType(false)
+{
+}
+
+
+QQmlType::QQmlType(int index, const QQmlPrivate::RegisterInterface &interface)
+: d(new QQmlTypePrivate)
+{
+ d->m_isInterface = true;
+ d->m_iid = interface.iid;
+ d->m_typeId = interface.typeId;
+ d->m_listId = interface.listId;
+ d->m_newFunc = 0;
+ d->m_index = index;
+ d->m_isSetup = true;
+ d->m_version_maj = 0;
+ d->m_version_min = 0;
+}
+
+QQmlType::QQmlType(int index, const QQmlPrivate::RegisterType &type)
+: d(new QQmlTypePrivate)
+{
+ QString name = QString::fromUtf8(type.uri);
+ if (type.uri) name += QLatin1Char('/');
+ name += QString::fromUtf8(type.elementName);
+
+ d->m_module = QString::fromUtf8(type.uri);
+ d->m_name = name;
+ d->m_version_maj = type.versionMajor;
+ d->m_version_min = type.versionMinor;
+ if (type.version >= 1) // revisions added in version 1
+ d->m_revision = type.revision;
+ d->m_typeId = type.typeId;
+ d->m_listId = type.listId;
+ d->m_allocationSize = type.objectSize;
+ d->m_newFunc = type.create;
+ d->m_noCreationReason = type.noCreationReason;
+ d->m_baseMetaObject = type.metaObject;
+ d->m_attachedPropertiesFunc = type.attachedPropertiesFunction;
+ d->m_attachedPropertiesType = type.attachedPropertiesMetaObject;
+ if (d->m_attachedPropertiesType) {
+ QHash<const QMetaObject *, int>::Iterator iter = d->m_attachedPropertyIds.find(d->m_baseMetaObject);
+ if (iter == d->m_attachedPropertyIds.end())
+ iter = d->m_attachedPropertyIds.insert(d->m_baseMetaObject, index);
+ d->m_attachedPropertiesId = *iter;
+ } else {
+ d->m_attachedPropertiesId = -1;
+ }
+ d->m_parserStatusCast = type.parserStatusCast;
+ d->m_propertyValueSourceCast = type.valueSourceCast;
+ d->m_propertyValueInterceptorCast = type.valueInterceptorCast;
+ d->m_extFunc = type.extensionObjectCreate;
+ d->m_index = index;
+ d->m_customParser = type.customParser;
+
+ if (type.extensionMetaObject)
+ d->m_extMetaObject = type.extensionMetaObject;
+}
+
+QQmlType::~QQmlType()
+{
+ delete d->m_customParser;
+ delete d;
+}
+
+QString QQmlType::module() const
+{
+ return d->m_module;
+}
+
+int QQmlType::majorVersion() const
+{
+ return d->m_version_maj;
+}
+
+int QQmlType::minorVersion() const
+{
+ return d->m_version_min;
+}
+
+bool QQmlType::availableInVersion(int vmajor, int vminor) const
+{
+ Q_ASSERT(vmajor >= 0 && vminor >= 0);
+ return vmajor == d->m_version_maj && vminor >= d->m_version_min;
+}
+
+bool QQmlType::availableInVersion(const QString &module, int vmajor, int vminor) const
+{
+ Q_ASSERT(vmajor >= 0 && vminor >= 0);
+ return module == d->m_module && vmajor == d->m_version_maj && vminor >= d->m_version_min;
+}
+
+// returns the nearest _registered_ super class
+QQmlType *QQmlType::superType() const
+{
+ if (!d->m_haveSuperType) {
+ const QMetaObject *mo = d->m_baseMetaObject->superClass();
+ while (mo && !d->m_superType) {
+ d->m_superType = QQmlMetaType::qmlType(mo, d->m_module, d->m_version_maj, d->m_version_min);
+ mo = mo->superClass();
+ }
+ d->m_haveSuperType = true;
+ }
+
+ return d->m_superType;
+}
+
+static void clone(QMetaObjectBuilder &builder, const QMetaObject *mo,
+ const QMetaObject *ignoreStart, const QMetaObject *ignoreEnd)
+{
+ // Set classname
+ builder.setClassName(ignoreEnd->className());
+
+ // Clone Q_CLASSINFO
+ for (int ii = mo->classInfoOffset(); ii < mo->classInfoCount(); ++ii) {
+ QMetaClassInfo info = mo->classInfo(ii);
+
+ int otherIndex = ignoreEnd->indexOfClassInfo(info.name());
+ if (otherIndex >= ignoreStart->classInfoOffset() + ignoreStart->classInfoCount()) {
+ // Skip
+ } else {
+ builder.addClassInfo(info.name(), info.value());
+ }
+ }
+
+ // Clone Q_PROPERTY
+ for (int ii = mo->propertyOffset(); ii < mo->propertyCount(); ++ii) {
+ QMetaProperty property = mo->property(ii);
+
+ int otherIndex = ignoreEnd->indexOfProperty(property.name());
+ if (otherIndex >= ignoreStart->propertyOffset() + ignoreStart->propertyCount()) {
+ builder.addProperty(QByteArray("__qml_ignore__") + property.name(), QByteArray("void"));
+ // Skip
+ } else {
+ builder.addProperty(property);
+ }
+ }
+
+ // Clone Q_METHODS
+ for (int ii = mo->methodOffset(); ii < mo->methodCount(); ++ii) {
+ QMetaMethod method = mo->method(ii);
+
+ // More complex - need to search name
+ QByteArray name = method.signature();
+ int parenIdx = name.indexOf('(');
+ if (parenIdx != -1) name = name.left(parenIdx);
+
+
+ bool found = false;
+
+ for (int ii = ignoreStart->methodOffset() + ignoreStart->methodCount();
+ !found && ii < ignoreEnd->methodOffset() + ignoreEnd->methodCount();
+ ++ii) {
+
+ QMetaMethod other = ignoreEnd->method(ii);
+ QByteArray othername = other.signature();
+ int parenIdx = othername.indexOf('(');
+ if (parenIdx != -1) othername = othername.left(parenIdx);
+
+ found = name == othername;
+ }
+
+ QMetaMethodBuilder m = builder.addMethod(method);
+ if (found) // SKIP
+ m.setAccess(QMetaMethod::Private);
+ }
+
+ // Clone Q_ENUMS
+ for (int ii = mo->enumeratorOffset(); ii < mo->enumeratorCount(); ++ii) {
+ QMetaEnum enumerator = mo->enumerator(ii);
+
+ int otherIndex = ignoreEnd->indexOfEnumerator(enumerator.name());
+ if (otherIndex >= ignoreStart->enumeratorOffset() + ignoreStart->enumeratorCount()) {
+ // Skip
+ } else {
+ builder.addEnumerator(enumerator);
+ }
+ }
+}
+
+static bool isPropertyRevisioned(const QMetaObject *mo, int index)
+{
+ int i = index;
+ i -= mo->propertyOffset();
+ if (i < 0 && mo->d.superdata)
+ return isPropertyRevisioned(mo->d.superdata, index);
+
+ const QMetaObjectPrivate *mop = reinterpret_cast<const QMetaObjectPrivate*>(mo->d.data);
+ if (i >= 0 && i < mop->propertyCount) {
+ int handle = mop->propertyData + 3*i;
+ int flags = mo->d.data[handle + 2];
+
+ return (flags & Revisioned);
+ }
+
+ return false;
+}
+
+void QQmlTypePrivate::init() const
+{
+ if (m_isSetup) return;
+
+ QWriteLocker lock(metaTypeDataLock());
+ if (m_isSetup)
+ return;
+
+ // Setup extended meta object
+ // XXX - very inefficient
+ const QMetaObject *mo = m_baseMetaObject;
+ if (m_extFunc) {
+ QMetaObjectBuilder builder;
+ clone(builder, m_extMetaObject, m_extMetaObject, m_extMetaObject);
+ builder.setFlags(QMetaObjectBuilder::DynamicMetaObject);
+ QMetaObject *mmo = builder.toMetaObject();
+ mmo->d.superdata = mo;
+ QQmlProxyMetaObject::ProxyData data = { mmo, m_extFunc, 0, 0 };
+ m_metaObjects << data;
+ }
+
+ mo = mo->d.superdata;
+ while(mo) {
+ QQmlType *t = metaTypeData()->metaObjectToType.value(mo);
+ if (t) {
+ if (t->d->m_extFunc) {
+ QMetaObjectBuilder builder;
+ clone(builder, t->d->m_extMetaObject, t->d->m_baseMetaObject, m_baseMetaObject);
+ builder.setFlags(QMetaObjectBuilder::DynamicMetaObject);
+ QMetaObject *mmo = builder.toMetaObject();
+ mmo->d.superdata = m_baseMetaObject;
+ if (!m_metaObjects.isEmpty())
+ m_metaObjects.last().metaObject->d.superdata = mmo;
+ QQmlProxyMetaObject::ProxyData data = { mmo, t->d->m_extFunc, 0, 0 };
+ m_metaObjects << data;
+ }
+ }
+ mo = mo->d.superdata;
+ }
+
+ for (int ii = 0; ii < m_metaObjects.count(); ++ii) {
+ m_metaObjects[ii].propertyOffset =
+ m_metaObjects.at(ii).metaObject->propertyOffset();
+ m_metaObjects[ii].methodOffset =
+ m_metaObjects.at(ii).metaObject->methodOffset();
+ }
+
+ // Check for revisioned details
+ {
+ const QMetaObject *mo = 0;
+ if (m_metaObjects.isEmpty())
+ mo = m_baseMetaObject;
+ else
+ mo = m_metaObjects.first().metaObject;
+
+ for (int ii = 0; !m_containsRevisionedAttributes && ii < mo->propertyCount(); ++ii) {
+ if (isPropertyRevisioned(mo, ii))
+ m_containsRevisionedAttributes = true;
+ }
+
+ for (int ii = 0; !m_containsRevisionedAttributes && ii < mo->methodCount(); ++ii) {
+ if (mo->method(ii).revision() != 0)
+ m_containsRevisionedAttributes = true;
+ }
+ }
+
+ m_isSetup = true;
+ lock.unlock();
+}
+
+void QQmlTypePrivate::initEnums() const
+{
+ if (m_isEnumSetup) return;
+
+ init();
+
+ QWriteLocker lock(metaTypeDataLock());
+ if (m_isEnumSetup) return;
+
+ const QMetaObject *metaObject = m_baseMetaObject;
+ for (int ii = 0; ii < metaObject->enumeratorCount(); ++ii) {
+
+ QMetaEnum e = metaObject->enumerator(ii);
+
+ for (int jj = 0; jj < e.keyCount(); ++jj)
+ m_enums.insert(QString::fromUtf8(e.key(jj)), e.value(jj));
+ }
+
+ m_isEnumSetup = true;
+}
+
+QByteArray QQmlType::typeName() const
+{
+ if (d->m_baseMetaObject)
+ return d->m_baseMetaObject->className();
+ else
+ return QByteArray();
+}
+
+const QString &QQmlType::elementName() const
+{
+ if (d->m_elementName.isEmpty()) {
+ QString n = qmlTypeName();
+ int idx = n.lastIndexOf(QLatin1Char('/'));
+ d->m_elementName = n.mid(idx + 1);
+ }
+ return d->m_elementName;
+}
+
+const QString &QQmlType::qmlTypeName() const
+{
+ return d->m_name;
+}
+
+QObject *QQmlType::create() const
+{
+ d->init();
+
+ QObject *rv = (QObject *)operator new(d->m_allocationSize);
+ d->m_newFunc(rv);
+
+ if (rv && !d->m_metaObjects.isEmpty())
+ (void *)new QQmlProxyMetaObject(rv, &d->m_metaObjects);
+
+ return rv;
+}
+
+void QQmlType::create(QObject **out, void **memory, size_t additionalMemory) const
+{
+ d->init();
+
+ QObject *rv = (QObject *)operator new(d->m_allocationSize + additionalMemory);
+ d->m_newFunc(rv);
+
+ if (rv && !d->m_metaObjects.isEmpty())
+ (void *)new QQmlProxyMetaObject(rv, &d->m_metaObjects);
+
+ *out = rv;
+ *memory = ((char *)rv) + d->m_allocationSize;
+}
+
+QQmlCustomParser *QQmlType::customParser() const
+{
+ return d->m_customParser;
+}
+
+QQmlType::CreateFunc QQmlType::createFunction() const
+{
+ return d->m_newFunc;
+}
+
+QString QQmlType::noCreationReason() const
+{
+ return d->m_noCreationReason;
+}
+
+int QQmlType::createSize() const
+{
+ return d->m_allocationSize;
+}
+
+bool QQmlType::isCreatable() const
+{
+ return d->m_newFunc != 0;
+}
+
+bool QQmlType::isExtendedType() const
+{
+ d->init();
+
+ return !d->m_metaObjects.isEmpty();
+}
+
+bool QQmlType::isInterface() const
+{
+ return d->m_isInterface;
+}
+
+int QQmlType::typeId() const
+{
+ return d->m_typeId;
+}
+
+int QQmlType::qListTypeId() const
+{
+ return d->m_listId;
+}
+
+const QMetaObject *QQmlType::metaObject() const
+{
+ d->init();
+
+ if (d->m_metaObjects.isEmpty())
+ return d->m_baseMetaObject;
+ else
+ return d->m_metaObjects.first().metaObject;
+
+}
+
+const QMetaObject *QQmlType::baseMetaObject() const
+{
+ return d->m_baseMetaObject;
+}
+
+bool QQmlType::containsRevisionedAttributes() const
+{
+ d->init();
+
+ return d->m_containsRevisionedAttributes;
+}
+
+int QQmlType::metaObjectRevision() const
+{
+ return d->m_revision;
+}
+
+QQmlAttachedPropertiesFunc QQmlType::attachedPropertiesFunction() const
+{
+ return d->m_attachedPropertiesFunc;
+}
+
+const QMetaObject *QQmlType::attachedPropertiesType() const
+{
+ return d->m_attachedPropertiesType;
+}
+
+/*
+This is the id passed to qmlAttachedPropertiesById(). This is different from the index
+for the case that a single class is registered under two or more names (eg. Item in
+Qt 4.7 and QtQuick 1.0).
+*/
+int QQmlType::attachedPropertiesId() const
+{
+ return d->m_attachedPropertiesId;
+}
+
+int QQmlType::parserStatusCast() const
+{
+ return d->m_parserStatusCast;
+}
+
+int QQmlType::propertyValueSourceCast() const
+{
+ return d->m_propertyValueSourceCast;
+}
+
+int QQmlType::propertyValueInterceptorCast() const
+{
+ return d->m_propertyValueInterceptorCast;
+}
+
+const char *QQmlType::interfaceIId() const
+{
+ return d->m_iid;
+}
+
+int QQmlType::index() const
+{
+ return d->m_index;
+}
+
+int QQmlType::enumValue(const QHashedStringRef &name) const
+{
+ d->initEnums();
+
+ int *rv = d->m_enums.value(name);
+ return rv?*rv:-1;
+}
+
+int QQmlType::enumValue(const QHashedV8String &name) const
+{
+ d->initEnums();
+
+ int *rv = d->m_enums.value(name);
+ return rv?*rv:-1;
+}
+
+QQmlTypeModule::QQmlTypeModule()
+: d(new QQmlTypeModulePrivate)
+{
+}
+
+QQmlTypeModule::~QQmlTypeModule()
+{
+ delete d; d = 0;
+}
+
+QString QQmlTypeModule::module() const
+{
+ return d->uri.uri;
+}
+
+int QQmlTypeModule::majorVersion() const
+{
+ return d->uri.majorVersion;
+}
+
+int QQmlTypeModule::minimumMinorVersion() const
+{
+ return d->minMinorVersion;
+}
+
+int QQmlTypeModule::maximumMinorVersion() const
+{
+ return d->maxMinorVersion;
+}
+
+void QQmlTypeModulePrivate::add(QQmlType *type)
+{
+ types << type;
+
+ minMinorVersion = qMin(minMinorVersion, type->minorVersion());
+ maxMinorVersion = qMax(maxMinorVersion, type->minorVersion());
+
+ QList<QQmlType *> &list = typeHash[type->elementName()];
+ for (int ii = 0; ii < list.count(); ++ii) {
+ if (list.at(ii)->minorVersion() < type->minorVersion()) {
+ list.insert(ii, type);
+ return;
+ }
+ }
+ list.append(type);
+}
+
+QList<QQmlType *> QQmlTypeModule::types()
+{
+ QList<QQmlType *> rv;
+ QReadLocker lock(metaTypeDataLock());
+ rv = d->types;
+ return rv;
+}
+
+QList<QQmlType *> QQmlTypeModule::type(const QString &name)
+{
+ QReadLocker lock(metaTypeDataLock());
+ QList<QQmlType *> rv;
+ for (int ii = 0; ii < d->types.count(); ++ii) {
+ if (d->types.at(ii)->elementName() == name)
+ rv << d->types.at(ii);
+ }
+ return rv;
+}
+
+QQmlType *QQmlTypeModule::type(const QHashedStringRef &name, int minor)
+{
+ QReadLocker lock(metaTypeDataLock());
+
+ QList<QQmlType *> *types = d->typeHash.value(name);
+ if (!types) return 0;
+
+ for (int ii = 0; ii < types->count(); ++ii)
+ if (types->at(ii)->minorVersion() <= minor)
+ return types->at(ii);
+
+ return 0;
+}
+
+QQmlType *QQmlTypeModule::type(const QHashedV8String &name, int minor)
+{
+ QReadLocker lock(metaTypeDataLock());
+
+ QList<QQmlType *> *types = d->typeHash.value(name);
+ if (!types) return 0;
+
+ for (int ii = 0; ii < types->count(); ++ii)
+ if (types->at(ii)->minorVersion() <= minor)
+ return types->at(ii);
+
+ return 0;
+}
+
+
+QQmlTypeModuleVersion::QQmlTypeModuleVersion()
+: m_module(0), m_minor(0)
+{
+}
+
+QQmlTypeModuleVersion::QQmlTypeModuleVersion(QQmlTypeModule *module, int minor)
+: m_module(module), m_minor(minor)
+{
+ Q_ASSERT(m_module);
+ Q_ASSERT(m_minor >= 0);
+}
+
+QQmlTypeModuleVersion::QQmlTypeModuleVersion(const QQmlTypeModuleVersion &o)
+: m_module(o.m_module), m_minor(o.m_minor)
+{
+}
+
+QQmlTypeModuleVersion &QQmlTypeModuleVersion::operator=(const QQmlTypeModuleVersion &o)
+{
+ m_module = o.m_module;
+ m_minor = o.m_minor;
+ return *this;
+}
+
+QQmlTypeModule *QQmlTypeModuleVersion::module() const
+{
+ return m_module;
+}
+
+int QQmlTypeModuleVersion::minorVersion() const
+{
+ return m_minor;
+}
+
+QQmlType *QQmlTypeModuleVersion::type(const QHashedStringRef &name) const
+{
+ if (m_module) return m_module->type(name, m_minor);
+ else return 0;
+}
+
+QQmlType *QQmlTypeModuleVersion::type(const QHashedV8String &name) const
+{
+ if (m_module) return m_module->type(name, m_minor);
+ else return 0;
+}
+
+
+int registerAutoParentFunction(QQmlPrivate::RegisterAutoParent &autoparent)
+{
+ QWriteLocker lock(metaTypeDataLock());
+ QQmlMetaTypeData *data = metaTypeData();
+
+ data->parentFunctions.append(autoparent.function);
+
+ return data->parentFunctions.count() - 1;
+}
+
+int registerInterface(const QQmlPrivate::RegisterInterface &interface)
+{
+ if (interface.version > 0)
+ qFatal("qmlRegisterType(): Cannot mix incompatible QML versions.");
+
+ QWriteLocker lock(metaTypeDataLock());
+ QQmlMetaTypeData *data = metaTypeData();
+
+ int index = data->types.count();
+
+ QQmlType *type = new QQmlType(index, interface);
+
+ data->types.append(type);
+ data->idToType.insert(type->typeId(), type);
+ data->idToType.insert(type->qListTypeId(), type);
+ // XXX No insertMulti, so no multi-version interfaces?
+ if (!type->qmlTypeName().isEmpty())
+ data->nameToType.insert(type->qmlTypeName(), type);
+
+ if (data->interfaces.size() <= interface.typeId)
+ data->interfaces.resize(interface.typeId + 16);
+ if (data->lists.size() <= interface.listId)
+ data->lists.resize(interface.listId + 16);
+ data->interfaces.setBit(interface.typeId, true);
+ data->lists.setBit(interface.listId, true);
+
+ return index;
+}
+
+int registerType(const QQmlPrivate::RegisterType &type)
+{
+ if (type.elementName) {
+ for (int ii = 0; type.elementName[ii]; ++ii) {
+ if (!isalnum(type.elementName[ii])) {
+ qWarning("qmlRegisterType(): Invalid QML element name \"%s\"", type.elementName);
+ return -1;
+ }
+ }
+ }
+
+ QWriteLocker lock(metaTypeDataLock());
+ QQmlMetaTypeData *data = metaTypeData();
+ int index = data->types.count();
+
+ QQmlType *dtype = new QQmlType(index, type);
+
+ data->types.append(dtype);
+ data->idToType.insert(dtype->typeId(), dtype);
+ if (dtype->qListTypeId()) data->idToType.insert(dtype->qListTypeId(), dtype);
+
+ if (!dtype->qmlTypeName().isEmpty())
+ data->nameToType.insertMulti(dtype->qmlTypeName(), dtype);
+
+ data->metaObjectToType.insertMulti(dtype->baseMetaObject(), dtype);
+
+ if (data->objects.size() <= type.typeId)
+ data->objects.resize(type.typeId + 16);
+ if (data->lists.size() <= type.listId)
+ data->lists.resize(type.listId + 16);
+ data->objects.setBit(type.typeId, true);
+ if (type.listId) data->lists.setBit(type.listId, true);
+
+ if (type.uri) {
+ QString mod = QString::fromUtf8(type.uri);
+
+ QQmlMetaTypeData::VersionedUri versionedUri(mod, type.versionMajor);
+ QQmlTypeModule *module = data->uriToModule.value(versionedUri);
+ if (!module) {
+ module = new QQmlTypeModule;
+ module->d->uri = versionedUri;
+ data->uriToModule.insert(versionedUri, module);
+ }
+ module->d->add(dtype);
+ }
+
+ return index;
+}
+
+int registerModuleApi(const QQmlPrivate::RegisterModuleApi &api)
+{
+ QWriteLocker lock(metaTypeDataLock());
+
+ QQmlMetaTypeData *data = metaTypeData();
+ QString uri = QString::fromUtf8(api.uri);
+ QQmlMetaType::ModuleApi import;
+ import.major = api.versionMajor;
+ import.minor = api.versionMinor;
+ import.script = api.scriptApi;
+ import.qobject = api.qobjectApi;
+
+ int index = data->moduleApiCount++;
+
+ QQmlMetaTypeData::ModuleApis::Iterator iter = data->moduleApis.find(uri);
+ if (iter == data->moduleApis.end()) {
+ QQmlMetaTypeData::ModuleApiList apis;
+ apis.moduleApis << import;
+ data->moduleApis.insert(uri, apis);
+ } else {
+ iter->moduleApis << import;
+ iter->sorted = false;
+ }
+
+ return index;
+}
+
+
+/*
+This method is "over generalized" to allow us to (potentially) register more types of things in
+the future without adding exported symbols.
+*/
+int QQmlPrivate::qmlregister(RegistrationType type, void *data)
+{
+ if (type == TypeRegistration) {
+ return registerType(*reinterpret_cast<RegisterType *>(data));
+ } else if (type == InterfaceRegistration) {
+ return registerInterface(*reinterpret_cast<RegisterInterface *>(data));
+ } else if (type == AutoParentRegistration) {
+ return registerAutoParentFunction(*reinterpret_cast<RegisterAutoParent *>(data));
+ } else if (type == ModuleApiRegistration) {
+ return registerModuleApi(*reinterpret_cast<RegisterModuleApi *>(data));
+ }
+ return -1;
+}
+
+/*
+ Returns true if a module \a uri of any version is installed.
+*/
+bool QQmlMetaType::isAnyModule(const QString &uri)
+{
+ QReadLocker lock(metaTypeDataLock());
+ QQmlMetaTypeData *data = metaTypeData();
+
+ for (QQmlMetaTypeData::TypeModules::ConstIterator iter = data->uriToModule.begin();
+ iter != data->uriToModule.end(); ++iter) {
+ if ((*iter)->module() == uri)
+ return true;
+ }
+
+ return false;
+}
+
+/*
+ Returns true if any type or API has been registered for the given \a module with at least
+ versionMajor.versionMinor, or if types have been registered for \a module with at most
+ versionMajor.versionMinor.
+
+ So if only 4.7 and 4.9 have been registered, 4.7,4.8, and 4.9 are valid, but not 4.6 nor 4.10.
+*/
+bool QQmlMetaType::isModule(const QString &module, int versionMajor, int versionMinor)
+{
+ Q_ASSERT(versionMajor >= 0 && versionMinor >= 0);
+ QReadLocker lock(metaTypeDataLock());
+
+ QQmlMetaTypeData *data = metaTypeData();
+
+ // first, check Types
+ QQmlTypeModule *tm =
+ data->uriToModule.value(QQmlMetaTypeData::VersionedUri(module, versionMajor));
+ if (tm && tm->minimumMinorVersion() <= versionMinor && tm->maximumMinorVersion() >= versionMinor)
+ return true;
+
+ // then, check ModuleApis
+ foreach (const QQmlMetaType::ModuleApi &mApi, data->moduleApis.value(module).moduleApis) {
+ if (mApi.major == versionMajor && mApi.minor == versionMinor) // XXX is this correct?
+ return true;
+ }
+
+ return false;
+}
+
+QQmlTypeModule *QQmlMetaType::typeModule(const QString &uri, int majorVersion)
+{
+ QReadLocker lock(metaTypeDataLock());
+ QQmlMetaTypeData *data = metaTypeData();
+ return data->uriToModule.value(QQmlMetaTypeData::VersionedUri(uri, majorVersion));
+}
+
+QList<QQmlPrivate::AutoParentFunction> QQmlMetaType::parentFunctions()
+{
+ QReadLocker lock(metaTypeDataLock());
+ QQmlMetaTypeData *data = metaTypeData();
+ return data->parentFunctions;
+}
+
+static bool operator<(const QQmlMetaType::ModuleApi &lhs, const QQmlMetaType::ModuleApi &rhs)
+{
+ return lhs.major < rhs.major || (lhs.major == rhs.major && lhs.minor < rhs.minor);
+}
+
+QQmlMetaType::ModuleApi
+QQmlMetaType::moduleApi(const QString &uri, int versionMajor, int versionMinor)
+{
+ QReadLocker lock(metaTypeDataLock());
+ QQmlMetaTypeData *data = metaTypeData();
+
+ QQmlMetaTypeData::ModuleApis::Iterator iter = data->moduleApis.find(uri);
+ if (iter == data->moduleApis.end())
+ return ModuleApi();
+
+ if (iter->sorted == false) {
+ qSort(iter->moduleApis.begin(), iter->moduleApis.end());
+ iter->sorted = true;
+ }
+
+ for (int ii = iter->moduleApis.count() - 1; ii >= 0; --ii) {
+ const ModuleApi &import = iter->moduleApis.at(ii);
+ if (import.major == versionMajor && import.minor <= versionMinor)
+ return import;
+ }
+
+ return ModuleApi();
+}
+
+QHash<QString, QList<QQmlMetaType::ModuleApi> > QQmlMetaType::moduleApis()
+{
+ QReadLocker lock(metaTypeDataLock());
+ QQmlMetaTypeData *data = metaTypeData();
+
+ QHash<QString, QList<ModuleApi> > moduleApis;
+ QHashIterator<QString, QQmlMetaTypeData::ModuleApiList> it(data->moduleApis);
+ while (it.hasNext()) {
+ it.next();
+ moduleApis[it.key()] = it.value().moduleApis;
+ }
+
+ return moduleApis;
+}
+
+QObject *QQmlMetaType::toQObject(const QVariant &v, bool *ok)
+{
+ if (!isQObject(v.userType())) {
+ if (ok) *ok = false;
+ return 0;
+ }
+
+ if (ok) *ok = true;
+
+ return *(QObject **)v.constData();
+}
+
+bool QQmlMetaType::isQObject(int userType)
+{
+ if (userType == QMetaType::QObjectStar)
+ return true;
+
+ QReadLocker lock(metaTypeDataLock());
+ QQmlMetaTypeData *data = metaTypeData();
+ return userType >= 0 && userType < data->objects.size() && data->objects.testBit(userType);
+}
+
+/*
+ Returns the item type for a list of type \a id.
+ */
+int QQmlMetaType::listType(int id)
+{
+ QReadLocker lock(metaTypeDataLock());
+ QQmlMetaTypeData *data = metaTypeData();
+ QQmlType *type = data->idToType.value(id);
+ if (type && type->qListTypeId() == id)
+ return type->typeId();
+ else
+ return 0;
+}
+
+int QQmlMetaType::attachedPropertiesFuncId(const QMetaObject *mo)
+{
+ QReadLocker lock(metaTypeDataLock());
+ QQmlMetaTypeData *data = metaTypeData();
+
+ QQmlType *type = data->metaObjectToType.value(mo);
+ if (type && type->attachedPropertiesFunction())
+ return type->attachedPropertiesId();
+ else
+ return -1;
+}
+
+QQmlAttachedPropertiesFunc QQmlMetaType::attachedPropertiesFuncById(int id)
+{
+ if (id < 0)
+ return 0;
+ QReadLocker lock(metaTypeDataLock());
+ QQmlMetaTypeData *data = metaTypeData();
+ return data->types.at(id)->attachedPropertiesFunction();
+}
+
+QMetaProperty QQmlMetaType::defaultProperty(const QMetaObject *metaObject)
+{
+ int idx = metaObject->indexOfClassInfo("DefaultProperty");
+ if (-1 == idx)
+ return QMetaProperty();
+
+ QMetaClassInfo info = metaObject->classInfo(idx);
+ if (!info.value())
+ return QMetaProperty();
+
+ idx = metaObject->indexOfProperty(info.value());
+ if (-1 == idx)
+ return QMetaProperty();
+
+ return metaObject->property(idx);
+}
+
+QMetaProperty QQmlMetaType::defaultProperty(QObject *obj)
+{
+ if (!obj)
+ return QMetaProperty();
+
+ const QMetaObject *metaObject = obj->metaObject();
+ return defaultProperty(metaObject);
+}
+
+QMetaMethod QQmlMetaType::defaultMethod(const QMetaObject *metaObject)
+{
+ int idx = metaObject->indexOfClassInfo("DefaultMethod");
+ if (-1 == idx)
+ return QMetaMethod();
+
+ QMetaClassInfo info = metaObject->classInfo(idx);
+ if (!info.value())
+ return QMetaMethod();
+
+ idx = metaObject->indexOfMethod(info.value());
+ if (-1 == idx)
+ return QMetaMethod();
+
+ return metaObject->method(idx);
+}
+
+QMetaMethod QQmlMetaType::defaultMethod(QObject *obj)
+{
+ if (!obj)
+ return QMetaMethod();
+
+ const QMetaObject *metaObject = obj->metaObject();
+ return defaultMethod(metaObject);
+}
+
+QQmlMetaType::TypeCategory QQmlMetaType::typeCategory(int userType)
+{
+ if (userType < 0)
+ return Unknown;
+ if (userType == QMetaType::QObjectStar)
+ return Object;
+
+ QReadLocker lock(metaTypeDataLock());
+ QQmlMetaTypeData *data = metaTypeData();
+ if (userType < data->objects.size() && data->objects.testBit(userType))
+ return Object;
+ else if (userType < data->lists.size() && data->lists.testBit(userType))
+ return List;
+ else
+ return Unknown;
+}
+
+bool QQmlMetaType::isInterface(int userType)
+{
+ QReadLocker lock(metaTypeDataLock());
+ QQmlMetaTypeData *data = metaTypeData();
+ return userType >= 0 && userType < data->interfaces.size() && data->interfaces.testBit(userType);
+}
+
+const char *QQmlMetaType::interfaceIId(int userType)
+{
+ QReadLocker lock(metaTypeDataLock());
+ QQmlMetaTypeData *data = metaTypeData();
+ QQmlType *type = data->idToType.value(userType);
+ lock.unlock();
+ if (type && type->isInterface() && type->typeId() == userType)
+ return type->interfaceIId();
+ else
+ return 0;
+}
+
+bool QQmlMetaType::isList(int userType)
+{
+ QReadLocker lock(metaTypeDataLock());
+ QQmlMetaTypeData *data = metaTypeData();
+ return userType >= 0 && userType < data->lists.size() && data->lists.testBit(userType);
+}
+
+/*!
+ A custom string convertor allows you to specify a function pointer that
+ returns a variant of \a type. For example, if you have written your own icon
+ class that you want to support as an object property assignable in QML:
+
+ \code
+ int type = qRegisterMetaType<SuperIcon>("SuperIcon");
+ QML::addCustomStringConvertor(type, &SuperIcon::pixmapFromString);
+ \endcode
+
+ The function pointer must be of the form:
+ \code
+ QVariant (*StringConverter)(const QString &);
+ \endcode
+ */
+void QQmlMetaType::registerCustomStringConverter(int type, StringConverter converter)
+{
+ QWriteLocker lock(metaTypeDataLock());
+
+ QQmlMetaTypeData *data = metaTypeData();
+ if (data->stringConverters.contains(type))
+ return;
+ data->stringConverters.insert(type, converter);
+}
+
+/*!
+ Return the custom string converter for \a type, previously installed through
+ registerCustomStringConverter()
+ */
+QQmlMetaType::StringConverter QQmlMetaType::customStringConverter(int type)
+{
+ QReadLocker lock(metaTypeDataLock());
+
+ QQmlMetaTypeData *data = metaTypeData();
+ return data->stringConverters.value(type);
+}
+
+/*!
+ Returns the type (if any) of URI-qualified named \a name in version specified
+ by \a version_major and \a version_minor.
+*/
+QQmlType *QQmlMetaType::qmlType(const QString &name, int version_major, int version_minor)
+{
+ Q_ASSERT(version_major >= 0 && version_minor >= 0);
+ QReadLocker lock(metaTypeDataLock());
+ QQmlMetaTypeData *data = metaTypeData();
+
+ QQmlMetaTypeData::Names::ConstIterator it = data->nameToType.find(name);
+ while (it != data->nameToType.end()) {
+ // XXX version_major<0 just a kludge for QQmlPropertyPrivate::initProperty
+ if (it.key() == name && (version_major<0 || (*it)->availableInVersion(version_major,version_minor)))
+ return (*it);
+ ++it;
+ }
+
+ return 0;
+}
+
+/*!
+ Returns the type (if any) that corresponds to the \a metaObject. Returns null if no
+ type is registered.
+*/
+QQmlType *QQmlMetaType::qmlType(const QMetaObject *metaObject)
+{
+ QReadLocker lock(metaTypeDataLock());
+ QQmlMetaTypeData *data = metaTypeData();
+
+ return data->metaObjectToType.value(metaObject);
+}
+
+/*!
+ Returns the type (if any) that corresponds to the \a metaObject in version specified
+ by \a version_major and \a version_minor in module specified by \a uri. Returns null if no
+ type is registered.
+*/
+QQmlType *QQmlMetaType::qmlType(const QMetaObject *metaObject, const QString &module, int version_major, int version_minor)
+{
+ Q_ASSERT(version_major >= 0 && version_minor >= 0);
+ QReadLocker lock(metaTypeDataLock());
+ QQmlMetaTypeData *data = metaTypeData();
+
+ QQmlMetaTypeData::MetaObjects::const_iterator it = data->metaObjectToType.find(metaObject);
+ while (it != data->metaObjectToType.end() && it.key() == metaObject) {
+ QQmlType *t = *it;
+ if (version_major < 0 || t->availableInVersion(module, version_major,version_minor))
+ return t;
+ ++it;
+ }
+
+ return 0;
+}
+
+/*!
+ Returns the type (if any) that corresponds to the QVariant::Type \a userType.
+ Returns null if no type is registered.
+*/
+QQmlType *QQmlMetaType::qmlType(int userType)
+{
+ QReadLocker lock(metaTypeDataLock());
+ QQmlMetaTypeData *data = metaTypeData();
+
+ QQmlType *type = data->idToType.value(userType);
+ if (type && type->typeId() == userType)
+ return type;
+ else
+ return 0;
+}
+
+/*!
+ Returns the list of registered QML type names.
+*/
+QList<QString> QQmlMetaType::qmlTypeNames()
+{
+ QReadLocker lock(metaTypeDataLock());
+ QQmlMetaTypeData *data = metaTypeData();
+
+ return data->nameToType.keys();
+}
+
+/*!
+ Returns the list of registered QML types.
+*/
+QList<QQmlType*> QQmlMetaType::qmlTypes()
+{
+ QReadLocker lock(metaTypeDataLock());
+ QQmlMetaTypeData *data = metaTypeData();
+
+ return data->nameToType.values();
+}
+
+int QQmlMetaType::QQuickAnchorLineMetaTypeId()
+{
+ static int id = 0;
+ if (!id) {
+ id = QMetaType::type("QQuickAnchorLine");
+ }
+ return id;
+}
+
+QQmlMetaType::CompareFunction QQmlMetaType::anchorLineCompareFunction = 0;
+
+void QQmlMetaType::setQQuickAnchorLineCompareFunction(CompareFunction fun)
+{
+ anchorLineCompareFunction = fun;
+}
+
+bool QQmlMetaType::QQuickAnchorLineCompare(const void *p1, const void *p2)
+{
+ Q_ASSERT(anchorLineCompareFunction != 0);
+ return anchorLineCompareFunction(p1, p2);
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlmetatype_p.h b/src/qml/qml/qqmlmetatype_p.h
new file mode 100644
index 0000000000..ad6a2aa055
--- /dev/null
+++ b/src/qml/qml/qqmlmetatype_p.h
@@ -0,0 +1,268 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLMETATYPE_P_H
+#define QQMLMETATYPE_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qqml.h"
+#include <private/qtqmlglobal_p.h>
+
+#include <QtCore/qglobal.h>
+#include <QtCore/qvariant.h>
+#include <QtCore/qbitarray.h>
+#include <QtQml/qjsvalue.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQmlType;
+class QQmlCustomParser;
+class QQmlTypePrivate;
+class QQmlTypeModule;
+
+class Q_QML_PRIVATE_EXPORT QQmlMetaType
+{
+public:
+ static QList<QString> qmlTypeNames();
+ static QList<QQmlType*> qmlTypes();
+
+ static QQmlType *qmlType(const QString &, int, int);
+ static QQmlType *qmlType(const QMetaObject *);
+ static QQmlType *qmlType(const QMetaObject *metaObject, const QString &module, int version_major, int version_minor);
+ static QQmlType *qmlType(int);
+
+ static QMetaProperty defaultProperty(const QMetaObject *);
+ static QMetaProperty defaultProperty(QObject *);
+ static QMetaMethod defaultMethod(const QMetaObject *);
+ static QMetaMethod defaultMethod(QObject *);
+
+ static bool isQObject(int);
+ static QObject *toQObject(const QVariant &, bool *ok = 0);
+
+ static int listType(int);
+ static int attachedPropertiesFuncId(const QMetaObject *);
+ static QQmlAttachedPropertiesFunc attachedPropertiesFuncById(int);
+
+ enum TypeCategory { Unknown, Object, List };
+ static TypeCategory typeCategory(int);
+
+ static bool isInterface(int);
+ static const char *interfaceIId(int);
+ static bool isList(int);
+
+ typedef QVariant (*StringConverter)(const QString &);
+ static void registerCustomStringConverter(int, StringConverter);
+ static StringConverter customStringConverter(int);
+
+ static bool isAnyModule(const QString &uri);
+ static bool isModule(const QString &module, int versionMajor, int versionMinor);
+ static QQmlTypeModule *typeModule(const QString &uri, int majorVersion);
+
+ static QList<QQmlPrivate::AutoParentFunction> parentFunctions();
+
+ static int QQuickAnchorLineMetaTypeId();
+ typedef bool (*CompareFunction)(const void *, const void *);
+ static void setQQuickAnchorLineCompareFunction(CompareFunction);
+ static bool QQuickAnchorLineCompare(const void *p1, const void *p2);
+
+ struct ModuleApiInstance {
+ ModuleApiInstance()
+ : scriptCallback(0), qobjectCallback(0), qobjectApi(0) {}
+
+ QJSValue (*scriptCallback)(QQmlEngine *, QJSEngine *);
+ QObject *(*qobjectCallback)(QQmlEngine *, QJSEngine *);
+ QJSValue scriptApi;
+ QObject *qobjectApi;
+ };
+ struct ModuleApi {
+ inline ModuleApi();
+ inline bool operator==(const ModuleApi &) const;
+ int major;
+ int minor;
+ QJSValue (*script)(QQmlEngine *, QJSEngine *);
+ QObject *(*qobject)(QQmlEngine *, QJSEngine *);
+ };
+ static ModuleApi moduleApi(const QString &, int, int);
+ static QHash<QString, QList<ModuleApi> > moduleApis();
+
+private:
+ static CompareFunction anchorLineCompareFunction;
+};
+
+class QHashedStringRef;
+class QHashedV8String;
+class Q_QML_PRIVATE_EXPORT QQmlType
+{
+public:
+ QByteArray typeName() const;
+ const QString &qmlTypeName() const;
+ const QString &elementName() const;
+
+ QString module() const;
+ int majorVersion() const;
+ int minorVersion() const;
+
+ bool availableInVersion(int vmajor, int vminor) const;
+ bool availableInVersion(const QString &module, int vmajor, int vminor) const;
+
+ QObject *create() const;
+ void create(QObject **, void **, size_t) const;
+
+ typedef void (*CreateFunc)(void *);
+ CreateFunc createFunction() const;
+ int createSize() const;
+
+ QQmlCustomParser *customParser() const;
+
+ bool isCreatable() const;
+ bool isExtendedType() const;
+ QString noCreationReason() const;
+
+ bool isInterface() const;
+ int typeId() const;
+ int qListTypeId() const;
+
+ const QMetaObject *metaObject() const;
+ const QMetaObject *baseMetaObject() const;
+ int metaObjectRevision() const;
+ bool containsRevisionedAttributes() const;
+
+ QQmlAttachedPropertiesFunc attachedPropertiesFunction() const;
+ const QMetaObject *attachedPropertiesType() const;
+ int attachedPropertiesId() const;
+
+ int parserStatusCast() const;
+ QVariant fromObject(QObject *) const;
+ const char *interfaceIId() const;
+ int propertyValueSourceCast() const;
+ int propertyValueInterceptorCast() const;
+
+ int index() const;
+
+ int enumValue(const QHashedStringRef &) const;
+ int enumValue(const QHashedV8String &) const;
+private:
+ QQmlType *superType() const;
+ friend class QQmlTypePrivate;
+ friend struct QQmlMetaTypeData;
+ friend int registerType(const QQmlPrivate::RegisterType &);
+ friend int registerInterface(const QQmlPrivate::RegisterInterface &);
+ QQmlType(int, const QQmlPrivate::RegisterInterface &);
+ QQmlType(int, const QQmlPrivate::RegisterType &);
+ ~QQmlType();
+
+ QQmlTypePrivate *d;
+};
+
+class QQmlTypeModulePrivate;
+class QQmlTypeModule
+{
+public:
+ QString module() const;
+ int majorVersion() const;
+
+ int minimumMinorVersion() const;
+ int maximumMinorVersion() const;
+
+ QList<QQmlType *> types();
+ QList<QQmlType *> type(const QString &);
+
+ QQmlType *type(const QHashedStringRef &, int);
+ QQmlType *type(const QHashedV8String &, int);
+
+private:
+ friend int registerType(const QQmlPrivate::RegisterType &);
+ QQmlTypeModule();
+ ~QQmlTypeModule();
+ QQmlTypeModulePrivate *d;
+};
+
+class QQmlTypeModuleVersion
+{
+public:
+ QQmlTypeModuleVersion();
+ QQmlTypeModuleVersion(QQmlTypeModule *, int);
+ QQmlTypeModuleVersion(const QQmlTypeModuleVersion &);
+ QQmlTypeModuleVersion &operator=(const QQmlTypeModuleVersion &);
+
+ QQmlTypeModule *module() const;
+ int minorVersion() const;
+
+ QQmlType *type(const QHashedStringRef &) const;
+ QQmlType *type(const QHashedV8String &) const;
+
+private:
+ QQmlTypeModule *m_module;
+ int m_minor;
+};
+
+QQmlMetaType::ModuleApi::ModuleApi()
+{
+ major = 0;
+ minor = 0;
+ script = 0;
+ qobject = 0;
+}
+
+bool QQmlMetaType::ModuleApi::operator==(const ModuleApi &other) const
+{
+ return major == other.major && minor == other.minor && script == other.script && qobject == other.qobject;
+}
+
+inline uint qHash(const QQmlMetaType::ModuleApi &import)
+{
+ return import.major ^ import.minor ^ quintptr(import.script) ^ quintptr(import.qobject);
+}
+
+QT_END_NAMESPACE
+
+#endif // QQMLMETATYPE_P_H
+
diff --git a/src/qml/qml/qqmlnetworkaccessmanagerfactory.cpp b/src/qml/qml/qqmlnetworkaccessmanagerfactory.cpp
new file mode 100644
index 0000000000..cc33f387d9
--- /dev/null
+++ b/src/qml/qml/qqmlnetworkaccessmanagerfactory.cpp
@@ -0,0 +1,103 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qqmlnetworkaccessmanagerfactory.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QQmlNetworkAccessManagerFactory
+ \since 4.7
+ \brief The QQmlNetworkAccessManagerFactory class creates QNetworkAccessManager instances for a QML engine.
+
+ A QML engine uses QNetworkAccessManager for all network access.
+ By implementing a factory, it is possible to provide the QML engine
+ with custom QNetworkAccessManager instances with specialized caching,
+ proxy and cookies support.
+
+ To implement a factory, subclass QQmlNetworkAccessManagerFactory and
+ implement the virtual create() method, then assign it to the relevant QML
+ engine using QQmlEngine::setNetworkAccessManagerFactory().
+
+ Note the QML engine may create QNetworkAccessManager instances
+ from multiple threads. Because of this, the implementation of the create()
+ method must be \l{Reentrancy and Thread-Safety}{reentrant}. In addition,
+ the developer should be careful if the signals of the object to be
+ returned from create() are connected to the slots of an object that may
+ be created in a different thread:
+
+ \list
+ \o The QML engine internally handles all requests, and cleans up any
+ QNetworkReply objects it creates. Receiving the
+ QNetworkAccessManager::finished() signal in another thread may not
+ provide the receiver with a valid reply object if it has already
+ been deleted.
+ \o Authentication details provided to QNetworkAccessManager::authenticationRequired()
+ must be provided immediately, so this signal cannot be connected as a
+ Qt::QueuedConnection (or as the default Qt::AutoConnection from another
+ thread).
+ \endlist
+
+ For more information about signals and threads, see
+ \l {Threads and QObjects} and \l {Signals and Slots Across Threads}.
+
+ \sa {declarative/cppextensions/networkaccessmanagerfactory}{NetworkAccessManagerFactory example}
+*/
+
+/*!
+ Destroys the factory. The default implementation does nothing.
+ */
+QQmlNetworkAccessManagerFactory::~QQmlNetworkAccessManagerFactory()
+{
+}
+
+/*!
+ \fn QNetworkAccessManager *QQmlNetworkAccessManagerFactory::create(QObject *parent)
+
+ Creates and returns a network access manager with the specified \a parent.
+ This method must return a new QNetworkAccessManager instance each time
+ it is called.
+
+ Note: this method may be called by multiple threads, so ensure the
+ implementation of this method is reentrant.
+*/
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlnetworkaccessmanagerfactory.h b/src/qml/qml/qqmlnetworkaccessmanagerfactory.h
new file mode 100644
index 0000000000..ac3583cf4c
--- /dev/null
+++ b/src/qml/qml/qqmlnetworkaccessmanagerfactory.h
@@ -0,0 +1,66 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLNETWORKACCESSMANAGERFACTORY_H
+#define QQMLNETWORKACCESSMANAGERFACTORY_H
+
+#include <QtQml/qtqmlglobal.h>
+#include <QtCore/qobject.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+
+class QNetworkAccessManager;
+class Q_QML_EXPORT QQmlNetworkAccessManagerFactory
+{
+public:
+ virtual ~QQmlNetworkAccessManagerFactory();
+ virtual QNetworkAccessManager *create(QObject *parent) = 0;
+
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QQMLNETWORKACCESSMANAGERFACTORY_H
diff --git a/src/qml/qml/qqmlnotifier.cpp b/src/qml/qml/qqmlnotifier.cpp
new file mode 100644
index 0000000000..270eee52b4
--- /dev/null
+++ b/src/qml/qml/qqmlnotifier.cpp
@@ -0,0 +1,115 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qqmlnotifier_p.h"
+#include "qqmlproperty_p.h"
+
+QT_BEGIN_NAMESPACE
+
+void QQmlNotifier::emitNotify(QQmlNotifierEndpoint *endpoint)
+{
+ QQmlNotifierEndpoint **oldDisconnected = endpoint->disconnected;
+ endpoint->disconnected = &endpoint;
+ endpoint->notifying = 1;
+
+ if (endpoint->next)
+ emitNotify(endpoint->next);
+
+ if (endpoint) {
+
+ Q_ASSERT(endpoint->callback);
+
+ endpoint->callback(endpoint);
+
+ if (endpoint)
+ endpoint->disconnected = oldDisconnected;
+ }
+
+ if (oldDisconnected) *oldDisconnected = endpoint;
+ else if (endpoint) endpoint->notifying = 0;
+}
+
+void QQmlNotifierEndpoint::connect(QObject *source, int sourceSignal)
+{
+ disconnect();
+
+ this->source = source;
+ this->sourceSignal = sourceSignal;
+ QQmlPropertyPrivate::flushSignal(source, sourceSignal);
+ QQmlData *ddata = QQmlData::get(source, true);
+ ddata->addNotify(sourceSignal, this);
+}
+
+void QQmlNotifierEndpoint::copyAndClear(QQmlNotifierEndpoint &other)
+{
+ if (&other == this)
+ return;
+
+ other.disconnect();
+
+ other.callback = callback;
+
+ if (!isConnected())
+ return;
+
+ other.notifier = notifier;
+ other.sourceSignal = sourceSignal;
+ other.disconnected = disconnected;
+ other.notifying = notifying;
+ if (other.disconnected) *other.disconnected = &other;
+
+ if (next) {
+ other.next = next;
+ next->prev = &other.next;
+ }
+ other.prev = prev;
+ *other.prev = &other;
+
+ prev = 0;
+ next = 0;
+ disconnected = 0;
+ notifier = 0;
+ notifying = 0;
+ sourceSignal = -1;
+}
+
+QT_END_NAMESPACE
+
diff --git a/src/qml/qml/qqmlnotifier_p.h b/src/qml/qml/qqmlnotifier_p.h
new file mode 100644
index 0000000000..ab0711341d
--- /dev/null
+++ b/src/qml/qml/qqmlnotifier_p.h
@@ -0,0 +1,206 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLNOTIFIER_P_H
+#define QQMLNOTIFIER_P_H
+
+#include "qqmldata_p.h"
+#include "qqmlguard_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QQmlNotifierEndpoint;
+class Q_QML_EXPORT QQmlNotifier
+{
+public:
+ inline QQmlNotifier();
+ inline ~QQmlNotifier();
+ inline void notify();
+
+private:
+ friend class QQmlData;
+ friend class QQmlNotifierEndpoint;
+
+ static void emitNotify(QQmlNotifierEndpoint *);
+ QQmlNotifierEndpoint *endpoints;
+};
+
+class QQmlNotifierEndpoint
+{
+public:
+ inline QQmlNotifierEndpoint();
+ inline ~QQmlNotifierEndpoint();
+
+ typedef void (*Callback)(QQmlNotifierEndpoint *);
+ Callback callback;
+
+ inline bool isConnected();
+ inline bool isConnected(QObject *source, int sourceSignal);
+ inline bool isConnected(QQmlNotifier *);
+
+ void connect(QObject *source, int sourceSignal);
+ inline void connect(QQmlNotifier *);
+ inline void disconnect();
+
+ inline bool isNotifying() const;
+ inline void cancelNotify();
+
+ void copyAndClear(QQmlNotifierEndpoint &other);
+
+private:
+ friend class QQmlData;
+ friend class QQmlNotifier;
+
+ union {
+ QQmlNotifier *notifier;
+ QObject *source;
+ };
+ unsigned int notifying : 1;
+ signed int sourceSignal : 31;
+ QQmlNotifierEndpoint **disconnected;
+ QQmlNotifierEndpoint *next;
+ QQmlNotifierEndpoint **prev;
+};
+
+QQmlNotifier::QQmlNotifier()
+: endpoints(0)
+{
+}
+
+QQmlNotifier::~QQmlNotifier()
+{
+ QQmlNotifierEndpoint *endpoint = endpoints;
+ while (endpoint) {
+ QQmlNotifierEndpoint *n = endpoint;
+ endpoint = n->next;
+
+ n->next = 0;
+ n->prev = 0;
+ n->notifier = 0;
+ n->sourceSignal = -1;
+ if (n->disconnected) *n->disconnected = 0;
+ n->disconnected = 0;
+ }
+ endpoints = 0;
+}
+
+void QQmlNotifier::notify()
+{
+ if (endpoints) emitNotify(endpoints);
+}
+
+QQmlNotifierEndpoint::QQmlNotifierEndpoint()
+: callback(0), notifier(0), notifying(0), sourceSignal(-1), disconnected(0), next(0), prev(0)
+{
+}
+
+QQmlNotifierEndpoint::~QQmlNotifierEndpoint()
+{
+ disconnect();
+}
+
+bool QQmlNotifierEndpoint::isConnected()
+{
+ return prev != 0;
+}
+
+bool QQmlNotifierEndpoint::isConnected(QObject *source, int sourceSignal)
+{
+ return this->sourceSignal != -1 && this->source == source && this->sourceSignal == sourceSignal;
+}
+
+bool QQmlNotifierEndpoint::isConnected(QQmlNotifier *notifier)
+{
+ return sourceSignal == -1 && this->notifier == notifier;
+}
+
+void QQmlNotifierEndpoint::connect(QQmlNotifier *notifier)
+{
+ disconnect();
+
+ next = notifier->endpoints;
+ if (next) { next->prev = &next; }
+ notifier->endpoints = this;
+ prev = &notifier->endpoints;
+ this->notifier = notifier;
+}
+
+void QQmlNotifierEndpoint::disconnect()
+{
+ if (next) next->prev = prev;
+ if (prev) *prev = next;
+ if (disconnected) *disconnected = 0;
+ next = 0;
+ prev = 0;
+ disconnected = 0;
+ notifier = 0;
+ notifying = 0;
+ sourceSignal = -1;
+}
+
+/*!
+Returns true if a notify is in progress. This means that the signal or QQmlNotifier
+that this endpoing is connected to has been triggered, but this endpoint's callback has not
+yet been called.
+
+An in progress notify can be cancelled by calling cancelNotify.
+*/
+bool QQmlNotifierEndpoint::isNotifying() const
+{
+ return notifying == 1;
+}
+
+/*!
+Cancel any notifies that are in progress.
+*/
+void QQmlNotifierEndpoint::cancelNotify()
+{
+ notifying = 0;
+ if (disconnected) {
+ *disconnected = 0;
+ disconnected = 0;
+ }
+}
+
+QT_END_NAMESPACE
+
+#endif // QQMLNOTIFIER_P_H
+
diff --git a/src/qml/qml/qqmlnullablevalue_p_p.h b/src/qml/qml/qqmlnullablevalue_p_p.h
new file mode 100644
index 0000000000..b19e2722cf
--- /dev/null
+++ b/src/qml/qml/qqmlnullablevalue_p_p.h
@@ -0,0 +1,81 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLNULLABLEVALUE_P_H
+#define QQMLNULLABLEVALUE_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.
+//
+
+QT_BEGIN_NAMESPACE
+
+template<typename T>
+struct QQmlNullableValue
+{
+ QQmlNullableValue()
+ : isNull(true), value(T()) {}
+ QQmlNullableValue(const QQmlNullableValue<T> &o)
+ : isNull(o.isNull), value(o.value) {}
+ QQmlNullableValue(const T &t)
+ : isNull(false), value(t) {}
+ QQmlNullableValue<T> &operator=(const T &t)
+ { isNull = false; value = t; return *this; }
+ QQmlNullableValue<T> &operator=(const QQmlNullableValue<T> &o)
+ { isNull = o.isNull; value = o.value; return *this; }
+ operator T() const { return value; }
+
+ void invalidate() { isNull = true; }
+ bool isValid() const { return !isNull; }
+ bool isNull;
+ T value;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQMLNULLABLEVALUE_P_H
diff --git a/src/qml/qml/qqmlopenmetaobject.cpp b/src/qml/qml/qqmlopenmetaobject.cpp
new file mode 100644
index 0000000000..221cb3a314
--- /dev/null
+++ b/src/qml/qml/qqmlopenmetaobject.cpp
@@ -0,0 +1,387 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qqmlopenmetaobject_p.h"
+#include <private/qqmlpropertycache_p.h>
+#include <private/qqmldata_p.h>
+#include <private/qmetaobjectbuilder_p.h>
+#include <qdebug.h>
+
+QT_BEGIN_NAMESPACE
+
+
+class QQmlOpenMetaObjectTypePrivate
+{
+public:
+ QQmlOpenMetaObjectTypePrivate() : mem(0), cache(0), engine(0) {}
+
+ void init(const QMetaObject *metaObj);
+
+ int propertyOffset;
+ int signalOffset;
+ QHash<QByteArray, int> names;
+ QMetaObjectBuilder mob;
+ QMetaObject *mem;
+ QQmlPropertyCache *cache;
+ QQmlEngine *engine;
+ QSet<QQmlOpenMetaObject*> referers;
+};
+
+QQmlOpenMetaObjectType::QQmlOpenMetaObjectType(const QMetaObject *base, QQmlEngine *engine)
+ : QQmlCleanup(engine), d(new QQmlOpenMetaObjectTypePrivate)
+{
+ d->engine = engine;
+ d->init(base);
+}
+
+QQmlOpenMetaObjectType::~QQmlOpenMetaObjectType()
+{
+ if (d->mem)
+ free(d->mem);
+ if (d->cache)
+ d->cache->release();
+ delete d;
+}
+
+void QQmlOpenMetaObjectType::clear()
+{
+ d->engine = 0;
+}
+
+int QQmlOpenMetaObjectType::propertyOffset() const
+{
+ return d->propertyOffset;
+}
+
+int QQmlOpenMetaObjectType::signalOffset() const
+{
+ return d->signalOffset;
+}
+
+int QQmlOpenMetaObjectType::createProperty(const QByteArray &name)
+{
+ int id = d->mob.propertyCount();
+ d->mob.addSignal("__" + QByteArray::number(id) + "()");
+ QMetaPropertyBuilder build = d->mob.addProperty(name, "QVariant", id);
+ propertyCreated(id, build);
+ free(d->mem);
+ d->mem = d->mob.toMetaObject();
+ d->names.insert(name, id);
+ QSet<QQmlOpenMetaObject*>::iterator it = d->referers.begin();
+ while (it != d->referers.end()) {
+ QQmlOpenMetaObject *omo = *it;
+ *static_cast<QMetaObject *>(omo) = *d->mem;
+ if (d->cache)
+ d->cache->update(d->engine, omo);
+ ++it;
+ }
+
+ return d->propertyOffset + id;
+}
+
+void QQmlOpenMetaObjectType::propertyCreated(int id, QMetaPropertyBuilder &builder)
+{
+ if (d->referers.count())
+ (*d->referers.begin())->propertyCreated(id, builder);
+}
+
+void QQmlOpenMetaObjectTypePrivate::init(const QMetaObject *metaObj)
+{
+ if (!mem) {
+ mob.setSuperClass(metaObj);
+ mob.setClassName(metaObj->className());
+ mob.setFlags(QMetaObjectBuilder::DynamicMetaObject);
+
+ mem = mob.toMetaObject();
+
+ propertyOffset = mem->propertyOffset();
+ signalOffset = mem->methodOffset();
+ }
+}
+
+//----------------------------------------------------------------------------
+
+class QQmlOpenMetaObjectPrivate
+{
+public:
+ QQmlOpenMetaObjectPrivate(QQmlOpenMetaObject *_q)
+ : q(_q), parent(0), type(0), cacheProperties(false) {}
+
+ inline QVariant &getData(int idx) {
+ while (data.count() <= idx)
+ data << QPair<QVariant, bool>(QVariant(), false);
+ QPair<QVariant, bool> &prop = data[idx];
+ if (!prop.second) {
+ prop.first = q->initialValue(idx);
+ prop.second = true;
+ }
+ return prop.first;
+ }
+
+ inline void writeData(int idx, const QVariant &value) {
+ while (data.count() <= idx)
+ data << QPair<QVariant, bool>(QVariant(), false);
+ QPair<QVariant, bool> &prop = data[idx];
+ prop.first = value;
+ prop.second = true;
+ }
+
+ inline bool hasData(int idx) const {
+ if (idx >= data.count())
+ return false;
+ return data[idx].second;
+ }
+
+ bool autoCreate;
+ QQmlOpenMetaObject *q;
+ QAbstractDynamicMetaObject *parent;
+ QList<QPair<QVariant, bool> > data;
+ QObject *object;
+ QQmlOpenMetaObjectType *type;
+ bool cacheProperties;
+};
+
+QQmlOpenMetaObject::QQmlOpenMetaObject(QObject *obj, bool automatic)
+: d(new QQmlOpenMetaObjectPrivate(this))
+{
+ d->autoCreate = automatic;
+ d->object = obj;
+
+ d->type = new QQmlOpenMetaObjectType(obj->metaObject(), 0);
+ d->type->d->referers.insert(this);
+
+ QObjectPrivate *op = QObjectPrivate::get(obj);
+ d->parent = static_cast<QAbstractDynamicMetaObject *>(op->metaObject);
+ *static_cast<QMetaObject *>(this) = *d->type->d->mem;
+ op->metaObject = this;
+}
+
+QQmlOpenMetaObject::QQmlOpenMetaObject(QObject *obj, QQmlOpenMetaObjectType *type, bool automatic)
+: d(new QQmlOpenMetaObjectPrivate(this))
+{
+ d->autoCreate = automatic;
+ d->object = obj;
+
+ d->type = type;
+ d->type->addref();
+ d->type->d->referers.insert(this);
+
+ QObjectPrivate *op = QObjectPrivate::get(obj);
+ d->parent = static_cast<QAbstractDynamicMetaObject *>(op->metaObject);
+ *static_cast<QMetaObject *>(this) = *d->type->d->mem;
+ op->metaObject = this;
+}
+
+QQmlOpenMetaObject::~QQmlOpenMetaObject()
+{
+ if (d->parent)
+ delete d->parent;
+ d->type->d->referers.remove(this);
+ d->type->release();
+ delete d;
+}
+
+QQmlOpenMetaObjectType *QQmlOpenMetaObject::type() const
+{
+ return d->type;
+}
+
+int QQmlOpenMetaObject::metaCall(QMetaObject::Call c, int id, void **a)
+{
+ if (( c == QMetaObject::ReadProperty || c == QMetaObject::WriteProperty)
+ && id >= d->type->d->propertyOffset) {
+ int propId = id - d->type->d->propertyOffset;
+ if (c == QMetaObject::ReadProperty) {
+ propertyRead(propId);
+ *reinterpret_cast<QVariant *>(a[0]) = d->getData(propId);
+ } else if (c == QMetaObject::WriteProperty) {
+ if (propId <= d->data.count() || d->data[propId].first != *reinterpret_cast<QVariant *>(a[0])) {
+ propertyWrite(propId);
+ d->writeData(propId, *reinterpret_cast<QVariant *>(a[0]));
+ propertyWritten(propId);
+ activate(d->object, d->type->d->signalOffset + propId, 0);
+ }
+ }
+ return -1;
+ } else {
+ if (d->parent)
+ return d->parent->metaCall(c, id, a);
+ else
+ return d->object->qt_metacall(c, id, a);
+ }
+}
+
+QAbstractDynamicMetaObject *QQmlOpenMetaObject::parent() const
+{
+ return d->parent;
+}
+
+QVariant QQmlOpenMetaObject::value(int id) const
+{
+ return d->getData(id);
+}
+
+void QQmlOpenMetaObject::setValue(int id, const QVariant &value)
+{
+ d->writeData(id, value);
+ activate(d->object, id + d->type->d->signalOffset, 0);
+}
+
+QVariant QQmlOpenMetaObject::value(const QByteArray &name) const
+{
+ QHash<QByteArray, int>::ConstIterator iter = d->type->d->names.find(name);
+ if (iter == d->type->d->names.end())
+ return QVariant();
+
+ return d->getData(*iter);
+}
+
+QVariant &QQmlOpenMetaObject::operator[](const QByteArray &name)
+{
+ QHash<QByteArray, int>::ConstIterator iter = d->type->d->names.find(name);
+ Q_ASSERT(iter != d->type->d->names.end());
+
+ return d->getData(*iter);
+}
+
+QVariant &QQmlOpenMetaObject::operator[](int id)
+{
+ return d->getData(id);
+}
+
+bool QQmlOpenMetaObject::setValue(const QByteArray &name, const QVariant &val)
+{
+ QHash<QByteArray, int>::ConstIterator iter = d->type->d->names.find(name);
+
+ int id = -1;
+ if (iter == d->type->d->names.end()) {
+ id = createProperty(name.constData(), "") - d->type->d->propertyOffset;
+ } else {
+ id = *iter;
+ }
+
+ if (id >= 0) {
+ QVariant &dataVal = d->getData(id);
+ if (dataVal == val)
+ return false;
+
+ dataVal = val;
+ activate(d->object, id + d->type->d->signalOffset, 0);
+ return true;
+ }
+
+ return false;
+}
+
+// returns true if this value has been initialized by a call to either value() or setValue()
+bool QQmlOpenMetaObject::hasValue(int id) const
+{
+ return d->hasData(id);
+}
+
+void QQmlOpenMetaObject::setCached(bool c)
+{
+ if (c == d->cacheProperties || !d->type->d->engine)
+ return;
+
+ d->cacheProperties = c;
+
+ QQmlData *qmldata = QQmlData::get(d->object, true);
+ if (d->cacheProperties) {
+ if (!d->type->d->cache)
+ d->type->d->cache = new QQmlPropertyCache(d->type->d->engine, this);
+ qmldata->propertyCache = d->type->d->cache;
+ d->type->d->cache->addref();
+ } else {
+ if (d->type->d->cache)
+ d->type->d->cache->release();
+ qmldata->propertyCache = 0;
+ }
+}
+
+
+int QQmlOpenMetaObject::createProperty(const char *name, const char *)
+{
+ if (d->autoCreate)
+ return d->type->createProperty(name);
+ else
+ return -1;
+}
+
+void QQmlOpenMetaObject::propertyRead(int)
+{
+}
+
+void QQmlOpenMetaObject::propertyWrite(int)
+{
+}
+
+void QQmlOpenMetaObject::propertyWritten(int)
+{
+}
+
+void QQmlOpenMetaObject::propertyCreated(int, QMetaPropertyBuilder &)
+{
+}
+
+QVariant QQmlOpenMetaObject::initialValue(int)
+{
+ return QVariant();
+}
+
+int QQmlOpenMetaObject::count() const
+{
+ return d->type->d->names.count();
+}
+
+QByteArray QQmlOpenMetaObject::name(int idx) const
+{
+ Q_ASSERT(idx >= 0 && idx < d->type->d->names.count());
+
+ return d->type->d->mob.property(idx).name();
+}
+
+QObject *QQmlOpenMetaObject::object() const
+{
+ return d->object;
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlopenmetaobject_p.h b/src/qml/qml/qqmlopenmetaobject_p.h
new file mode 100644
index 0000000000..188192edc1
--- /dev/null
+++ b/src/qml/qml/qqmlopenmetaobject_p.h
@@ -0,0 +1,130 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLOPENMETAOBJECT_H
+#define QQMLOPENMETAOBJECT_H
+
+#include <QtCore/QMetaObject>
+#include <QtCore/QObject>
+
+#include <private/qqmlrefcount_p.h>
+#include <private/qqmlcleanup_p.h>
+#include <private/qtqmlglobal_p.h>
+#include <private/qobject_p.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+
+class QQmlEngine;
+class QMetaPropertyBuilder;
+class QQmlOpenMetaObjectTypePrivate;
+class Q_QML_PRIVATE_EXPORT QQmlOpenMetaObjectType : public QQmlRefCount, public QQmlCleanup
+{
+public:
+ QQmlOpenMetaObjectType(const QMetaObject *base, QQmlEngine *engine);
+ ~QQmlOpenMetaObjectType();
+
+ int createProperty(const QByteArray &name);
+
+ int propertyOffset() const;
+ int signalOffset() const;
+
+protected:
+ virtual void propertyCreated(int, QMetaPropertyBuilder &);
+ virtual void clear();
+
+private:
+ QQmlOpenMetaObjectTypePrivate *d;
+ friend class QQmlOpenMetaObject;
+ friend class QQmlOpenMetaObjectPrivate;
+};
+
+class QQmlOpenMetaObjectPrivate;
+class Q_QML_PRIVATE_EXPORT QQmlOpenMetaObject : public QAbstractDynamicMetaObject
+{
+public:
+ QQmlOpenMetaObject(QObject *, bool = true);
+ QQmlOpenMetaObject(QObject *, QQmlOpenMetaObjectType *, bool = true);
+ ~QQmlOpenMetaObject();
+
+ QVariant value(const QByteArray &) const;
+ bool setValue(const QByteArray &, const QVariant &);
+ QVariant value(int) const;
+ void setValue(int, const QVariant &);
+ QVariant &operator[](const QByteArray &);
+ QVariant &operator[](int);
+ bool hasValue(int) const;
+
+ int count() const;
+ QByteArray name(int) const;
+
+ QObject *object() const;
+ virtual QVariant initialValue(int);
+
+ // Be careful - once setCached(true) is called createProperty() is no
+ // longer automatically called for new properties.
+ void setCached(bool);
+
+ QQmlOpenMetaObjectType *type() const;
+
+protected:
+ virtual int metaCall(QMetaObject::Call _c, int _id, void **_a);
+ virtual int createProperty(const char *, const char *);
+
+ virtual void propertyRead(int);
+ virtual void propertyWrite(int);
+ virtual void propertyWritten(int);
+ virtual void propertyCreated(int, QMetaPropertyBuilder &);
+
+ QAbstractDynamicMetaObject *parent() const;
+
+private:
+ QQmlOpenMetaObjectPrivate *d;
+ friend class QQmlOpenMetaObjectType;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QQMLOPENMETAOBJECT_H
diff --git a/src/qml/qml/qqmlparserstatus.cpp b/src/qml/qml/qqmlparserstatus.cpp
new file mode 100644
index 0000000000..d4e415a069
--- /dev/null
+++ b/src/qml/qml/qqmlparserstatus.cpp
@@ -0,0 +1,107 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qqmlparserstatus.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QQmlParserStatus
+ \since 4.7
+ \brief The QQmlParserStatus class provides updates on the QML parser state.
+
+ QQmlParserStatus provides a mechanism for classes instantiated by
+ a QQmlEngine to receive notification at key points in their creation.
+
+ This class is often used for optimization purposes, as it allows you to defer an
+ expensive operation until after all the properties have been set on an
+ object. For example, QML's \l {Text} element uses the parser status
+ to defer text layout until all of its properties have been set (we
+ don't want to layout when the \c text is assigned, and then relayout
+ when the \c font is assigned, and relayout again when the \c width is assigned,
+ and so on).
+
+ To use QQmlParserStatus, you must inherit both a QObject-derived class
+ and QQmlParserStatus, and use the Q_INTERFACES() macro.
+
+ \code
+ class MyObject : public QObject, public QQmlParserStatus
+ {
+ Q_OBJECT
+ Q_INTERFACES(QQmlParserStatus)
+
+ public:
+ MyObject(QObject *parent = 0);
+ ...
+ void classBegin();
+ void componentComplete();
+ }
+ \endcode
+*/
+
+/*! \internal */
+QQmlParserStatus::QQmlParserStatus()
+: d(0)
+{
+}
+
+/*! \internal */
+QQmlParserStatus::~QQmlParserStatus()
+{
+ if(d)
+ (*d) = 0;
+}
+
+/*!
+ \fn void QQmlParserStatus::classBegin()
+
+ Invoked after class creation, but before any properties have been set.
+*/
+
+/*!
+ \fn void QQmlParserStatus::componentComplete()
+
+ Invoked after the root component that caused this instantiation has
+ completed construction. At this point all static values and binding values
+ have been assigned to the class.
+*/
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlparserstatus.h b/src/qml/qml/qqmlparserstatus.h
new file mode 100644
index 0000000000..9f06f45b06
--- /dev/null
+++ b/src/qml/qml/qqmlparserstatus.h
@@ -0,0 +1,75 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLPARSERSTATUS_H
+#define QQMLPARSERSTATUS_H
+
+#include <QtQml/qtqmlglobal.h>
+#include <QtCore/qobject.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+
+class Q_QML_EXPORT QQmlParserStatus
+{
+public:
+ QQmlParserStatus();
+ virtual ~QQmlParserStatus();
+
+ virtual void classBegin()=0;
+ virtual void componentComplete()=0;
+
+private:
+ friend class QQmlVME;
+ friend class QQmlComponent;
+ friend class QQmlComponentPrivate;
+ friend class QQmlEnginePrivate;
+ QQmlParserStatus **d;
+};
+Q_DECLARE_INTERFACE(QQmlParserStatus, "com.trolltech.qml.QQmlParserStatus")
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QQMLPARSERSTATUS_H
diff --git a/src/qml/qml/qqmlprivate.h b/src/qml/qml/qqmlprivate.h
new file mode 100644
index 0000000000..b4c6fc3a12
--- /dev/null
+++ b/src/qml/qml/qqmlprivate.h
@@ -0,0 +1,265 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLPRIVATE_H
+#define QQMLPRIVATE_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtQml/qtqmlglobal.h>
+
+#include <QtCore/qglobal.h>
+#include <QtCore/qvariant.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+
+typedef QObject *(*QQmlAttachedPropertiesFunc)(QObject *);
+
+template <typename TYPE>
+class QQmlTypeInfo
+{
+public:
+ enum {
+ hasAttachedProperties = 0
+ };
+};
+
+
+class QJSValue;
+class QJSEngine;
+class QQmlEngine;
+class QQmlCustomParser;
+namespace QQmlPrivate
+{
+ void Q_QML_EXPORT qdeclarativeelement_destructor(QObject *);
+ template<typename T>
+ class QQmlElement : public T
+ {
+ public:
+ virtual ~QQmlElement() {
+ QQmlPrivate::qdeclarativeelement_destructor(this);
+ }
+ };
+
+ template<typename T>
+ void createInto(void *memory) { new (memory) QQmlElement<T>; }
+
+ template<typename T>
+ QObject *createParent(QObject *p) { return new T(p); }
+
+ template<class From, class To, int N>
+ struct StaticCastSelectorClass
+ {
+ static inline int cast() { return -1; }
+ };
+
+ template<class From, class To>
+ struct StaticCastSelectorClass<From, To, sizeof(int)>
+ {
+ static inline int cast() { return int(reinterpret_cast<quintptr>(static_cast<To *>(reinterpret_cast<From *>(0x10000000)))) - 0x10000000; }
+ };
+
+ template<class From, class To>
+ struct StaticCastSelector
+ {
+ typedef int yes_type;
+ typedef char no_type;
+
+ static yes_type check(To *);
+ static no_type check(...);
+
+ static inline int cast()
+ {
+ return StaticCastSelectorClass<From, To, sizeof(check(reinterpret_cast<From *>(0)))>::cast();
+ }
+ };
+
+ template <typename T>
+ struct has_attachedPropertiesMember
+ {
+ static bool const value = QQmlTypeInfo<T>::hasAttachedProperties;
+ };
+
+ template <typename T, bool hasMember>
+ class has_attachedPropertiesMethod
+ {
+ public:
+ typedef int yes_type;
+ typedef char no_type;
+
+ template<typename ReturnType>
+ static yes_type check(ReturnType *(*)(QObject *));
+ static no_type check(...);
+
+ static bool const value = sizeof(check(&T::qmlAttachedProperties)) == sizeof(yes_type);
+ };
+
+ template <typename T>
+ class has_attachedPropertiesMethod<T, false>
+ {
+ public:
+ static bool const value = false;
+ };
+
+ template<typename T, int N>
+ class AttachedPropertySelector
+ {
+ public:
+ static inline QQmlAttachedPropertiesFunc func() { return 0; }
+ static inline const QMetaObject *metaObject() { return 0; }
+ };
+ template<typename T>
+ class AttachedPropertySelector<T, 1>
+ {
+ static inline QObject *attachedProperties(QObject *obj) {
+ return T::qmlAttachedProperties(obj);
+ }
+ template<typename ReturnType>
+ static inline const QMetaObject *attachedPropertiesMetaObject(ReturnType *(*)(QObject *)) {
+ return &ReturnType::staticMetaObject;
+ }
+ public:
+ static inline QQmlAttachedPropertiesFunc func() {
+ return &attachedProperties;
+ }
+ static inline const QMetaObject *metaObject() {
+ return attachedPropertiesMetaObject(&T::qmlAttachedProperties);
+ }
+ };
+
+ template<typename T>
+ inline QQmlAttachedPropertiesFunc attachedPropertiesFunc()
+ {
+ return AttachedPropertySelector<T, has_attachedPropertiesMethod<T, has_attachedPropertiesMember<T>::value>::value>::func();
+ }
+
+ template<typename T>
+ inline const QMetaObject *attachedPropertiesMetaObject()
+ {
+ return AttachedPropertySelector<T, has_attachedPropertiesMethod<T, has_attachedPropertiesMember<T>::value>::value>::metaObject();
+ }
+
+ enum AutoParentResult { Parented, IncompatibleObject, IncompatibleParent };
+ typedef AutoParentResult (*AutoParentFunction)(QObject *object, QObject *parent);
+
+ struct RegisterType {
+ int version;
+
+ int typeId;
+ int listId;
+ int objectSize;
+ void (*create)(void *);
+ QString noCreationReason;
+
+ const char *uri;
+ int versionMajor;
+ int versionMinor;
+ const char *elementName;
+ const QMetaObject *metaObject;
+
+ QQmlAttachedPropertiesFunc attachedPropertiesFunction;
+ const QMetaObject *attachedPropertiesMetaObject;
+
+ int parserStatusCast;
+ int valueSourceCast;
+ int valueInterceptorCast;
+
+ QObject *(*extensionObjectCreate)(QObject *);
+ const QMetaObject *extensionMetaObject;
+
+ QQmlCustomParser *customParser;
+ int revision;
+ // If this is extended ensure "version" is bumped!!!
+ };
+
+ struct RegisterInterface {
+ int version;
+
+ int typeId;
+ int listId;
+
+ const char *iid;
+ };
+
+ struct RegisterAutoParent {
+ int version;
+
+ AutoParentFunction function;
+ };
+
+ struct RegisterModuleApi {
+ int version;
+
+ const char *uri;
+ int versionMajor;
+ int versionMinor;
+
+ QJSValue (*scriptApi)(QQmlEngine *, QJSEngine *);
+ QObject *(*qobjectApi)(QQmlEngine *, QJSEngine *);
+ };
+
+ enum RegistrationType {
+ TypeRegistration = 0,
+ InterfaceRegistration = 1,
+ AutoParentRegistration = 2,
+ ModuleApiRegistration = 3
+ };
+
+ int Q_QML_EXPORT qmlregister(RegistrationType, void *);
+}
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QQMLPRIVATE_H
diff --git a/src/qml/qml/qqmlproperty.cpp b/src/qml/qml/qqmlproperty.cpp
new file mode 100644
index 0000000000..6321592e9a
--- /dev/null
+++ b/src/qml/qml/qqmlproperty.cpp
@@ -0,0 +1,1917 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qqmlproperty.h"
+#include "qqmlproperty_p.h"
+
+#include "qqml.h"
+#include "qqmlbinding_p.h"
+#include "qqmlcontext.h"
+#include "qqmlcontext_p.h"
+#include "qqmlboundsignal_p.h"
+#include "qqmlengine.h"
+#include "qqmlengine_p.h"
+#include "qqmldata_p.h"
+#include "qqmlstringconverters_p.h"
+#include "qqmllist_p.h"
+#include "qqmlcompiler_p.h"
+#include "qqmlvmemetaobject_p.h"
+#include "qqmlexpression_p.h"
+
+#include <QStringList>
+#include <QtCore/qdebug.h>
+
+#include <math.h>
+
+Q_DECLARE_METATYPE(QList<int>)
+Q_DECLARE_METATYPE(QList<qreal>)
+Q_DECLARE_METATYPE(QList<bool>)
+Q_DECLARE_METATYPE(QList<QString>)
+Q_DECLARE_METATYPE(QList<QUrl>)
+
+QT_BEGIN_NAMESPACE
+
+/*!
+\class QQmlProperty
+\since 4.7
+\brief The QQmlProperty class abstracts accessing properties on objects created from QML.
+
+As QML uses Qt's meta-type system all of the existing QMetaObject classes can be used to introspect
+and interact with objects created by QML. However, some of the new features provided by QML - such
+as type safety and attached properties - are most easily used through the QQmlProperty class
+that simplifies some of their natural complexity.
+
+Unlike QMetaProperty which represents a property on a class type, QQmlProperty encapsulates
+a property on a specific object instance. To read a property's value, programmers create a
+QQmlProperty instance and call the read() method. Likewise to write a property value the
+write() method is used.
+
+For example, for the following QML code:
+
+\qml
+// MyItem.qml
+import QtQuick 2.0
+
+Text { text: "A bit of text" }
+\endqml
+
+The \l Text object's properties could be accessed using QQmlProperty, like this:
+
+\code
+#include <QQmlProperty>
+#include <QGraphicsObject>
+
+...
+
+QQuickView view(QUrl::fromLocalFile("MyItem.qml"));
+QQmlProperty property(view.rootObject(), "font.pixelSize");
+qWarning() << "Current pixel size:" << property.read().toInt();
+property.write(24);
+qWarning() << "Pixel size should now be 24:" << property.read().toInt();
+\endcode
+*/
+
+/*!
+ Create an invalid QQmlProperty.
+*/
+QQmlProperty::QQmlProperty()
+: d(0)
+{
+}
+
+/*! \internal */
+QQmlProperty::~QQmlProperty()
+{
+ if (d)
+ d->release();
+ d = 0;
+}
+
+/*!
+ Creates a QQmlProperty for the default property of \a obj. If there is no
+ default property, an invalid QQmlProperty will be created.
+ */
+QQmlProperty::QQmlProperty(QObject *obj)
+: d(new QQmlPropertyPrivate)
+{
+ d->initDefault(obj);
+}
+
+/*!
+ Creates a QQmlProperty for the default property of \a obj
+ using the \l{QQmlContext} {context} \a ctxt. If there is
+ no default property, an invalid QQmlProperty will be
+ created.
+ */
+QQmlProperty::QQmlProperty(QObject *obj, QQmlContext *ctxt)
+: d(new QQmlPropertyPrivate)
+{
+ d->context = ctxt?QQmlContextData::get(ctxt):0;
+ d->engine = ctxt?ctxt->engine():0;
+ d->initDefault(obj);
+}
+
+/*!
+ Creates a QQmlProperty for the default property of \a obj
+ using the environment for instantiating QML components that is
+ provided by \a engine. If there is no default property, an
+ invalid QQmlProperty will be created.
+ */
+QQmlProperty::QQmlProperty(QObject *obj, QQmlEngine *engine)
+ : d(new QQmlPropertyPrivate)
+{
+ d->context = 0;
+ d->engine = engine;
+ d->initDefault(obj);
+}
+
+/*!
+ Initialize from the default property of \a obj
+*/
+void QQmlPropertyPrivate::initDefault(QObject *obj)
+{
+ if (!obj)
+ return;
+
+ QMetaProperty p = QQmlMetaType::defaultProperty(obj);
+ core.load(p);
+ if (core.isValid())
+ object = obj;
+}
+
+/*!
+ Creates a QQmlProperty for the property \a name of \a obj.
+ */
+QQmlProperty::QQmlProperty(QObject *obj, const QString &name)
+: d(new QQmlPropertyPrivate)
+{
+ d->initProperty(obj, name);
+ if (!isValid()) d->object = 0;
+}
+
+/*!
+ Creates a QQmlProperty for the property \a name of \a obj
+ using the \l{QQmlContext} {context} \a ctxt.
+
+ Creating a QQmlProperty without a context will render some
+ properties - like attached properties - inaccessible.
+*/
+QQmlProperty::QQmlProperty(QObject *obj, const QString &name, QQmlContext *ctxt)
+: d(new QQmlPropertyPrivate)
+{
+ d->context = ctxt?QQmlContextData::get(ctxt):0;
+ d->engine = ctxt?ctxt->engine():0;
+ d->initProperty(obj, name);
+ if (!isValid()) { d->object = 0; d->context = 0; d->engine = 0; }
+}
+
+/*!
+ Creates a QQmlProperty for the property \a name of \a obj
+ using the environment for instantiating QML components that is
+ provided by \a engine.
+ */
+QQmlProperty::QQmlProperty(QObject *obj, const QString &name, QQmlEngine *engine)
+: d(new QQmlPropertyPrivate)
+{
+ d->context = 0;
+ d->engine = engine;
+ d->initProperty(obj, name);
+ if (!isValid()) { d->object = 0; d->context = 0; d->engine = 0; }
+}
+
+Q_GLOBAL_STATIC(QQmlValueTypeFactory, qmlValueTypes);
+
+QQmlPropertyPrivate::QQmlPropertyPrivate()
+: context(0), engine(0), object(0), isNameCached(false)
+{
+}
+
+QQmlContextData *QQmlPropertyPrivate::effectiveContext() const
+{
+ if (context) return context;
+ else if (engine) return QQmlContextData::get(engine->rootContext());
+ else return 0;
+}
+
+void QQmlPropertyPrivate::initProperty(QObject *obj, const QString &name)
+{
+ if (!obj) return;
+
+ QQmlTypeNameCache *typeNameCache = context?context->imports:0;
+
+ QStringList path = name.split(QLatin1Char('.'));
+ if (path.isEmpty()) return;
+
+ QObject *currentObject = obj;
+
+ // Everything up to the last property must be an "object type" property
+ for (int ii = 0; ii < path.count() - 1; ++ii) {
+ const QString &pathName = path.at(ii);
+
+ if (typeNameCache) {
+ QQmlTypeNameCache::Result r = typeNameCache->query(pathName);
+ if (r.isValid()) {
+ if (r.type) {
+ QQmlAttachedPropertiesFunc func = r.type->attachedPropertiesFunction();
+ if (!func) return; // Not an attachable type
+
+ currentObject = qmlAttachedPropertiesObjectById(r.type->attachedPropertiesId(), currentObject);
+ if (!currentObject) return; // Something is broken with the attachable type
+ } else if (r.importNamespace) {
+ if ((ii + 1) == path.count()) return; // No type following the namespace
+
+ ++ii; r = typeNameCache->query(path.at(ii), r.importNamespace);
+ if (!r.type) return; // Invalid type in namespace
+
+ QQmlAttachedPropertiesFunc func = r.type->attachedPropertiesFunction();
+ if (!func) return; // Not an attachable type
+
+ currentObject = qmlAttachedPropertiesObjectById(r.type->attachedPropertiesId(), currentObject);
+ if (!currentObject) return; // Something is broken with the attachable type
+
+ } else if (r.scriptIndex != -1) {
+ return; // Not a type
+ } else {
+ Q_ASSERT(!"Unreachable");
+ }
+ continue;
+ }
+
+ }
+
+ QQmlPropertyData local;
+ QQmlPropertyData *property =
+ QQmlPropertyCache::property(engine, obj, pathName, local);
+
+ if (!property) return; // Not a property
+ if (property->isFunction())
+ return; // Not an object property
+
+ if (ii == (path.count() - 2) && QQmlValueTypeFactory::isValueType(property->propType)) {
+ // We're now at a value type property. We can use a global valuetypes array as we
+ // never actually use the objects, just look up their properties.
+ QObject *typeObject = (*qmlValueTypes())[property->propType];
+ if (!typeObject) return; // Not a value type
+
+ int idx = typeObject->metaObject()->indexOfProperty(path.last().toUtf8().constData());
+ if (idx == -1) return; // Value type property does not exist
+
+ QMetaProperty vtProp = typeObject->metaObject()->property(idx);
+
+ typedef QQmlPropertyData PCD;
+
+ Q_ASSERT(PCD::flagsForProperty(vtProp) <= PCD::ValueTypeFlagMask);
+ Q_ASSERT(vtProp.userType() <= 0xFF);
+ Q_ASSERT(idx <= 0xFF);
+
+ object = currentObject;
+ core = *property;
+ core.setFlags(core.getFlags() | PCD::IsValueTypeVirtual);
+ core.valueTypeFlags = PCD::flagsForProperty(vtProp);
+ core.valueTypePropType = vtProp.userType();
+ core.valueTypeCoreIndex = idx;
+
+ return;
+ } else {
+ if (!property->isQObject())
+ return; // Not an object property
+
+ void *args[] = { &currentObject, 0 };
+ QMetaObject::metacall(currentObject, QMetaObject::ReadProperty, property->coreIndex, args);
+ if (!currentObject) return; // No value
+
+ }
+
+ }
+
+ const QString &terminal = path.last();
+
+ if (terminal.count() >= 3 &&
+ terminal.at(0) == QLatin1Char('o') &&
+ terminal.at(1) == QLatin1Char('n') &&
+ terminal.at(2).isUpper()) {
+
+ QString signalName = terminal.mid(2);
+ signalName[0] = signalName.at(0).toLower();
+
+ QMetaMethod method = findSignalByName(currentObject->metaObject(), signalName.toLatin1().constData());
+ if (method.signature()) {
+ object = currentObject;
+ core.load(method);
+ return;
+ }
+ }
+
+ // Property
+ QQmlPropertyData local;
+ QQmlPropertyData *property =
+ QQmlPropertyCache::property(engine, currentObject, terminal, local);
+ if (property && !property->isFunction()) {
+ object = currentObject;
+ core = *property;
+ nameCache = terminal;
+ isNameCached = true;
+ }
+}
+
+/*!
+ Create a copy of \a other.
+*/
+QQmlProperty::QQmlProperty(const QQmlProperty &other)
+{
+ d = other.d;
+ if (d)
+ d->addref();
+}
+
+/*!
+ \enum QQmlProperty::PropertyTypeCategory
+
+ This enum specifies a category of QML property.
+
+ \value InvalidCategory The property is invalid, or is a signal property.
+ \value List The property is a QQmlListProperty list property
+ \value Object The property is a QObject derived type pointer
+ \value Normal The property is a normal value property.
+ */
+
+/*!
+ \enum QQmlProperty::Type
+
+ This enum specifies a type of QML property.
+
+ \value Invalid The property is invalid.
+ \value Property The property is a regular Qt property.
+ \value SignalProperty The property is a signal property.
+*/
+
+/*!
+ Returns the property category.
+*/
+QQmlProperty::PropertyTypeCategory QQmlProperty::propertyTypeCategory() const
+{
+ return d ? d->propertyTypeCategory() : InvalidCategory;
+}
+
+QQmlProperty::PropertyTypeCategory
+QQmlPropertyPrivate::propertyTypeCategory() const
+{
+ uint type = this->type();
+
+ if (isValueType()) {
+ return QQmlProperty::Normal;
+ } else if (type & QQmlProperty::Property) {
+ int type = propertyType();
+ if (type == QVariant::Invalid)
+ return QQmlProperty::InvalidCategory;
+ else if (QQmlValueTypeFactory::isValueType((uint)type))
+ return QQmlProperty::Normal;
+ else if (core.isQObject())
+ return QQmlProperty::Object;
+ else if (core.isQList())
+ return QQmlProperty::List;
+ else
+ return QQmlProperty::Normal;
+ } else {
+ return QQmlProperty::InvalidCategory;
+ }
+}
+
+/*!
+ Returns the type name of the property, or 0 if the property has no type
+ name.
+*/
+const char *QQmlProperty::propertyTypeName() const
+{
+ if (!d)
+ return 0;
+ if (d->isValueType()) {
+
+ QQmlEnginePrivate *ep = d->engine?QQmlEnginePrivate::get(d->engine):0;
+ QQmlValueType *valueType = 0;
+ if (ep) valueType = ep->valueTypes[d->core.propType];
+ else valueType = QQmlValueTypeFactory::valueType(d->core.propType);
+ Q_ASSERT(valueType);
+
+ const char *rv = valueType->metaObject()->property(d->core.valueTypeCoreIndex).typeName();
+
+ if (!ep) delete valueType;
+
+ return rv;
+ } else if (d->object && type() & Property && d->core.isValid()) {
+ return d->object->metaObject()->property(d->core.coreIndex).typeName();
+ } else {
+ return 0;
+ }
+}
+
+/*!
+ Returns true if \a other and this QQmlProperty represent the same
+ property.
+*/
+bool QQmlProperty::operator==(const QQmlProperty &other) const
+{
+ if (!d || !other.d)
+ return false;
+ // category is intentially omitted here as it is generated
+ // from the other members
+ return d->object == other.d->object &&
+ d->core.coreIndex == other.d->core.coreIndex &&
+ d->core.isValueTypeVirtual() == other.d->core.isValueTypeVirtual() &&
+ (!d->core.isValueTypeVirtual() ||
+ (d->core.valueTypeCoreIndex == other.d->core.valueTypeCoreIndex &&
+ d->core.valueTypePropType == other.d->core.valueTypePropType));
+}
+
+/*!
+ Returns the QVariant type of the property, or QVariant::Invalid if the
+ property has no QVariant type.
+*/
+int QQmlProperty::propertyType() const
+{
+ return d ? d->propertyType() : int(QVariant::Invalid);
+}
+
+bool QQmlPropertyPrivate::isValueType() const
+{
+ return core.isValueTypeVirtual();
+}
+
+int QQmlPropertyPrivate::propertyType() const
+{
+ uint type = this->type();
+ if (isValueType()) {
+ return core.valueTypePropType;
+ } else if (type & QQmlProperty::Property) {
+ return core.propType;
+ } else {
+ return QVariant::Invalid;
+ }
+}
+
+QQmlProperty::Type QQmlPropertyPrivate::type() const
+{
+ if (core.isFunction())
+ return QQmlProperty::SignalProperty;
+ else if (core.isValid())
+ return QQmlProperty::Property;
+ else
+ return QQmlProperty::Invalid;
+}
+
+/*!
+ Returns the type of the property.
+*/
+QQmlProperty::Type QQmlProperty::type() const
+{
+ return d ? d->type() : Invalid;
+}
+
+/*!
+ Returns true if this QQmlProperty represents a regular Qt property.
+*/
+bool QQmlProperty::isProperty() const
+{
+ return type() & Property;
+}
+
+/*!
+ Returns true if this QQmlProperty represents a QML signal property.
+*/
+bool QQmlProperty::isSignalProperty() const
+{
+ return type() & SignalProperty;
+}
+
+/*!
+ Returns the QQmlProperty's QObject.
+*/
+QObject *QQmlProperty::object() const
+{
+ return d ? d->object : 0;
+}
+
+/*!
+ Assign \a other to this QQmlProperty.
+*/
+QQmlProperty &QQmlProperty::operator=(const QQmlProperty &other)
+{
+ if (d)
+ d->release();
+ d = other.d;
+ if (d)
+ d->addref();
+
+ return *this;
+}
+
+/*!
+ Returns true if the property is writable, otherwise false.
+*/
+bool QQmlProperty::isWritable() const
+{
+ if (!d)
+ return false;
+ if (!d->object)
+ return false;
+ if (d->core.isQList()) //list
+ return true;
+ else if (d->core.isFunction()) //signal handler
+ return false;
+ else if (d->core.isValid()) //normal property
+ return d->core.isWritable();
+ else
+ return false;
+}
+
+/*!
+ Returns true if the property is designable, otherwise false.
+*/
+bool QQmlProperty::isDesignable() const
+{
+ if (!d)
+ return false;
+ if (type() & Property && d->core.isValid() && d->object)
+ return d->object->metaObject()->property(d->core.coreIndex).isDesignable();
+ else
+ return false;
+}
+
+/*!
+ Returns true if the property is resettable, otherwise false.
+*/
+bool QQmlProperty::isResettable() const
+{
+ if (!d)
+ return false;
+ if (type() & Property && d->core.isValid() && d->object)
+ return d->core.isResettable();
+ else
+ return false;
+}
+
+/*!
+ Returns true if the QQmlProperty refers to a valid property, otherwise
+ false.
+*/
+bool QQmlProperty::isValid() const
+{
+ if (!d)
+ return false;
+ return type() != Invalid;
+}
+
+/*!
+ Return the name of this QML property.
+*/
+QString QQmlProperty::name() const
+{
+ if (!d)
+ return QString();
+ if (!d->isNameCached) {
+ // ###
+ if (!d->object) {
+ } else if (d->isValueType()) {
+ QString rv = d->core.name(d->object) + QLatin1Char('.');
+
+ QQmlEnginePrivate *ep = d->engine?QQmlEnginePrivate::get(d->engine):0;
+ QQmlValueType *valueType = 0;
+ if (ep) valueType = ep->valueTypes[d->core.propType];
+ else valueType = QQmlValueTypeFactory::valueType(d->core.propType);
+ Q_ASSERT(valueType);
+
+ const char *vtName = valueType->metaObject()->property(d->core.valueTypeCoreIndex).name();
+ rv += QString::fromUtf8(vtName);
+
+ if (!ep) delete valueType;
+
+ d->nameCache = rv;
+ } else if (type() & SignalProperty) {
+ QString name = QLatin1String("on") + d->core.name(d->object);
+ name[2] = name.at(2).toUpper();
+ d->nameCache = name;
+ } else {
+ d->nameCache = d->core.name(d->object);
+ }
+ d->isNameCached = true;
+ }
+
+ return d->nameCache;
+}
+
+/*!
+ Returns the \l{QMetaProperty} {Qt property} associated with
+ this QML property.
+ */
+QMetaProperty QQmlProperty::property() const
+{
+ if (!d)
+ return QMetaProperty();
+ if (type() & Property && d->core.isValid() && d->object)
+ return d->object->metaObject()->property(d->core.coreIndex);
+ else
+ return QMetaProperty();
+}
+
+/*!
+ Return the QMetaMethod for this property if it is a SignalProperty,
+ otherwise returns an invalid QMetaMethod.
+*/
+QMetaMethod QQmlProperty::method() const
+{
+ if (!d)
+ return QMetaMethod();
+ if (type() & SignalProperty && d->object)
+ return d->object->metaObject()->method(d->core.coreIndex);
+ else
+ return QMetaMethod();
+}
+
+/*!
+ Returns the binding associated with this property, or 0 if no binding
+ exists.
+*/
+QQmlAbstractBinding *
+QQmlPropertyPrivate::binding(const QQmlProperty &that)
+{
+ if (!that.d || !that.isProperty() || !that.d->object)
+ return 0;
+
+ return binding(that.d->object, that.d->core.coreIndex,
+ that.d->core.getValueTypeCoreIndex());
+}
+
+/*!
+ Set the binding associated with this property to \a newBinding. Returns
+ the existing binding (if any), otherwise 0.
+
+ \a newBinding will be enabled, and the returned binding (if any) will be
+ disabled.
+
+ Ownership of \a newBinding transfers to QML. Ownership of the return value
+ is assumed by the caller.
+
+ \a flags is passed through to the binding and is used for the initial update (when
+ the binding sets the initial value, it will use these flags for the write).
+*/
+QQmlAbstractBinding *
+QQmlPropertyPrivate::setBinding(const QQmlProperty &that,
+ QQmlAbstractBinding *newBinding,
+ WriteFlags flags)
+{
+ if (!that.d || !that.isProperty() || !that.d->object) {
+ if (newBinding)
+ newBinding->destroy();
+ return 0;
+ }
+
+ if (newBinding) {
+ // In the case that the new binding is provided, we must target the property it
+ // is associated with. If we don't do this, retargetBinding() can fail.
+ QObject *object = newBinding->object();
+ int pi = newBinding->propertyIndex();
+
+ int core = pi & 0xFFFFFF;
+ int vt = (pi & 0xFF000000)?(pi >> 24):-1;
+
+ return setBinding(object, core, vt, newBinding, flags);
+ } else {
+ return setBinding(that.d->object, that.d->core.coreIndex,
+ that.d->core.getValueTypeCoreIndex(),
+ newBinding, flags);
+ }
+}
+
+QQmlAbstractBinding *
+QQmlPropertyPrivate::binding(QObject *object, int coreIndex, int valueTypeIndex)
+{
+ QQmlData *data = QQmlData::get(object);
+ if (!data)
+ return 0;
+
+ QQmlPropertyData *propertyData =
+ data->propertyCache?data->propertyCache->property(coreIndex):0;
+ if (propertyData && propertyData->isAlias()) {
+ const QQmlVMEMetaObject *vme =
+ static_cast<const QQmlVMEMetaObject *>(metaObjectForProperty(object->metaObject(), coreIndex));
+
+ QObject *aObject = 0; int aCoreIndex = -1; int aValueTypeIndex = -1;
+ if (!vme->aliasTarget(coreIndex, &aObject, &aCoreIndex, &aValueTypeIndex) || aCoreIndex == -1)
+ return 0;
+
+ // This will either be a value type sub-reference or an alias to a value-type sub-reference not both
+ Q_ASSERT(valueTypeIndex == -1 || aValueTypeIndex == -1);
+ aValueTypeIndex = (valueTypeIndex == -1)?aValueTypeIndex:valueTypeIndex;
+ return binding(aObject, aCoreIndex, aValueTypeIndex);
+ }
+
+ if (!data->hasBindingBit(coreIndex))
+ return 0;
+
+ QQmlAbstractBinding *binding = data->bindings;
+ while (binding && binding->propertyIndex() != coreIndex)
+ binding = binding->m_nextBinding;
+
+ if (binding && valueTypeIndex != -1) {
+ if (binding->bindingType() == QQmlAbstractBinding::ValueTypeProxy) {
+ int index = coreIndex | (valueTypeIndex << 24);
+ binding = static_cast<QQmlValueTypeProxyBinding *>(binding)->binding(index);
+ }
+ }
+
+ return binding;
+}
+
+void QQmlPropertyPrivate::findAliasTarget(QObject *object, int bindingIndex,
+ QObject **targetObject, int *targetBindingIndex)
+{
+ int coreIndex = bindingIndex & 0xFFFFFF;
+ int valueTypeIndex = bindingIndex >> 24;
+ if (valueTypeIndex == 0) valueTypeIndex = -1;
+
+ QQmlData *data = QQmlData::get(object, false);
+ if (data) {
+ QQmlPropertyData *propertyData =
+ data->propertyCache?data->propertyCache->property(coreIndex):0;
+ if (propertyData && propertyData->isAlias()) {
+ const QQmlVMEMetaObject *vme =
+ static_cast<const QQmlVMEMetaObject *>(metaObjectForProperty(object->metaObject(), coreIndex));
+ QObject *aObject = 0; int aCoreIndex = -1; int aValueTypeIndex = -1;
+ if (vme->aliasTarget(coreIndex, &aObject, &aCoreIndex, &aValueTypeIndex)) {
+ // This will either be a value type sub-reference or an alias to a value-type sub-reference not both
+ Q_ASSERT(valueTypeIndex == -1 || aValueTypeIndex == -1);
+
+ int aBindingIndex = aCoreIndex;
+ if (aValueTypeIndex != -1)
+ aBindingIndex |= aValueTypeIndex << 24;
+ else if (valueTypeIndex != -1)
+ aBindingIndex |= valueTypeIndex << 24;
+
+ findAliasTarget(aObject, aBindingIndex, targetObject, targetBindingIndex);
+ return;
+ }
+ }
+ }
+
+ *targetObject = object;
+ *targetBindingIndex = bindingIndex;
+}
+
+QQmlAbstractBinding *
+QQmlPropertyPrivate::setBinding(QObject *object, int coreIndex, int valueTypeIndex,
+ QQmlAbstractBinding *newBinding, WriteFlags flags)
+{
+ QQmlData *data = QQmlData::get(object, 0 != newBinding);
+ QQmlAbstractBinding *binding = 0;
+
+ if (data) {
+ QQmlPropertyData *propertyData =
+ data->propertyCache?data->propertyCache->property(coreIndex):0;
+ if (propertyData && propertyData->isAlias()) {
+ const QQmlVMEMetaObject *vme =
+ static_cast<const QQmlVMEMetaObject *>(metaObjectForProperty(object->metaObject(), coreIndex));
+
+ QObject *aObject = 0; int aCoreIndex = -1; int aValueTypeIndex = -1;
+ if (!vme->aliasTarget(coreIndex, &aObject, &aCoreIndex, &aValueTypeIndex)) {
+ if (newBinding) newBinding->destroy();
+ return 0;
+ }
+
+ // This will either be a value type sub-reference or an alias to a value-type sub-reference not both
+ Q_ASSERT(valueTypeIndex == -1 || aValueTypeIndex == -1);
+ aValueTypeIndex = (valueTypeIndex == -1)?aValueTypeIndex:valueTypeIndex;
+ return setBinding(aObject, aCoreIndex, aValueTypeIndex, newBinding, flags);
+ }
+ }
+
+ if (data && data->hasBindingBit(coreIndex)) {
+ binding = data->bindings;
+
+ while (binding && binding->propertyIndex() != coreIndex)
+ binding = binding->m_nextBinding;
+ }
+
+ int index = coreIndex;
+ if (valueTypeIndex != -1)
+ index |= (valueTypeIndex << 24);
+
+ if (binding && valueTypeIndex != -1 && binding->bindingType() == QQmlAbstractBinding::ValueTypeProxy)
+ binding = static_cast<QQmlValueTypeProxyBinding *>(binding)->binding(index);
+
+ if (binding) {
+ binding->removeFromObject();
+ binding->setEnabled(false, 0);
+ }
+
+ if (newBinding) {
+ if (newBinding->propertyIndex() != index || newBinding->object() != object)
+ newBinding->retargetBinding(object, index);
+
+ Q_ASSERT(newBinding->propertyIndex() == index);
+ Q_ASSERT(newBinding->object() == object);
+
+ newBinding->addToObject();
+ newBinding->setEnabled(true, flags);
+ }
+
+ return binding;
+}
+
+QQmlAbstractBinding *
+QQmlPropertyPrivate::setBindingNoEnable(QObject *object, int coreIndex, int valueTypeIndex,
+ QQmlAbstractBinding *newBinding)
+{
+ QQmlData *data = QQmlData::get(object, 0 != newBinding);
+ QQmlAbstractBinding *binding = 0;
+
+ if (data) {
+ QQmlPropertyData *propertyData =
+ data->propertyCache?data->propertyCache->property(coreIndex):0;
+ if (propertyData && propertyData->isAlias()) {
+ const QQmlVMEMetaObject *vme =
+ static_cast<const QQmlVMEMetaObject *>(metaObjectForProperty(object->metaObject(), coreIndex));
+
+ QObject *aObject = 0; int aCoreIndex = -1; int aValueTypeIndex = -1;
+ if (!vme->aliasTarget(coreIndex, &aObject, &aCoreIndex, &aValueTypeIndex)) {
+ if (newBinding) newBinding->destroy();
+ return 0;
+ }
+
+ // This will either be a value type sub-reference or an alias to a value-type sub-reference not both
+ Q_ASSERT(valueTypeIndex == -1 || aValueTypeIndex == -1);
+ aValueTypeIndex = (valueTypeIndex == -1)?aValueTypeIndex:valueTypeIndex;
+ return setBindingNoEnable(aObject, aCoreIndex, aValueTypeIndex, newBinding);
+ }
+ }
+
+ if (data && data->hasBindingBit(coreIndex)) {
+ binding = data->bindings;
+
+ while (binding && binding->propertyIndex() != coreIndex)
+ binding = binding->m_nextBinding;
+ }
+
+ int index = coreIndex;
+ if (valueTypeIndex != -1)
+ index |= (valueTypeIndex << 24);
+
+ if (binding && valueTypeIndex != -1 && binding->bindingType() == QQmlAbstractBinding::ValueTypeProxy)
+ binding = static_cast<QQmlValueTypeProxyBinding *>(binding)->binding(index);
+
+ if (binding)
+ binding->removeFromObject();
+
+ if (newBinding) {
+ if (newBinding->propertyIndex() != index || newBinding->object() != object)
+ newBinding->retargetBinding(object, index);
+
+ Q_ASSERT(newBinding->propertyIndex() == index);
+ Q_ASSERT(newBinding->object() == object);
+
+ newBinding->addToObject();
+ }
+
+ return binding;
+}
+
+/*!
+ Returns the expression associated with this signal property, or 0 if no
+ signal expression exists.
+*/
+QQmlExpression *
+QQmlPropertyPrivate::signalExpression(const QQmlProperty &that)
+{
+ if (!(that.type() & QQmlProperty::SignalProperty))
+ return 0;
+
+ const QObjectList &children = that.d->object->children();
+
+ for (int ii = 0; ii < children.count(); ++ii) {
+ QObject *child = children.at(ii);
+
+ QQmlBoundSignal *signal = QQmlBoundSignal::cast(child);
+ if (signal && signal->index() == that.index())
+ return signal->expression();
+ }
+
+ return 0;
+}
+
+/*!
+ Set the signal expression associated with this signal property to \a expr.
+ Returns the existing signal expression (if any), otherwise 0.
+
+ Ownership of \a expr transfers to QML. Ownership of the return value is
+ assumed by the caller.
+*/
+QQmlExpression *
+QQmlPropertyPrivate::setSignalExpression(const QQmlProperty &that,
+ QQmlExpression *expr)
+{
+ if (!(that.type() & QQmlProperty::SignalProperty)) {
+ delete expr;
+ return 0;
+ }
+
+ const QObjectList &children = that.d->object->children();
+
+ for (int ii = 0; ii < children.count(); ++ii) {
+ QObject *child = children.at(ii);
+
+ QQmlBoundSignal *signal = QQmlBoundSignal::cast(child);
+ if (signal && signal->index() == that.index())
+ return signal->setExpression(expr);
+ }
+
+ if (expr) {
+ QQmlBoundSignal *signal = new QQmlBoundSignal(that.d->object, that.method(), that.d->object);
+ return signal->setExpression(expr);
+ } else {
+ return 0;
+ }
+}
+
+/*!
+ Returns the property value.
+*/
+QVariant QQmlProperty::read() const
+{
+ if (!d)
+ return QVariant();
+ if (!d->object)
+ return QVariant();
+
+ if (type() & SignalProperty) {
+
+ return QVariant();
+
+ } else if (type() & Property) {
+
+ return d->readValueProperty();
+
+ }
+ return QVariant();
+}
+
+/*!
+Return the \a name property value of \a object. This method is equivalent to:
+\code
+ QQmlProperty p(object, name);
+ p.read();
+\endcode
+*/
+QVariant QQmlProperty::read(QObject *object, const QString &name)
+{
+ QQmlProperty p(object, name);
+ return p.read();
+}
+
+/*!
+ Return the \a name property value of \a object using the
+ \l{QQmlContext} {context} \a ctxt. This method is
+ equivalent to:
+
+ \code
+ QQmlProperty p(object, name, context);
+ p.read();
+ \endcode
+*/
+QVariant QQmlProperty::read(QObject *object, const QString &name, QQmlContext *ctxt)
+{
+ QQmlProperty p(object, name, ctxt);
+ return p.read();
+}
+
+/*!
+
+ Return the \a name property value of \a object using the environment
+ for instantiating QML components that is provided by \a engine. .
+ This method is equivalent to:
+
+ \code
+ QQmlProperty p(object, name, engine);
+ p.read();
+ \endcode
+*/
+QVariant QQmlProperty::read(QObject *object, const QString &name, QQmlEngine *engine)
+{
+ QQmlProperty p(object, name, engine);
+ return p.read();
+}
+
+QVariant QQmlPropertyPrivate::readValueProperty()
+{
+ if (isValueType()) {
+
+ QQmlEnginePrivate *ep = engine?QQmlEnginePrivate::get(engine):0;
+ QQmlValueType *valueType = 0;
+ if (ep) valueType = ep->valueTypes[core.propType];
+ else valueType = QQmlValueTypeFactory::valueType(core.propType);
+ Q_ASSERT(valueType);
+
+ valueType->read(object, core.coreIndex);
+
+ QVariant rv = valueType->metaObject()->property(core.valueTypeCoreIndex).read(valueType);
+
+ if (!ep) delete valueType;
+ return rv;
+
+ } else if (core.isQList()) {
+
+ QQmlListProperty<QObject> prop;
+ void *args[] = { &prop, 0 };
+ QMetaObject::metacall(object, QMetaObject::ReadProperty, core.coreIndex, args);
+ return QVariant::fromValue(QQmlListReferencePrivate::init(prop, core.propType, engine));
+
+ } else if (core.isQObject()) {
+
+ QObject *rv = 0;
+ void *args[] = { &rv, 0 };
+ QMetaObject::metacall(object, QMetaObject::ReadProperty, core.coreIndex, args);
+ return QVariant::fromValue(rv);
+
+ } else {
+
+ return object->metaObject()->property(core.coreIndex).read(object.data());
+
+ }
+}
+
+static QUrl urlFromUserString(const QByteArray &data)
+{
+ QUrl u;
+ if (!data.isEmpty())
+ {
+ // Preserve any valid percent-encoded octets supplied by the source
+ u.setEncodedUrl(data, QUrl::TolerantMode);
+ }
+ return u;
+}
+
+static QUrl urlFromUserString(const QString &data)
+{
+ return urlFromUserString(data.toUtf8());
+}
+
+// helper function to allow assignment / binding to QList<QUrl> properties.
+static QVariant resolvedUrlSequence(const QVariant &value, QQmlContextData *context)
+{
+ QList<QUrl> urls;
+ if (value.userType() == qMetaTypeId<QUrl>()) {
+ urls.append(value.toUrl());
+ } else if (value.userType() == qMetaTypeId<QString>()) {
+ urls.append(urlFromUserString(value.toString()));
+ } else if (value.userType() == qMetaTypeId<QByteArray>()) {
+ urls.append(urlFromUserString(value.toByteArray()));
+ } else if (value.userType() == qMetaTypeId<QList<QUrl> >()) {
+ urls = value.value<QList<QUrl> >();
+ } else if (value.userType() == qMetaTypeId<QStringList>()) {
+ QStringList urlStrings = value.value<QStringList>();
+ for (int i = 0; i < urlStrings.size(); ++i)
+ urls.append(urlFromUserString(urlStrings.at(i)));
+ } else if (value.userType() == qMetaTypeId<QList<QString> >()) {
+ QList<QString> urlStrings = value.value<QList<QString> >();
+ for (int i = 0; i < urlStrings.size(); ++i)
+ urls.append(urlFromUserString(urlStrings.at(i)));
+ } // note: QList<QByteArray> is not currently supported.
+
+ QList<QUrl> resolvedUrls;
+ for (int i = 0; i < urls.size(); ++i) {
+ QUrl u = urls.at(i);
+ if (context && u.isRelative() && !u.isEmpty())
+ u = context->resolvedUrl(u);
+ resolvedUrls.append(u);
+ }
+
+ return QVariant::fromValue<QList<QUrl> >(resolvedUrls);
+}
+
+//writeEnumProperty MIRRORS the relelvant bit of QMetaProperty::write AND MUST BE KEPT IN SYNC!
+bool QQmlPropertyPrivate::writeEnumProperty(const QMetaProperty &prop, int idx, QObject *object, const QVariant &value, int flags)
+{
+ if (!object || !prop.isWritable())
+ return false;
+
+ QVariant v = value;
+ if (prop.isEnumType()) {
+ QMetaEnum menum = prop.enumerator();
+ if (v.userType() == QVariant::String
+#ifdef QT3_SUPPORT
+ || v.userType() == QVariant::CString
+#endif
+ ) {
+ bool ok;
+ if (prop.isFlagType())
+ v = QVariant(menum.keysToValue(value.toByteArray(), &ok));
+ else
+ v = QVariant(menum.keyToValue(value.toByteArray(), &ok));
+ if (!ok)
+ return false;
+ } else if (v.userType() != QVariant::Int && v.userType() != QVariant::UInt) {
+ int enumMetaTypeId = QMetaType::type(QByteArray(menum.scope() + QByteArray("::") + menum.name()));
+ if ((enumMetaTypeId == 0) || (v.userType() != enumMetaTypeId) || !v.constData())
+ return false;
+ v = QVariant(*reinterpret_cast<const int *>(v.constData()));
+ }
+ v.convert(QVariant::Int);
+ }
+
+ // the status variable is changed by qt_metacall to indicate what it did
+ // this feature is currently only used by QtDBus and should not be depended
+ // upon. Don't change it without looking into QDBusAbstractInterface first
+ // -1 (unchanged): normal qt_metacall, result stored in argv[0]
+ // changed: result stored directly in value, return the value of status
+ int status = -1;
+ void *argv[] = { v.data(), &v, &status, &flags };
+ QMetaObject::metacall(object, QMetaObject::WriteProperty, idx, argv);
+ return status;
+}
+
+bool QQmlPropertyPrivate::writeValueProperty(const QVariant &value, WriteFlags flags)
+{
+ return writeValueProperty(object, engine, core, value, effectiveContext(), flags);
+}
+
+bool
+QQmlPropertyPrivate::writeValueProperty(QObject *object, QQmlEngine *engine,
+ const QQmlPropertyData &core,
+ const QVariant &value,
+ QQmlContextData *context, WriteFlags flags)
+{
+ // Remove any existing bindings on this property
+ if (!(flags & DontRemoveBinding) && object) {
+ QQmlAbstractBinding *binding = setBinding(object, core.coreIndex,
+ core.getValueTypeCoreIndex(),
+ 0, flags);
+ if (binding) binding->destroy();
+ }
+
+ bool rv = false;
+ if (core.isValueTypeVirtual()) {
+ QQmlEnginePrivate *ep = engine?QQmlEnginePrivate::get(engine):0;
+
+ QQmlValueType *writeBack = 0;
+ if (ep) {
+ writeBack = ep->valueTypes[core.propType];
+ } else {
+ writeBack = QQmlValueTypeFactory::valueType(core.propType);
+ }
+
+ writeBack->read(object, core.coreIndex);
+
+ QQmlPropertyData data = core;
+ data.setFlags(QQmlPropertyData::Flag(core.valueTypeFlags));
+ data.coreIndex = core.valueTypeCoreIndex;
+ data.propType = core.valueTypePropType;
+
+ rv = write(writeBack, data, value, context, flags);
+
+ writeBack->write(object, core.coreIndex, flags);
+ if (!ep) delete writeBack;
+
+ } else {
+
+ rv = write(object, core, value, context, flags);
+
+ }
+
+ return rv;
+}
+
+bool QQmlPropertyPrivate::write(QObject *object,
+ const QQmlPropertyData &property,
+ const QVariant &value, QQmlContextData *context,
+ WriteFlags flags)
+{
+ int coreIdx = property.coreIndex;
+ int status = -1; //for dbus
+
+ if (property.isEnum()) {
+ QMetaProperty prop = object->metaObject()->property(property.coreIndex);
+ QVariant v = value;
+ // Enum values come through the script engine as doubles
+ if (value.userType() == QVariant::Double) {
+ double integral;
+ double fractional = modf(value.toDouble(), &integral);
+ if (qFuzzyIsNull(fractional))
+ v.convert(QVariant::Int);
+ }
+ return writeEnumProperty(prop, coreIdx, object, v, flags);
+ }
+
+ int propertyType = property.propType;
+ int variantType = value.userType();
+
+ QQmlEnginePrivate *enginePriv = QQmlEnginePrivate::get(context);
+
+ if (propertyType == QVariant::Url) {
+
+ QUrl u;
+ bool found = false;
+ if (variantType == QVariant::Url) {
+ u = value.toUrl();
+ found = true;
+ } else if (variantType == QVariant::ByteArray) {
+ u = urlFromUserString(value.toByteArray());
+ found = true;
+ } else if (variantType == QVariant::String) {
+ u = urlFromUserString(value.toString());
+ found = true;
+ }
+
+ if (!found)
+ return false;
+
+ if (context && u.isRelative() && !u.isEmpty())
+ u = context->resolvedUrl(u);
+ int status = -1;
+ void *argv[] = { &u, 0, &status, &flags };
+ QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, argv);
+
+ } else if (propertyType == qMetaTypeId<QList<QUrl> >()) {
+ QList<QUrl> urlSeq = resolvedUrlSequence(value, context).value<QList<QUrl> >();
+ int status = -1;
+ void *argv[] = { &urlSeq, 0, &status, &flags };
+ QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, argv);
+ } else if (variantType == propertyType) {
+
+ void *a[] = { (void *)value.constData(), 0, &status, &flags };
+ QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, a);
+
+ } else if (qMetaTypeId<QVariant>() == propertyType) {
+
+ void *a[] = { (void *)&value, 0, &status, &flags };
+ QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, a);
+
+ } else if (property.isQObject()) {
+
+ const QMetaObject *valMo = rawMetaObjectForType(enginePriv, value.userType());
+
+ if (!valMo)
+ return false;
+
+ QObject *o = *(QObject **)value.constData();
+ const QMetaObject *propMo = rawMetaObjectForType(enginePriv, propertyType);
+
+ if (o) valMo = o->metaObject();
+
+ if (canConvert(valMo, propMo)) {
+ void *args[] = { &o, 0, &status, &flags };
+ QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx,
+ args);
+ } else if (!o && canConvert(propMo, valMo)) {
+ // In the case of a null QObject, we assign the null if there is
+ // any change that the null variant type could be up or down cast to
+ // the property type.
+ void *args[] = { &o, 0, &status, &flags };
+ QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx,
+ args);
+ } else {
+ return false;
+ }
+
+ } else if (property.isQList()) {
+
+ const QMetaObject *listType = 0;
+ if (enginePriv) {
+ listType = enginePriv->rawMetaObjectForType(enginePriv->listType(property.propType));
+ } else {
+ QQmlType *type = QQmlMetaType::qmlType(QQmlMetaType::listType(property.propType));
+ if (!type) return false;
+ listType = type->baseMetaObject();
+ }
+ if (!listType) return false;
+
+ QQmlListProperty<void> prop;
+ void *args[] = { &prop, 0 };
+ QMetaObject::metacall(object, QMetaObject::ReadProperty, coreIdx, args);
+
+ if (!prop.clear) return false;
+
+ prop.clear(&prop);
+
+ if (value.userType() == qMetaTypeId<QQmlListReference>()) {
+ QQmlListReference qdlr = value.value<QQmlListReference>();
+
+ for (int ii = 0; ii < qdlr.count(); ++ii) {
+ QObject *o = qdlr.at(ii);
+ if (o && !canConvert(o->metaObject(), listType))
+ o = 0;
+ prop.append(&prop, (void *)o);
+ }
+ } else if (value.userType() == qMetaTypeId<QList<QObject *> >()) {
+ const QList<QObject *> &list = qvariant_cast<QList<QObject *> >(value);
+
+ for (int ii = 0; ii < list.count(); ++ii) {
+ QObject *o = list.at(ii);
+ if (o && !canConvert(o->metaObject(), listType))
+ o = 0;
+ prop.append(&prop, (void *)o);
+ }
+ } else {
+ QObject *o = enginePriv?enginePriv->toQObject(value):QQmlMetaType::toQObject(value);
+ if (o && !canConvert(o->metaObject(), listType))
+ o = 0;
+ prop.append(&prop, (void *)o);
+ }
+
+ } else {
+ Q_ASSERT(variantType != propertyType);
+
+ bool ok = false;
+ QVariant v;
+ if (variantType == QVariant::String)
+ v = QQmlStringConverters::variantFromString(value.toString(), propertyType, &ok);
+ if (!ok) {
+ v = value;
+ if (v.convert((QVariant::Type)propertyType)) {
+ ok = true;
+ } else if ((uint)propertyType >= QVariant::UserType && variantType == QVariant::String) {
+ QQmlMetaType::StringConverter con = QQmlMetaType::customStringConverter(propertyType);
+ if (con) {
+ v = con(value.toString());
+ if (v.userType() == propertyType)
+ ok = true;
+ }
+ }
+ }
+ if (!ok) {
+ // the only other option is that they are assigning a single value
+ // to a sequence type property (eg, an int to a QList<int> property).
+ // Note that we've already handled single-value assignment to QList<QUrl> properties.
+ if (variantType == QVariant::Int && propertyType == qMetaTypeId<QList<int> >()) {
+ QList<int> list;
+ list << value.toInt();
+ v = QVariant::fromValue<QList<int> >(list);
+ ok = true;
+ } else if (variantType == QVariant::Double && propertyType == qMetaTypeId<QList<qreal> >()) {
+ QList<qreal> list;
+ list << value.toReal();
+ v = QVariant::fromValue<QList<qreal> >(list);
+ ok = true;
+ } else if (variantType == QVariant::Bool && propertyType == qMetaTypeId<QList<bool> >()) {
+ QList<bool> list;
+ list << value.toBool();
+ v = QVariant::fromValue<QList<bool> >(list);
+ ok = true;
+ } else if (variantType == QVariant::String && propertyType == qMetaTypeId<QList<QString> >()) {
+ QList<QString> list;
+ list << value.toString();
+ v = QVariant::fromValue<QList<QString> >(list);
+ ok = true;
+ } else if (variantType == QVariant::String && propertyType == qMetaTypeId<QStringList>()) {
+ QStringList list;
+ list << value.toString();
+ v = QVariant::fromValue<QStringList>(list);
+ ok = true;
+ }
+ }
+
+ if (ok) {
+ void *a[] = { (void *)v.constData(), 0, &status, &flags};
+ QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, a);
+ } else {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+// Returns true if successful, false if an error description was set on expression
+bool QQmlPropertyPrivate::writeBinding(QObject *object,
+ const QQmlPropertyData &core,
+ QQmlContextData *context,
+ QQmlJavaScriptExpression *expression,
+ v8::Handle<v8::Value> result, bool isUndefined,
+ WriteFlags flags)
+{
+ Q_ASSERT(object);
+ Q_ASSERT(core.coreIndex != -1);
+
+ QQmlEngine *engine = context->engine;
+ QV8Engine *v8engine = QQmlEnginePrivate::getV8Engine(engine);
+
+#define QUICK_STORE(cpptype, conversion) \
+ { \
+ cpptype o = (conversion); \
+ int status = -1; \
+ void *argv[] = { &o, 0, &status, &flags }; \
+ QMetaObject::metacall(object, QMetaObject::WriteProperty, core.coreIndex, argv); \
+ return true; \
+ } \
+
+
+ if (!isUndefined && !core.isValueTypeVirtual()) {
+ switch (core.propType) {
+ case QMetaType::Int:
+ if (result->IsInt32())
+ QUICK_STORE(int, result->Int32Value())
+ else if (result->IsNumber())
+ QUICK_STORE(int, qRound(result->NumberValue()))
+ break;
+ case QMetaType::Double:
+ if (result->IsNumber())
+ QUICK_STORE(double, result->NumberValue())
+ break;
+ case QMetaType::Float:
+ if (result->IsNumber())
+ QUICK_STORE(float, result->NumberValue())
+ break;
+ case QMetaType::QString:
+ if (result->IsString())
+ QUICK_STORE(QString, v8engine->toString(result))
+ break;
+ default:
+ break;
+ }
+ }
+#undef QUICK_STORE
+
+ int type = core.isValueTypeVirtual()?core.valueTypePropType:core.propType;
+
+ QQmlJavaScriptExpression::DeleteWatcher watcher(expression);
+
+ QVariant value;
+ bool isVmeProperty = core.isVMEProperty();
+
+ if (isUndefined) {
+ } else if (core.isQList()) {
+ value = v8engine->toVariant(result, qMetaTypeId<QList<QObject *> >());
+ } else if (result->IsNull() && core.isQObject()) {
+ value = QVariant::fromValue((QObject *)0);
+ } else if (core.propType == qMetaTypeId<QList<QUrl> >()) {
+ value = resolvedUrlSequence(v8engine->toVariant(result, qMetaTypeId<QList<QUrl> >()), context);
+ } else if (!isVmeProperty) {
+ value = v8engine->toVariant(result, type);
+ }
+
+ if (expression->hasError()) {
+ return false;
+ } else if (isUndefined && core.isResettable()) {
+ void *args[] = { 0 };
+ QMetaObject::metacall(object, QMetaObject::ResetProperty, core.coreIndex, args);
+ } else if (isUndefined && type == qMetaTypeId<QVariant>()) {
+ writeValueProperty(object, engine, core, QVariant(), context, flags);
+ } else if (isUndefined) {
+ expression->delayedError()->error.setDescription(QLatin1String("Unable to assign [undefined] to ") + QLatin1String(QMetaType::typeName(type)));
+ return false;
+ } else if (result->IsFunction()) {
+ expression->delayedError()->error.setDescription(QLatin1String("Unable to assign a function to a property."));
+ return false;
+ } else if (isVmeProperty) {
+ typedef QQmlVMEMetaObject VMEMO;
+ VMEMO *vmemo = static_cast<VMEMO *>(const_cast<QMetaObject *>(object->metaObject()));
+ vmemo->setVMEProperty(core.coreIndex, result);
+ } else if (!writeValueProperty(object, engine, core, value, context, flags)) {
+
+ if (watcher.wasDeleted())
+ return true;
+
+ const char *valueType = 0;
+ if (value.userType() == QVariant::Invalid) valueType = "null";
+ else valueType = QMetaType::typeName(value.userType());
+
+ expression->delayedError()->error.setDescription(QLatin1String("Unable to assign ") +
+ QLatin1String(valueType) +
+ QLatin1String(" to ") +
+ QLatin1String(QMetaType::typeName(type)));
+ return false;
+ }
+
+ return true;
+}
+
+bool QQmlPropertyPrivate::writeBinding(const QQmlProperty &that,
+ QQmlContextData *context,
+ QQmlJavaScriptExpression *expression,
+ v8::Handle<v8::Value> result, bool isUndefined,
+ WriteFlags flags)
+{
+ QQmlPropertyPrivate *pp = that.d;
+
+ if (!pp)
+ return true;
+
+ QObject *object = that.object();
+ if (!object)
+ return true;
+
+ return writeBinding(object, pp->core, context, expression, result, isUndefined, flags);
+}
+
+const QMetaObject *QQmlPropertyPrivate::rawMetaObjectForType(QQmlEnginePrivate *engine, int userType)
+{
+ if (engine) {
+ return engine->rawMetaObjectForType(userType);
+ } else {
+ QQmlType *type = QQmlMetaType::qmlType(userType);
+ return type?type->baseMetaObject():0;
+ }
+}
+
+/*!
+ Sets the property value to \a value and returns true.
+ Returns false if the property can't be set because the
+ \a value is the wrong type, for example.
+ */
+bool QQmlProperty::write(const QVariant &value) const
+{
+ return QQmlPropertyPrivate::write(*this, value, 0);
+}
+
+/*!
+ Writes \a value to the \a name property of \a object. This method
+ is equivalent to:
+
+ \code
+ QQmlProperty p(object, name);
+ p.write(value);
+ \endcode
+*/
+bool QQmlProperty::write(QObject *object, const QString &name, const QVariant &value)
+{
+ QQmlProperty p(object, name);
+ return p.write(value);
+}
+
+/*!
+ Writes \a value to the \a name property of \a object using the
+ \l{QQmlContext} {context} \a ctxt. This method is
+ equivalent to:
+
+ \code
+ QQmlProperty p(object, name, ctxt);
+ p.write(value);
+ \endcode
+*/
+bool QQmlProperty::write(QObject *object,
+ const QString &name,
+ const QVariant &value,
+ QQmlContext *ctxt)
+{
+ QQmlProperty p(object, name, ctxt);
+ return p.write(value);
+}
+
+/*!
+
+ Writes \a value to the \a name property of \a object using the
+ environment for instantiating QML components that is provided by
+ \a engine. This method is equivalent to:
+
+ \code
+ QQmlProperty p(object, name, engine);
+ p.write(value);
+ \endcode
+*/
+bool QQmlProperty::write(QObject *object, const QString &name, const QVariant &value,
+ QQmlEngine *engine)
+{
+ QQmlProperty p(object, name, engine);
+ return p.write(value);
+}
+
+/*!
+ Resets the property and returns true if the property is
+ resettable. If the property is not resettable, nothing happens
+ and false is returned.
+*/
+bool QQmlProperty::reset() const
+{
+ if (isResettable()) {
+ void *args[] = { 0 };
+ QMetaObject::metacall(d->object, QMetaObject::ResetProperty, d->core.coreIndex, args);
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool QQmlPropertyPrivate::write(const QQmlProperty &that,
+ const QVariant &value, WriteFlags flags)
+{
+ if (!that.d)
+ return false;
+ if (that.d->object && that.type() & QQmlProperty::Property &&
+ that.d->core.isValid() && that.isWritable())
+ return that.d->writeValueProperty(value, flags);
+ else
+ return false;
+}
+
+/*!
+ Returns true if the property has a change notifier signal, otherwise false.
+*/
+bool QQmlProperty::hasNotifySignal() const
+{
+ if (type() & Property && d->object) {
+ return d->object->metaObject()->property(d->core.coreIndex).hasNotifySignal();
+ }
+ return false;
+}
+
+/*!
+ Returns true if the property needs a change notifier signal for bindings
+ to remain upto date, false otherwise.
+
+ Some properties, such as attached properties or those whose value never
+ changes, do not require a change notifier.
+*/
+bool QQmlProperty::needsNotifySignal() const
+{
+ return type() & Property && !property().isConstant();
+}
+
+/*!
+ Connects the property's change notifier signal to the
+ specified \a method of the \a dest object and returns
+ true. Returns false if this metaproperty does not
+ represent a regular Qt property or if it has no
+ change notifier signal, or if the \a dest object does
+ not have the specified \a method.
+*/
+bool QQmlProperty::connectNotifySignal(QObject *dest, int method) const
+{
+ if (!(type() & Property) || !d->object)
+ return false;
+
+ QMetaProperty prop = d->object->metaObject()->property(d->core.coreIndex);
+ if (prop.hasNotifySignal()) {
+ return QQmlPropertyPrivate::connect(d->object, prop.notifySignalIndex(), dest, method, Qt::DirectConnection);
+ } else {
+ return false;
+ }
+}
+
+/*!
+ Connects the property's change notifier signal to the
+ specified \a slot of the \a dest object and returns
+ true. Returns false if this metaproperty does not
+ represent a regular Qt property or if it has no
+ change notifier signal, or if the \a dest object does
+ not have the specified \a slot.
+*/
+bool QQmlProperty::connectNotifySignal(QObject *dest, const char *slot) const
+{
+ if (!(type() & Property) || !d->object)
+ return false;
+
+ QMetaProperty prop = d->object->metaObject()->property(d->core.coreIndex);
+ if (prop.hasNotifySignal()) {
+ QByteArray signal(QByteArray("2") + prop.notifySignal().signature());
+ return QObject::connect(d->object, signal.constData(), dest, slot);
+ } else {
+ return false;
+ }
+}
+
+/*!
+ Return the Qt metaobject index of the property.
+*/
+int QQmlProperty::index() const
+{
+ return d ? d->core.coreIndex : -1;
+}
+
+int QQmlPropertyPrivate::valueTypeCoreIndex(const QQmlProperty &that)
+{
+ return that.d ? that.d->core.getValueTypeCoreIndex() : -1;
+}
+
+/*!
+ Returns the "property index" for use in bindings. The top 8 bits are the value type
+ offset, and 0 otherwise. The bottom 24-bits are the regular property index.
+*/
+int QQmlPropertyPrivate::bindingIndex(const QQmlProperty &that)
+{
+ if (!that.d)
+ return -1;
+ return bindingIndex(that.d->core);
+}
+
+int QQmlPropertyPrivate::bindingIndex(const QQmlPropertyData &that)
+{
+ int rv = that.coreIndex;
+ if (rv != -1 && that.isValueTypeVirtual())
+ rv = rv | (that.valueTypeCoreIndex << 24);
+ return rv;
+}
+
+QQmlPropertyData
+QQmlPropertyPrivate::saveValueType(const QMetaObject *metaObject, int index,
+ const QMetaObject *subObject, int subIndex,
+ QQmlEngine *)
+{
+ QMetaProperty subProp = subObject->property(subIndex);
+
+ QQmlPropertyData core;
+ core.load(metaObject->property(index));
+ core.setFlags(core.getFlags() | QQmlPropertyData::IsValueTypeVirtual);
+ core.valueTypeFlags = QQmlPropertyData::flagsForProperty(subProp);
+ core.valueTypeCoreIndex = subIndex;
+ core.valueTypePropType = subProp.userType();
+
+ return core;
+}
+
+QQmlProperty
+QQmlPropertyPrivate::restore(QObject *object, const QQmlPropertyData &data,
+ QQmlContextData *ctxt)
+{
+ QQmlProperty prop;
+
+ prop.d = new QQmlPropertyPrivate;
+ prop.d->object = object;
+ prop.d->context = ctxt;
+ prop.d->engine = ctxt?ctxt->engine:0;
+
+ prop.d->core = data;
+
+ return prop;
+}
+
+/*!
+ Returns true if lhs and rhs refer to the same metaobject data
+*/
+bool QQmlPropertyPrivate::equal(const QMetaObject *lhs, const QMetaObject *rhs)
+{
+ return lhs == rhs || (1 && lhs && rhs && lhs->d.stringdata == rhs->d.stringdata);
+}
+
+/*!
+ Returns true if from inherits to.
+*/
+bool QQmlPropertyPrivate::canConvert(const QMetaObject *from, const QMetaObject *to)
+{
+ if (from && to == &QObject::staticMetaObject)
+ return true;
+
+ while (from) {
+ if (equal(from, to))
+ return true;
+ from = from->superClass();
+ }
+
+ return false;
+}
+
+/*!
+ Return the signal corresponding to \a name
+*/
+QMetaMethod QQmlPropertyPrivate::findSignalByName(const QMetaObject *mo, const QByteArray &name)
+{
+ Q_ASSERT(mo);
+ int methods = mo->methodCount();
+ for (int ii = methods - 1; ii >= 2; --ii) { // >= 2 to block the destroyed signal
+ QMetaMethod method = mo->method(ii);
+ QByteArray methodName = method.signature();
+ int idx = methodName.indexOf('(');
+ methodName = methodName.left(idx);
+
+ if (methodName == name)
+ return method;
+ }
+
+ // If no signal is found, but the signal is of the form "onBlahChanged",
+ // return the notify signal for the property "Blah"
+ if (name.endsWith("Changed")) {
+ QByteArray propName = name.mid(0, name.length() - 7);
+ int propIdx = mo->indexOfProperty(propName.constData());
+ if (propIdx >= 0) {
+ QMetaProperty prop = mo->property(propIdx);
+ if (prop.hasNotifySignal())
+ return prop.notifySignal();
+ }
+ }
+
+ return QMetaMethod();
+}
+
+static inline int QMetaObject_methods(const QMetaObject *metaObject)
+{
+ struct Private
+ {
+ int revision;
+ int className;
+ int classInfoCount, classInfoData;
+ int methodCount, methodData;
+ int propertyCount, propertyData;
+ };
+
+ return reinterpret_cast<const Private *>(metaObject->d.data)->methodCount;
+}
+
+static inline int QMetaObject_properties(const QMetaObject *metaObject)
+{
+ struct Private
+ {
+ int revision;
+ int className;
+ int classInfoCount, classInfoData;
+ int methodCount, methodData;
+ int propertyCount, propertyData;
+ };
+
+ return reinterpret_cast<const Private *>(metaObject->d.data)->propertyCount;
+}
+
+static inline void flush_vme_signal(const QObject *object, int index)
+{
+ QQmlData *data = static_cast<QQmlData *>(QObjectPrivate::get(const_cast<QObject *>(object))->declarativeData);
+ if (data && data->propertyCache) {
+ QQmlPropertyData *property = data->propertyCache->method(index);
+
+ if (property && property->isVMESignal()) {
+ const QMetaObject *metaObject = object->metaObject();
+ int methodOffset = metaObject->methodOffset();
+
+ while (methodOffset > index) {
+ metaObject = metaObject->d.superdata;
+ methodOffset -= QMetaObject_methods(metaObject);
+ }
+
+ QQmlVMEMetaObject *vme =
+ static_cast<QQmlVMEMetaObject *>(const_cast<QMetaObject *>(metaObject));
+
+ vme->connectAliasSignal(index);
+ }
+ }
+}
+
+/*!
+Connect \a sender \a signal_index to \a receiver \a method_index with the specified
+\a type and \a types. This behaves identically to QMetaObject::connect() except that
+it connects any lazy "proxy" signal connections set up by QML.
+
+It is possible that this logic should be moved to QMetaObject::connect().
+*/
+bool QQmlPropertyPrivate::connect(const QObject *sender, int signal_index,
+ const QObject *receiver, int method_index,
+ int type, int *types)
+{
+ flush_vme_signal(sender, signal_index);
+ flush_vme_signal(receiver, method_index);
+
+ return QMetaObject::connect(sender, signal_index, receiver, method_index, type, types);
+}
+
+void QQmlPropertyPrivate::flushSignal(const QObject *sender, int signal_index)
+{
+ flush_vme_signal(sender, signal_index);
+}
+
+/*!
+Return \a metaObject's [super] meta object that provides data for \a property.
+*/
+const QMetaObject *QQmlPropertyPrivate::metaObjectForProperty(const QMetaObject *metaObject, int property)
+{
+ int propertyOffset = metaObject->propertyOffset();
+
+ while (propertyOffset > property) {
+ metaObject = metaObject->d.superdata;
+ propertyOffset -= QMetaObject_properties(metaObject);
+ }
+
+ return metaObject;
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlproperty.h b/src/qml/qml/qqmlproperty.h
new file mode 100644
index 0000000000..2c4b2544c1
--- /dev/null
+++ b/src/qml/qml/qqmlproperty.h
@@ -0,0 +1,143 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLPROPERTY_H
+#define QQMLPROPERTY_H
+
+#include <QtQml/qtqmlglobal.h>
+#include <QtCore/qmetaobject.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+
+class QObject;
+class QVariant;
+class QQmlContext;
+class QQmlEngine;
+
+class QQmlPropertyPrivate;
+class Q_QML_EXPORT QQmlProperty
+{
+public:
+ enum PropertyTypeCategory {
+ InvalidCategory,
+ List,
+ Object,
+ Normal
+ };
+
+ enum Type {
+ Invalid,
+ Property,
+ SignalProperty
+ };
+
+ QQmlProperty();
+ ~QQmlProperty();
+
+ QQmlProperty(QObject *);
+ QQmlProperty(QObject *, QQmlContext *);
+ QQmlProperty(QObject *, QQmlEngine *);
+
+ QQmlProperty(QObject *, const QString &);
+ QQmlProperty(QObject *, const QString &, QQmlContext *);
+ QQmlProperty(QObject *, const QString &, QQmlEngine *);
+
+ QQmlProperty(const QQmlProperty &);
+ QQmlProperty &operator=(const QQmlProperty &);
+
+ bool operator==(const QQmlProperty &) const;
+
+ Type type() const;
+ bool isValid() const;
+ bool isProperty() const;
+ bool isSignalProperty() const;
+
+ int propertyType() const;
+ PropertyTypeCategory propertyTypeCategory() const;
+ const char *propertyTypeName() const;
+
+ QString name() const;
+
+ QVariant read() const;
+ static QVariant read(QObject *, const QString &);
+ static QVariant read(QObject *, const QString &, QQmlContext *);
+ static QVariant read(QObject *, const QString &, QQmlEngine *);
+
+ bool write(const QVariant &) const;
+ static bool write(QObject *, const QString &, const QVariant &);
+ static bool write(QObject *, const QString &, const QVariant &, QQmlContext *);
+ static bool write(QObject *, const QString &, const QVariant &, QQmlEngine *);
+
+ bool reset() const;
+
+ bool hasNotifySignal() const;
+ bool needsNotifySignal() const;
+ bool connectNotifySignal(QObject *dest, const char *slot) const;
+ bool connectNotifySignal(QObject *dest, int method) const;
+
+ bool isWritable() const;
+ bool isDesignable() const;
+ bool isResettable() const;
+ QObject *object() const;
+
+ int index() const;
+ QMetaProperty property() const;
+ QMetaMethod method() const;
+
+private:
+ friend class QQmlPropertyPrivate;
+ QQmlPropertyPrivate *d;
+};
+typedef QList<QQmlProperty> QQmlProperties;
+
+inline uint qHash (const QQmlProperty &key)
+{
+ return qHash(key.object()) + qHash(key.name());
+}
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QQMLPROPERTY_H
diff --git a/src/qml/qml/qqmlproperty_p.h b/src/qml/qml/qqmlproperty_p.h
new file mode 100644
index 0000000000..0f97a63155
--- /dev/null
+++ b/src/qml/qml/qqmlproperty_p.h
@@ -0,0 +1,171 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLPROPERTY_P_H
+#define QQMLPROPERTY_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 "qqmlproperty.h"
+
+#include <private/qobject_p.h>
+#include <private/qtqmlglobal_p.h>
+#include <private/qqmlpropertycache_p.h>
+#include <private/qqmlguard_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQmlContext;
+class QQmlExpression;
+class QQmlEnginePrivate;
+class QQmlJavaScriptExpression;
+class Q_QML_PRIVATE_EXPORT QQmlPropertyPrivate : public QQmlRefCount
+{
+public:
+ enum WriteFlag {
+ BypassInterceptor = 0x01,
+ DontRemoveBinding = 0x02,
+ RemoveBindingOnAliasWrite = 0x04
+ };
+ Q_DECLARE_FLAGS(WriteFlags, WriteFlag)
+
+ QQmlContextData *context;
+ QQmlEngine *engine;
+ QQmlGuard<QObject> object;
+
+ QQmlPropertyData core;
+
+ bool isNameCached:1;
+ QString nameCache;
+
+ QQmlPropertyPrivate();
+
+ inline QQmlContextData *effectiveContext() const;
+
+ void initProperty(QObject *obj, const QString &name);
+ void initDefault(QObject *obj);
+
+ bool isValueType() const;
+ int propertyType() const;
+ QQmlProperty::Type type() const;
+ QQmlProperty::PropertyTypeCategory propertyTypeCategory() const;
+
+ QVariant readValueProperty();
+ bool writeValueProperty(const QVariant &, WriteFlags);
+
+ static const QMetaObject *rawMetaObjectForType(QQmlEnginePrivate *, int);
+ static bool writeEnumProperty(const QMetaProperty &prop, int idx, QObject *object,
+ const QVariant &value, int flags);
+ static bool writeValueProperty(QObject *, QQmlEngine *,
+ const QQmlPropertyData &,
+ const QVariant &, QQmlContextData *,
+ WriteFlags flags = 0);
+ static bool write(QObject *, const QQmlPropertyData &, const QVariant &,
+ QQmlContextData *, WriteFlags flags = 0);
+ static void findAliasTarget(QObject *, int, QObject **, int *);
+
+ static QQmlAbstractBinding *setBinding(QObject *, int coreIndex,
+ int valueTypeIndex /* -1 */,
+ QQmlAbstractBinding *,
+ WriteFlags flags = DontRemoveBinding);
+ static QQmlAbstractBinding *setBindingNoEnable(QObject *, int coreIndex,
+ int valueTypeIndex /* -1 */,
+ QQmlAbstractBinding *);
+ static QQmlAbstractBinding *binding(QObject *, int coreIndex,
+ int valueTypeIndex /* -1 */);
+
+ static QQmlPropertyData saveValueType(const QMetaObject *, int,
+ const QMetaObject *, int,
+ QQmlEngine *);
+ static QQmlProperty restore(QObject *,
+ const QQmlPropertyData &,
+ QQmlContextData *);
+
+ static bool equal(const QMetaObject *, const QMetaObject *);
+ static bool canConvert(const QMetaObject *from, const QMetaObject *to);
+ static inline QQmlPropertyPrivate *get(const QQmlProperty &p) {
+ return p.d;
+ }
+
+ // "Public" (to QML) methods
+ static QQmlAbstractBinding *binding(const QQmlProperty &that);
+ static QQmlAbstractBinding *setBinding(const QQmlProperty &that,
+ QQmlAbstractBinding *,
+ WriteFlags flags = DontRemoveBinding);
+ static QQmlExpression *signalExpression(const QQmlProperty &that);
+ static QQmlExpression *setSignalExpression(const QQmlProperty &that,
+ QQmlExpression *) ;
+ static bool write(const QQmlProperty &that, const QVariant &, WriteFlags);
+ static bool writeBinding(const QQmlProperty &that,
+ QQmlContextData *context,
+ QQmlJavaScriptExpression *expression,
+ v8::Handle<v8::Value> result, bool isUndefined,
+ WriteFlags flags);
+ static bool writeBinding(QObject *, const QQmlPropertyData &,
+ QQmlContextData *context,
+ QQmlJavaScriptExpression *expression,
+ v8::Handle<v8::Value> result, bool isUndefined,
+ WriteFlags flags);
+ static int valueTypeCoreIndex(const QQmlProperty &that);
+ static int bindingIndex(const QQmlProperty &that);
+ static int bindingIndex(const QQmlPropertyData &that);
+ static QMetaMethod findSignalByName(const QMetaObject *mo, const QByteArray &);
+ static bool connect(const QObject *sender, int signal_index,
+ const QObject *receiver, int method_index,
+ int type = 0, int *types = 0);
+ static const QMetaObject *metaObjectForProperty(const QMetaObject *, int);
+ static void flushSignal(const QObject *sender, int signal_index);
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QQmlPropertyPrivate::WriteFlags)
+
+QT_END_NAMESPACE
+
+#endif // QQMLPROPERTY_P_H
diff --git a/src/qml/qml/qqmlpropertycache.cpp b/src/qml/qml/qqmlpropertycache.cpp
new file mode 100644
index 0000000000..9b132a4647
--- /dev/null
+++ b/src/qml/qml/qqmlpropertycache.cpp
@@ -0,0 +1,889 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qqmlpropertycache_p.h"
+
+#include "qqmlengine_p.h"
+#include "qqmlbinding_p.h"
+#include <private/qv8engine_p.h>
+
+#include <private/qmetaobject_p.h>
+#include <private/qqmlaccessors_p.h>
+
+#include <QtCore/qdebug.h>
+
+Q_DECLARE_METATYPE(QJSValue)
+Q_DECLARE_METATYPE(QQmlV8Handle);
+
+QT_BEGIN_NAMESPACE
+
+#define Q_INT16_MAX 32767
+
+class QQmlPropertyCacheMethodArguments
+{
+public:
+ QQmlPropertyCacheMethodArguments *next;
+ int arguments[0];
+};
+
+// Flags that do *NOT* depend on the property's QMetaProperty::userType() and thus are quick
+// to load
+static QQmlPropertyData::Flags fastFlagsForProperty(const QMetaProperty &p)
+{
+ QQmlPropertyData::Flags flags;
+
+ if (p.isConstant())
+ flags |= QQmlPropertyData::IsConstant;
+ if (p.isWritable())
+ flags |= QQmlPropertyData::IsWritable;
+ if (p.isResettable())
+ flags |= QQmlPropertyData::IsResettable;
+ if (p.isFinal())
+ flags |= QQmlPropertyData::IsFinal;
+ if (p.isEnumType())
+ flags |= QQmlPropertyData::IsEnumType;
+
+ return flags;
+}
+
+// Flags that do depend on the property's QMetaProperty::userType() and thus are slow to
+// load
+static QQmlPropertyData::Flags flagsForPropertyType(int propType, QQmlEngine *engine)
+{
+ Q_ASSERT(propType != -1);
+
+ QQmlPropertyData::Flags flags;
+
+ if (propType == QMetaType::QObjectStar || propType == QMetaType::QWidgetStar) {
+ flags |= QQmlPropertyData::IsQObjectDerived;
+ } else if (propType == QMetaType::QVariant) {
+ flags |= QQmlPropertyData::IsQVariant;
+ } else if (propType < (int)QVariant::UserType) {
+ } else if (propType == qMetaTypeId<QQmlBinding *>()) {
+ flags |= QQmlPropertyData::IsQmlBinding;
+ } else if (propType == qMetaTypeId<QJSValue>()) {
+ flags |= QQmlPropertyData::IsQJSValue;
+ } else if (propType == qMetaTypeId<QQmlV8Handle>()) {
+ flags |= QQmlPropertyData::IsV8Handle;
+ } else {
+ QQmlMetaType::TypeCategory cat =
+ engine ? QQmlEnginePrivate::get(engine)->typeCategory(propType)
+ : QQmlMetaType::typeCategory(propType);
+
+ if (cat == QQmlMetaType::Object)
+ flags |= QQmlPropertyData::IsQObjectDerived;
+ else if (cat == QQmlMetaType::List)
+ flags |= QQmlPropertyData::IsQList;
+ }
+
+ return flags;
+}
+
+static int metaObjectSignalCount(const QMetaObject *metaObject)
+{
+ int signalCount = 0;
+ for (const QMetaObject *obj = metaObject; obj; obj = obj->superClass())
+ signalCount += QMetaObjectPrivate::get(obj)->signalCount;
+ return signalCount;
+}
+
+QQmlPropertyData::Flags
+QQmlPropertyData::flagsForProperty(const QMetaProperty &p, QQmlEngine *engine)
+{
+ return fastFlagsForProperty(p) | flagsForPropertyType(p.userType(), engine);
+}
+
+void QQmlPropertyData::lazyLoad(const QMetaProperty &p, QQmlEngine *engine)
+{
+ Q_UNUSED(engine);
+
+ coreIndex = p.propertyIndex();
+ notifyIndex = p.notifySignalIndex();
+ Q_ASSERT(p.revision() <= Q_INT16_MAX);
+ revision = p.revision();
+
+ flags = fastFlagsForProperty(p);
+
+ int type = p.type();
+ if (type == QMetaType::QObjectStar || type == QMetaType::QWidgetStar) {
+ propType = type;
+ flags |= QQmlPropertyData::IsQObjectDerived;
+ } else if (type == QMetaType::QVariant) {
+ propType = type;
+ flags |= QQmlPropertyData::IsQVariant;
+ } else if (type == QVariant::UserType || type == -1) {
+ propTypeName = p.typeName();
+ flags |= QQmlPropertyData::NotFullyResolved;
+ } else {
+ propType = type;
+ }
+}
+
+void QQmlPropertyData::load(const QMetaProperty &p, QQmlEngine *engine)
+{
+ propType = p.userType();
+ coreIndex = p.propertyIndex();
+ notifyIndex = p.notifySignalIndex();
+ flags = fastFlagsForProperty(p) | flagsForPropertyType(propType, engine);
+ Q_ASSERT(p.revision() <= Q_INT16_MAX);
+ revision = p.revision();
+}
+
+void QQmlPropertyData::load(const QMetaMethod &m)
+{
+ coreIndex = m.methodIndex();
+ arguments = 0;
+ flags |= IsFunction;
+ if (m.methodType() == QMetaMethod::Signal)
+ flags |= IsSignal;
+ propType = QVariant::Invalid;
+
+ const char *returnType = m.typeName();
+ if (returnType)
+ propType = QMetaType::type(returnType);
+
+ const char *signature = m.signature();
+ while (*signature != '(') { Q_ASSERT(*signature != 0); ++signature; }
+
+ ++signature;
+ if (*signature != ')') {
+ flags |= HasArguments;
+ if (0 == ::strcmp(signature, "QQmlV8Function*)")) {
+ flags |= IsV8Function;
+ }
+ }
+
+ Q_ASSERT(m.revision() <= Q_INT16_MAX);
+ revision = m.revision();
+}
+
+void QQmlPropertyData::lazyLoad(const QMetaMethod &m)
+{
+ coreIndex = m.methodIndex();
+ arguments = 0;
+ flags |= IsFunction;
+ if (m.methodType() == QMetaMethod::Signal)
+ flags |= IsSignal;
+ propType = QVariant::Invalid;
+
+ const char *returnType = m.typeName();
+ if (returnType && *returnType) {
+ propTypeName = returnType;
+ flags |= NotFullyResolved;
+ }
+
+ const char *signature = m.signature();
+ while (*signature != '(') { Q_ASSERT(*signature != 0); ++signature; }
+
+ ++signature;
+ if (*signature != ')') {
+ flags |= HasArguments;
+ if (0 == ::strcmp(signature, "QQmlV8Function*)")) {
+ flags |= IsV8Function;
+ }
+ }
+
+ Q_ASSERT(m.revision() <= Q_INT16_MAX);
+ revision = m.revision();
+}
+
+/*!
+Creates a new empty QQmlPropertyCache.
+*/
+QQmlPropertyCache::QQmlPropertyCache(QQmlEngine *e)
+: engine(e), parent(0), propertyIndexCacheStart(0), methodIndexCacheStart(0),
+ signalHanderIndexCacheStart(0), metaObject(0), argumentsCache(0)
+{
+ Q_ASSERT(engine);
+}
+
+/*!
+Creates a new QQmlPropertyCache of \a metaObject.
+*/
+QQmlPropertyCache::QQmlPropertyCache(QQmlEngine *e, const QMetaObject *metaObject)
+: engine(e), parent(0), propertyIndexCacheStart(0), methodIndexCacheStart(0),
+ signalHanderIndexCacheStart(0), metaObject(0), argumentsCache(0)
+{
+ Q_ASSERT(engine);
+ Q_ASSERT(metaObject);
+
+ update(engine, metaObject);
+}
+
+QQmlPropertyCache::~QQmlPropertyCache()
+{
+ clear();
+
+ QQmlPropertyCacheMethodArguments *args = argumentsCache;
+ while (args) {
+ QQmlPropertyCacheMethodArguments *next = args->next;
+ free(args);
+ args = next;
+ }
+
+ // We must clear this prior to releasing the parent incase it is a
+ // linked hash
+ stringCache.clear();
+ if (parent) parent->release();
+ parent = 0;
+ engine = 0;
+}
+
+void QQmlPropertyCache::destroy()
+{
+ Q_ASSERT(engine || constructor.IsEmpty());
+ if (constructor.IsEmpty())
+ delete this;
+ else
+ QQmlEnginePrivate::deleteInEngineThread(engine, this);
+}
+
+// This is inherited from QQmlCleanup, so it should only clear the things
+// that are tied to the specific QQmlEngine.
+void QQmlPropertyCache::clear()
+{
+ qPersistentDispose(constructor);
+ engine = 0;
+}
+
+QQmlPropertyCache *QQmlPropertyCache::copy(int reserve)
+{
+ QQmlPropertyCache *cache = new QQmlPropertyCache(engine);
+ cache->parent = this;
+ cache->parent->addref();
+ cache->propertyIndexCacheStart = propertyIndexCache.count() + propertyIndexCacheStart;
+ cache->methodIndexCacheStart = methodIndexCache.count() + methodIndexCacheStart;
+ cache->signalHanderIndexCacheStart = signalHandlerIndexCache.count() + signalHanderIndexCacheStart;
+ cache->stringCache.linkAndReserve(stringCache, reserve);
+ cache->allowedRevisionCache = allowedRevisionCache;
+ cache->metaObject = metaObject;
+
+ // We specifically do *NOT* copy the constructor
+
+ return cache;
+}
+
+QQmlPropertyCache *QQmlPropertyCache::copy()
+{
+ return copy(0);
+}
+
+QQmlPropertyCache *
+QQmlPropertyCache::copyAndAppend(QQmlEngine *engine, const QMetaObject *metaObject,
+ QQmlPropertyData::Flag propertyFlags,
+ QQmlPropertyData::Flag methodFlags,
+ QQmlPropertyData::Flag signalFlags)
+{
+ return copyAndAppend(engine, metaObject, -1, propertyFlags, methodFlags, signalFlags);
+}
+
+QQmlPropertyCache *
+QQmlPropertyCache::copyAndAppend(QQmlEngine *engine, const QMetaObject *metaObject,
+ int revision,
+ QQmlPropertyData::Flag propertyFlags,
+ QQmlPropertyData::Flag methodFlags,
+ QQmlPropertyData::Flag signalFlags)
+{
+ Q_ASSERT(QMetaObjectPrivate::get(metaObject)->revision >= 4);
+
+ // Reserve enough space in the name hash for all the methods (including signals), all the
+ // signal handlers and all the properties. This assumes no name clashes, but this is the
+ // common case.
+ QQmlPropertyCache *rv = copy(QMetaObjectPrivate::get(metaObject)->methodCount +
+ QMetaObjectPrivate::get(metaObject)->signalCount +
+ QMetaObjectPrivate::get(metaObject)->propertyCount);
+
+ rv->append(engine, metaObject, revision, propertyFlags, methodFlags, signalFlags);
+
+ return rv;
+}
+
+void QQmlPropertyCache::append(QQmlEngine *engine, const QMetaObject *metaObject,
+ QQmlPropertyData::Flag propertyFlags,
+ QQmlPropertyData::Flag methodFlags,
+ QQmlPropertyData::Flag signalFlags)
+{
+ append(engine, metaObject, -1, propertyFlags, methodFlags, signalFlags);
+}
+
+void QQmlPropertyCache::append(QQmlEngine *engine, const QMetaObject *metaObject,
+ int revision,
+ QQmlPropertyData::Flag propertyFlags,
+ QQmlPropertyData::Flag methodFlags,
+ QQmlPropertyData::Flag signalFlags)
+{
+ Q_UNUSED(revision);
+ Q_ASSERT(constructor.IsEmpty()); // We should not be appending to an in-use property cache
+
+ this->metaObject = metaObject;
+
+ bool dynamicMetaObject = isDynamicMetaObject(metaObject);
+
+ allowedRevisionCache.append(0);
+
+ int methodCount = metaObject->methodCount();
+ Q_ASSERT(QMetaObjectPrivate::get(metaObject)->revision >= 4);
+ int signalCount = metaObjectSignalCount(metaObject);
+ int classInfoCount = QMetaObjectPrivate::get(metaObject)->classInfoCount;
+
+ QQmlAccessorProperties::Properties accessorProperties;
+
+ // Special case QObject as we don't want to add a qt_HasQmlAccessors classinfo to it
+ if (metaObject == &QObject::staticMetaObject) {
+ accessorProperties = QQmlAccessorProperties::properties(metaObject);
+ } else if (classInfoCount) {
+ int classInfoOffset = metaObject->classInfoOffset();
+ bool hasFastProperty = false;
+ for (int ii = 0; ii < classInfoCount; ++ii) {
+ int idx = ii + classInfoOffset;
+
+ if (0 == qstrcmp(metaObject->classInfo(idx).name(), "qt_HasQmlAccessors")) {
+ hasFastProperty = true;
+ break;
+ }
+ }
+
+ if (hasFastProperty) {
+ accessorProperties = QQmlAccessorProperties::properties(metaObject);
+ if (accessorProperties.count == 0)
+ qFatal("QQmlPropertyCache: %s has FastProperty class info, but has not "
+ "installed property accessors", metaObject->className());
+ } else {
+#ifndef QT_NO_DEBUG
+ accessorProperties = QQmlAccessorProperties::properties(metaObject);
+ if (accessorProperties.count != 0)
+ qFatal("QQmlPropertyCache: %s has fast property accessors, but is missing "
+ "FastProperty class info", metaObject->className());
+#endif
+ }
+ }
+
+ // qMax(defaultMethods, methodOffset) to block the signals and slots of QObject::staticMetaObject
+ // incl. destroyed signals, objectNameChanged signal, deleteLater slot, _q_reregisterTimers slot.
+ int methodOffset = qMax(QObject::staticMetaObject.methodCount(), metaObject->methodOffset());
+ int signalOffset = signalCount - QMetaObjectPrivate::get(metaObject)->signalCount;
+
+ // update() should have reserved enough space in the vector that this doesn't cause a realloc
+ // and invalidate the stringCache.
+ methodIndexCache.resize(methodCount - methodIndexCacheStart);
+ signalHandlerIndexCache.resize(signalCount - signalHanderIndexCacheStart);
+ int signalHandlerIndex = signalOffset;
+ for (int ii = methodOffset; ii < methodCount; ++ii) {
+ QMetaMethod m = metaObject->method(ii);
+ if (m.access() == QMetaMethod::Private)
+ continue;
+
+ // Extract method name
+ const char *signature = m.signature();
+ const char *cptr = signature;
+ char utf8 = 0;
+ while (*cptr != '(') {
+ Q_ASSERT(*cptr != 0);
+ utf8 |= *cptr & 0x80;
+ ++cptr;
+ }
+
+ QQmlPropertyData *data = &methodIndexCache[ii - methodIndexCacheStart];
+ QQmlPropertyData *sigdata = 0;
+
+ data->lazyLoad(m);
+
+ if (data->isSignal())
+ data->flags |= signalFlags;
+ else
+ data->flags |= methodFlags;
+
+ if (!dynamicMetaObject)
+ data->flags |= QQmlPropertyData::IsDirect;
+
+ Q_ASSERT((allowedRevisionCache.count() - 1) < Q_INT16_MAX);
+ data->metaObjectOffset = allowedRevisionCache.count() - 1;
+
+ if (data->isSignal()) {
+ sigdata = &signalHandlerIndexCache[signalHandlerIndex - signalHanderIndexCacheStart];
+ *sigdata = *data;
+ sigdata->flags |= QQmlPropertyData::IsSignalHandler;
+ }
+
+ QQmlPropertyData *old = 0;
+
+ if (utf8) {
+ QHashedString methodName(QString::fromUtf8(signature, cptr - signature));
+ if (QQmlPropertyData **it = stringCache.value(methodName))
+ old = *it;
+ stringCache.insert(methodName, data);
+
+ if (data->isSignal()) {
+ QHashedString on(QStringLiteral("on") % methodName.at(0).toUpper() % methodName.midRef(1));
+ stringCache.insert(on, sigdata);
+ ++signalHandlerIndex;
+ }
+ } else {
+ QHashedCStringRef methodName(signature, cptr - signature);
+ if (QQmlPropertyData **it = stringCache.value(methodName))
+ old = *it;
+ stringCache.insert(methodName, data);
+
+ if (data->isSignal()) {
+ int length = methodName.length();
+
+ QVarLengthArray<char, 128> str(length+3);
+ str[0] = 'o';
+ str[1] = 'n';
+ str[2] = toupper(signature[0]);
+ if (length > 1)
+ memcpy(&str[3], &signature[1], length - 1);
+ str[length + 2] = '\0';
+
+ QHashedString on(QString::fromLatin1(str.data()));
+ stringCache.insert(on, sigdata);
+ ++signalHandlerIndex;
+ }
+ }
+
+ if (old) {
+ // We only overload methods in the same class, exactly like C++
+ if (old->isFunction() && old->coreIndex >= methodOffset)
+ data->flags |= QQmlPropertyData::IsOverload;
+ data->overrideIndexIsProperty = !old->isFunction();
+ data->overrideIndex = old->coreIndex;
+ }
+ }
+
+ int propCount = metaObject->propertyCount();
+ int propOffset = metaObject->propertyOffset();
+
+ // update() should have reserved enough space in the vector that this doesn't cause a realloc
+ // and invalidate the stringCache.
+ propertyIndexCache.resize(propCount - propertyIndexCacheStart);
+ for (int ii = propOffset; ii < propCount; ++ii) {
+ QMetaProperty p = metaObject->property(ii);
+ if (!p.isScriptable())
+ continue;
+
+ const char *str = p.name();
+ char utf8 = 0;
+ const char *cptr = str;
+ while (*cptr != 0) {
+ utf8 |= *cptr & 0x80;
+ ++cptr;
+ }
+
+ QQmlPropertyData *data = &propertyIndexCache[ii - propertyIndexCacheStart];
+
+ data->lazyLoad(p, engine);
+ data->flags |= propertyFlags;
+
+ if (!dynamicMetaObject)
+ data->flags |= QQmlPropertyData::IsDirect;
+
+ Q_ASSERT((allowedRevisionCache.count() - 1) < Q_INT16_MAX);
+ data->metaObjectOffset = allowedRevisionCache.count() - 1;
+
+ QQmlPropertyData *old = 0;
+
+ if (utf8) {
+ QHashedString propName(QString::fromUtf8(str, cptr - str));
+ if (QQmlPropertyData **it = stringCache.value(propName))
+ old = *it;
+ stringCache.insert(propName, data);
+ } else {
+ QHashedCStringRef propName(str, cptr - str);
+ if (QQmlPropertyData **it = stringCache.value(propName))
+ old = *it;
+ stringCache.insert(propName, data);
+ }
+
+ QQmlAccessorProperties::Property *accessorProperty = accessorProperties.property(str);
+
+ // Fast properties may not be overrides or revisioned
+ Q_ASSERT(accessorProperty == 0 || (old == 0 && data->revision == 0));
+
+ if (accessorProperty) {
+ data->flags |= QQmlPropertyData::HasAccessors;
+ data->accessors = accessorProperty->accessors;
+ data->accessorData = accessorProperty->data;
+ } else if (old) {
+ data->overrideIndexIsProperty = !old->isFunction();
+ data->overrideIndex = old->coreIndex;
+ }
+ }
+}
+
+void QQmlPropertyCache::resolve(QQmlPropertyData *data) const
+{
+ Q_ASSERT(data->notFullyResolved());
+
+ data->propType = QMetaType::type(data->propTypeName);
+
+ if (!data->isFunction())
+ data->flags |= flagsForPropertyType(data->propType, engine);
+
+ data->flags &= ~QQmlPropertyData::NotFullyResolved;
+}
+
+void QQmlPropertyCache::updateRecur(QQmlEngine *engine, const QMetaObject *metaObject)
+{
+ if (!metaObject)
+ return;
+
+ updateRecur(engine, metaObject->superClass());
+
+ append(engine, metaObject);
+}
+
+void QQmlPropertyCache::update(QQmlEngine *engine, const QMetaObject *metaObject)
+{
+ Q_ASSERT(engine);
+ Q_ASSERT(metaObject);
+ Q_ASSERT(stringCache.isEmpty());
+
+ // Preallocate enough space in the index caches for all the properties/methods/signals that
+ // are not cached in a parent cache so that the caches never need to be reallocated as this
+ // would invalidate pointers stored in the stringCache.
+ int pc = metaObject->propertyCount();
+ int mc = metaObject->methodCount();
+ int sc = metaObjectSignalCount(metaObject);
+ propertyIndexCache.reserve(pc - propertyIndexCacheStart);
+ methodIndexCache.reserve(mc - methodIndexCacheStart);
+ signalHandlerIndexCache.reserve(sc - signalHanderIndexCacheStart);
+
+ // Reserve enough space in the stringCache for all properties/methods/signals including those
+ // cached in a parent cache.
+ stringCache.reserve(pc + mc + sc);
+
+ updateRecur(engine,metaObject);
+}
+
+QQmlPropertyData *
+QQmlPropertyCache::property(int index) const
+{
+ if (index < 0 || index >= (propertyIndexCacheStart + propertyIndexCache.count()))
+ return 0;
+
+ if (index < propertyIndexCacheStart)
+ return parent->property(index);
+
+ QQmlPropertyData *rv = const_cast<QQmlPropertyData *>(&propertyIndexCache.at(index - propertyIndexCacheStart));
+ if (rv->notFullyResolved()) resolve(rv);
+ return rv;
+}
+
+QQmlPropertyData *
+QQmlPropertyCache::method(int index) const
+{
+ if (index < 0 || index >= (methodIndexCacheStart + methodIndexCache.count()))
+ return 0;
+
+ if (index < methodIndexCacheStart)
+ return parent->method(index);
+
+ QQmlPropertyData *rv = const_cast<QQmlPropertyData *>(&methodIndexCache.at(index - methodIndexCacheStart));
+ if (rv->notFullyResolved()) resolve(rv);
+ return rv;
+}
+
+QQmlPropertyData *
+QQmlPropertyCache::property(const QHashedStringRef &str) const
+{
+ QQmlPropertyData **rv = stringCache.value(str);
+ if (rv && (*rv)->notFullyResolved()) resolve(*rv);
+ return rv?*rv:0;
+}
+
+QQmlPropertyData *
+QQmlPropertyCache::property(const QHashedCStringRef &str) const
+{
+ QQmlPropertyData **rv = stringCache.value(str);
+ if (rv && (*rv)->notFullyResolved()) resolve(*rv);
+ return rv?*rv:0;
+}
+
+QQmlPropertyData *
+QQmlPropertyCache::property(const QString &str) const
+{
+ QQmlPropertyData **rv = stringCache.value(str);
+ if (rv && (*rv)->notFullyResolved()) resolve(*rv);
+ return rv?*rv:0;
+}
+
+QString QQmlPropertyData::name(QObject *object)
+{
+ if (!object)
+ return QString();
+
+ return name(object->metaObject());
+}
+
+QString QQmlPropertyData::name(const QMetaObject *metaObject)
+{
+ if (!metaObject || coreIndex == -1)
+ return QString();
+
+ if (flags & IsFunction) {
+ QMetaMethod m = metaObject->method(coreIndex);
+
+ QString name = QString::fromUtf8(m.signature());
+ int parenIdx = name.indexOf(QLatin1Char('('));
+ if (parenIdx != -1)
+ name = name.left(parenIdx);
+ return name;
+ } else {
+ QMetaProperty p = metaObject->property(coreIndex);
+ return QString::fromUtf8(p.name());
+ }
+}
+
+QStringList QQmlPropertyCache::propertyNames() const
+{
+ QStringList keys;
+ for (StringCache::ConstIterator iter = stringCache.begin(); iter != stringCache.end(); ++iter)
+ keys.append(iter.key());
+ return keys;
+}
+
+static int EnumType(const QMetaObject *meta, const QByteArray &str)
+{
+ QByteArray scope;
+ QByteArray name;
+ int scopeIdx = str.lastIndexOf("::");
+ if (scopeIdx != -1) {
+ scope = str.left(scopeIdx);
+ name = str.mid(scopeIdx + 2);
+ } else {
+ name = str;
+ }
+ for (int i = meta->enumeratorCount() - 1; i >= 0; --i) {
+ QMetaEnum m = meta->enumerator(i);
+ if ((m.name() == name) && (scope.isEmpty() || (m.scope() == scope)))
+ return QVariant::Int;
+ }
+ return QVariant::Invalid;
+}
+
+// Returns an array of the arguments for method \a index. The first entry in the array
+// is the number of arguments.
+int *QQmlPropertyCache::methodParameterTypes(QObject *object, int index,
+ QVarLengthArray<int, 9> &dummy,
+ QByteArray *unknownTypeError)
+{
+ Q_ASSERT(object && index >= 0);
+
+ QQmlData *ddata = QQmlData::get(object, false);
+
+ if (ddata && ddata->propertyCache) {
+ typedef QQmlPropertyCacheMethodArguments A;
+
+ QQmlPropertyCache *c = ddata->propertyCache;
+ Q_ASSERT(index < c->methodIndexCacheStart + c->methodIndexCache.count());
+
+ while (index < c->methodIndexCacheStart)
+ c = c->parent;
+
+ QQmlPropertyData *rv = const_cast<QQmlPropertyData *>(&c->methodIndexCache.at(index - c->methodIndexCacheStart));
+
+ if (rv->arguments)
+ return static_cast<A *>(rv->arguments)->arguments;
+
+ const QMetaObject *metaObject = object->metaObject();
+ QMetaMethod m = metaObject->method(index);
+ QList<QByteArray> argTypeNames = m.parameterTypes();
+
+ A *args = static_cast<A *>(malloc(sizeof(A) + (argTypeNames.count() + 1) * sizeof(int)));
+ args->arguments[0] = argTypeNames.count();
+
+ for (int ii = 0; ii < argTypeNames.count(); ++ii) {
+ int type = QMetaType::type(argTypeNames.at(ii));
+ if (type == QVariant::Invalid)
+ type = EnumType(object->metaObject(), argTypeNames.at(ii));
+ if (type == QVariant::Invalid) {
+ if (unknownTypeError) *unknownTypeError = argTypeNames.at(ii);
+ free(args);
+ return 0;
+ }
+ args->arguments[ii + 1] = type;
+ }
+
+ rv->arguments = args;
+ args->next = c->argumentsCache;
+ c->argumentsCache = args;
+ return static_cast<A *>(rv->arguments)->arguments;
+
+ } else {
+ QMetaMethod m = object->metaObject()->method(index);
+ QList<QByteArray> argTypeNames = m.parameterTypes();
+ dummy.resize(argTypeNames.count() + 1);
+ dummy[0] = argTypeNames.count();
+
+ for (int ii = 0; ii < argTypeNames.count(); ++ii) {
+ int type = QMetaType::type(argTypeNames.at(ii));
+ if (type == QVariant::Invalid)
+ type = EnumType(object->metaObject(), argTypeNames.at(ii));
+ if (type == QVariant::Invalid) {
+ if (unknownTypeError) *unknownTypeError = argTypeNames.at(ii);
+ return 0;
+ }
+ dummy[ii + 1] = type;
+ }
+
+ return dummy.data();
+ }
+}
+
+QQmlPropertyData qQmlPropertyCacheCreate(const QMetaObject *metaObject,
+ const QString &property)
+{
+ Q_ASSERT(metaObject);
+
+ QQmlPropertyData rv;
+ {
+ const QMetaObject *cmo = metaObject;
+ const QByteArray propertyName = property.toUtf8();
+ while (cmo) {
+ int idx = cmo->indexOfProperty(propertyName);
+ if (idx != -1) {
+ QMetaProperty p = cmo->property(idx);
+ if (p.isScriptable()) {
+ rv.load(p);
+ return rv;
+ } else {
+ while (cmo && cmo->propertyOffset() >= idx)
+ cmo = cmo->superClass();
+ }
+ } else {
+ cmo = 0;
+ }
+ }
+ }
+
+ int methodCount = metaObject->methodCount();
+ int defaultMethods = QObject::staticMetaObject.methodCount();
+ for (int ii = methodCount - 1; ii >= defaultMethods; --ii) {
+ // >=defaultMethods to block the signals and slots of QObject::staticMetaObject
+ // incl. destroyed signals, objectNameChanged signal, deleteLater slot, _q_reregisterTimers slot.
+ QMetaMethod m = metaObject->method(ii);
+ if (m.access() == QMetaMethod::Private)
+ continue;
+ QString methodName = QString::fromUtf8(m.signature());
+
+ int parenIdx = methodName.indexOf(QLatin1Char('('));
+ Q_ASSERT(parenIdx != -1);
+ QStringRef methodNameRef = methodName.leftRef(parenIdx);
+
+ if (methodNameRef == property) {
+ rv.load(m);
+ return rv;
+ }
+ }
+
+ return rv;
+}
+
+inline const QString &qQmlPropertyCacheToString(const QString &string)
+{
+ return string;
+}
+
+inline QString qQmlPropertyCacheToString(const QHashedV8String &string)
+{
+ return QV8Engine::toStringStatic(string.string());
+}
+
+template<typename T>
+QQmlPropertyData *
+qQmlPropertyCacheProperty(QQmlEngine *engine, QObject *obj,
+ const T &name, QQmlPropertyData &local)
+{
+ QQmlPropertyCache *cache = 0;
+
+ if (engine) {
+ QQmlData *ddata = QQmlData::get(obj);
+
+ if (ddata && ddata->propertyCache) {
+ cache = ddata->propertyCache;
+ } else if (engine) {
+ QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine);
+ cache = ep->cache(obj);
+ if (cache) {
+ ddata = QQmlData::get(obj, true);
+ cache->addref();
+ ddata->propertyCache = cache;
+ }
+ }
+ }
+
+ QQmlPropertyData *rv = 0;
+
+ if (cache) {
+ rv = cache->property(name);
+ } else {
+ local = qQmlPropertyCacheCreate(obj->metaObject(),
+ qQmlPropertyCacheToString(name));
+ if (local.isValid())
+ rv = &local;
+ }
+
+ return rv;
+}
+
+QQmlPropertyData *
+QQmlPropertyCache::property(QQmlEngine *engine, QObject *obj,
+ const QHashedV8String &name, QQmlPropertyData &local)
+{
+ return qQmlPropertyCacheProperty<QHashedV8String>(engine, obj, name, local);
+}
+
+QQmlPropertyData *
+QQmlPropertyCache::property(QQmlEngine *engine, QObject *obj,
+ const QString &name, QQmlPropertyData &local)
+{
+ return qQmlPropertyCacheProperty<QString>(engine, obj, name, local);
+}
+
+static inline const QMetaObjectPrivate *priv(const uint* data)
+{ return reinterpret_cast<const QMetaObjectPrivate*>(data); }
+
+bool QQmlPropertyCache::isDynamicMetaObject(const QMetaObject *mo)
+{
+ return priv(mo->d.data)->revision >= 3 && priv(mo->d.data)->flags & DynamicMetaObject;
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlpropertycache_p.h b/src/qml/qml/qqmlpropertycache_p.h
new file mode 100644
index 0000000000..095ee79867
--- /dev/null
+++ b/src/qml/qml/qqmlpropertycache_p.h
@@ -0,0 +1,383 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLPROPERTYCACHE_P_H
+#define QQMLPROPERTYCACHE_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qqmlrefcount_p.h>
+#include "qqmlcleanup_p.h"
+#include "qqmlnotifier_p.h"
+
+#include <private/qhashedstring_p.h>
+#include <QtCore/qvarlengtharray.h>
+#include <QtCore/qvector.h>
+
+QT_BEGIN_NAMESPACE
+
+class QV8Engine;
+class QMetaProperty;
+class QV8QObjectWrapper;
+class QQmlEngine;
+class QQmlPropertyData;
+class QQmlAccessors;
+class QQmlPropertyCacheMethodArguments;
+
+// We have this somewhat awful split between RawData and Data so that RawData can be
+// used in unions. In normal code, you should always use Data which initializes RawData
+// to an invalid state on construction.
+class QQmlPropertyRawData
+{
+public:
+ enum Flag {
+ NoFlags = 0x00000000,
+ ValueTypeFlagMask = 0x0000FFFF, // Flags in valueTypeFlags must fit in this mask
+
+ // Can apply to all properties, except IsFunction
+ IsConstant = 0x00000001, // Has CONST flag
+ IsWritable = 0x00000002, // Has WRITE function
+ IsResettable = 0x00000004, // Has RESET function
+ IsAlias = 0x00000008, // Is a QML alias to another property
+ IsFinal = 0x00000010, // Has FINAL flag
+ IsDirect = 0x00000020, // Exists on a C++ QMetaObject
+ HasAccessors = 0x00000040, // Has property accessors
+
+ // These are mutualy exclusive
+ IsFunction = 0x00000080, // Is an invokable
+ IsQObjectDerived = 0x00000100, // Property type is a QObject* derived type
+ IsEnumType = 0x00000200, // Property type is an enum
+ IsQList = 0x00000400, // Property type is a QML list
+ IsQmlBinding = 0x00000800, // Property type is a QQmlBinding*
+ IsQJSValue = 0x00001000, // Property type is a QScriptValue
+ IsV8Handle = 0x00002000, // Property type is a QQmlV8Handle
+ IsVMEProperty = 0x00004000, // Property type is a "var" property of VMEMO
+ IsValueTypeVirtual = 0x00008000, // Property is a value type "virtual" property
+ IsQVariant = 0x00010000, // Property is a QVariant
+
+ // Apply only to IsFunctions
+ IsVMEFunction = 0x00020000, // Function was added by QML
+ HasArguments = 0x00040000, // Function takes arguments
+ IsSignal = 0x00080000, // Function is a signal
+ IsVMESignal = 0x00100000, // Signal was added by QML
+ IsV8Function = 0x00200000, // Function takes QQmlV8Function* args
+ IsSignalHandler = 0x00400000, // Function is a signal handler
+ IsOverload = 0x00800000, // Function is an overload of another function
+
+ // Internal QQmlPropertyCache flags
+ NotFullyResolved = 0x01000000 // True if the type data is to be lazily resolved
+ };
+ Q_DECLARE_FLAGS(Flags, Flag)
+
+ Flags getFlags() const { return Flag(flags); }
+ void setFlags(Flags f) { flags = f; }
+
+ bool isValid() const { return coreIndex != -1; }
+
+ bool isConstant() const { return flags & IsConstant; }
+ bool isWritable() const { return flags & IsWritable; }
+ bool isResettable() const { return flags & IsResettable; }
+ bool isAlias() const { return flags & IsAlias; }
+ bool isFinal() const { return flags & IsFinal; }
+ bool isDirect() const { return flags & IsDirect; }
+ bool hasAccessors() const { return flags & HasAccessors; }
+ bool isFunction() const { return flags & IsFunction; }
+ bool isQObject() const { return flags & IsQObjectDerived; }
+ bool isEnum() const { return flags & IsEnumType; }
+ bool isQList() const { return flags & IsQList; }
+ bool isQmlBinding() const { return flags & IsQmlBinding; }
+ bool isQJSValue() const { return flags & IsQJSValue; }
+ bool isV8Handle() const { return flags & IsV8Handle; }
+ bool isVMEProperty() const { return flags & IsVMEProperty; }
+ bool isValueTypeVirtual() const { return flags & IsValueTypeVirtual; }
+ bool isQVariant() const { return flags & IsQVariant; }
+ bool isVMEFunction() const { return flags & IsVMEFunction; }
+ bool hasArguments() const { return flags & HasArguments; }
+ bool isSignal() const { return flags & IsSignal; }
+ bool isVMESignal() const { return flags & IsVMESignal; }
+ bool isV8Function() const { return flags & IsV8Function; }
+ bool isSignalHandler() const { return flags & IsSignalHandler; }
+ bool isOverload() const { return flags & IsOverload; }
+
+ bool hasOverride() const { return !(flags & IsValueTypeVirtual) &&
+ !(flags & HasAccessors) &&
+ overrideIndex >= 0; }
+
+ // Returns -1 if not a value type virtual property
+ inline int getValueTypeCoreIndex() const;
+
+ // Returns the "encoded" index for use with bindings. Encoding is:
+ // coreIndex | (valueTypeCoreIndex << 24)
+ inline int encodedIndex() const;
+
+ union {
+ int propType; // When !NotFullyResolved
+ const char *propTypeName; // When NotFullyResolved
+ };
+ int coreIndex;
+ union {
+ int notifyIndex; // When !IsFunction
+ void *arguments; // When IsFunction && HasArguments
+ };
+
+ union {
+ struct { // When !HasAccessors
+ qint16 revision;
+ qint16 metaObjectOffset;
+
+ union {
+ struct { // When IsValueTypeVirtual
+ quint16 valueTypeFlags; // flags of the access property on the value type proxy
+ // object
+ quint8 valueTypePropType; // The QVariant::Type of access property on the value
+ // type proxy object
+ quint8 valueTypeCoreIndex; // The prop index of the access property on the value
+ // type proxy object
+ };
+
+ struct { // When !IsValueTypeVirtual
+ uint overrideIndexIsProperty : 1;
+ signed int overrideIndex : 31;
+ };
+ };
+ };
+ struct { // When HasAccessors
+ QQmlAccessors *accessors;
+ intptr_t accessorData;
+ };
+ };
+
+private:
+ friend class QQmlPropertyData;
+ friend class QQmlPropertyCache;
+ quint32 flags;
+};
+Q_DECLARE_OPERATORS_FOR_FLAGS(QQmlPropertyRawData::Flags);
+
+class QQmlPropertyData : public QQmlPropertyRawData
+{
+public:
+ inline QQmlPropertyData();
+ inline QQmlPropertyData(const QQmlPropertyRawData &);
+
+ inline bool operator==(const QQmlPropertyRawData &);
+
+ static Flags flagsForProperty(const QMetaProperty &, QQmlEngine *engine = 0);
+ void load(const QMetaProperty &, QQmlEngine *engine = 0);
+ void load(const QMetaMethod &);
+ QString name(QObject *);
+ QString name(const QMetaObject *);
+
+private:
+ friend class QQmlPropertyCache;
+ void lazyLoad(const QMetaProperty &, QQmlEngine *engine = 0);
+ void lazyLoad(const QMetaMethod &);
+ bool notFullyResolved() const { return flags & NotFullyResolved; }
+};
+
+class Q_QML_EXPORT QQmlPropertyCache : public QQmlRefCount, public QQmlCleanup
+{
+public:
+ QQmlPropertyCache(QQmlEngine *);
+ QQmlPropertyCache(QQmlEngine *, const QMetaObject *);
+ virtual ~QQmlPropertyCache();
+
+ void update(QQmlEngine *, const QMetaObject *);
+
+ QQmlPropertyCache *copy();
+
+ QQmlPropertyCache *copyAndAppend(QQmlEngine *, const QMetaObject *,
+ QQmlPropertyData::Flag propertyFlags = QQmlPropertyData::NoFlags,
+ QQmlPropertyData::Flag methodFlags = QQmlPropertyData::NoFlags,
+ QQmlPropertyData::Flag signalFlags = QQmlPropertyData::NoFlags);
+ QQmlPropertyCache *copyAndAppend(QQmlEngine *, const QMetaObject *, int revision,
+ QQmlPropertyData::Flag propertyFlags = QQmlPropertyData::NoFlags,
+ QQmlPropertyData::Flag methodFlags = QQmlPropertyData::NoFlags,
+ QQmlPropertyData::Flag signalFlags = QQmlPropertyData::NoFlags);
+
+ void append(QQmlEngine *, const QMetaObject *,
+ QQmlPropertyData::Flag propertyFlags = QQmlPropertyData::NoFlags,
+ QQmlPropertyData::Flag methodFlags = QQmlPropertyData::NoFlags,
+ QQmlPropertyData::Flag signalFlags = QQmlPropertyData::NoFlags);
+ void append(QQmlEngine *, const QMetaObject *, int revision,
+ QQmlPropertyData::Flag propertyFlags = QQmlPropertyData::NoFlags,
+ QQmlPropertyData::Flag methodFlags = QQmlPropertyData::NoFlags,
+ QQmlPropertyData::Flag signalFlags = QQmlPropertyData::NoFlags);
+
+ inline QQmlPropertyData *property(const QHashedV8String &) const;
+ QQmlPropertyData *property(const QHashedStringRef &) const;
+ QQmlPropertyData *property(const QHashedCStringRef &) const;
+ QQmlPropertyData *property(const QString &) const;
+ QQmlPropertyData *property(int) const;
+ QQmlPropertyData *method(int) const;
+ QStringList propertyNames() const;
+
+ inline QQmlPropertyData *overrideData(QQmlPropertyData *) const;
+ inline bool isAllowedInRevision(QQmlPropertyData *) const;
+
+ inline QQmlEngine *qmlEngine() const;
+ static QQmlPropertyData *property(QQmlEngine *, QObject *, const QString &,
+ QQmlPropertyData &);
+ static QQmlPropertyData *property(QQmlEngine *, QObject *, const QHashedV8String &,
+ QQmlPropertyData &);
+ static int *methodParameterTypes(QObject *, int index, QVarLengthArray<int, 9> &dummy,
+ QByteArray *unknownTypeError);
+
+ static bool isDynamicMetaObject(const QMetaObject *);
+protected:
+ virtual void destroy();
+ virtual void clear();
+
+private:
+ friend class QQmlEnginePrivate;
+ friend class QV8QObjectWrapper;
+
+ inline QQmlPropertyCache *copy(int reserve);
+
+ // Implemented in v8/qv8qobjectwrapper.cpp
+ v8::Local<v8::Object> newQObject(QObject *, QV8Engine *);
+
+ typedef QVector<QQmlPropertyData> IndexCache;
+ typedef QStringHash<QQmlPropertyData *> StringCache;
+ typedef QVector<int> AllowedRevisionCache;
+
+ void resolve(QQmlPropertyData *) const;
+ void updateRecur(QQmlEngine *, const QMetaObject *);
+
+ QQmlEngine *engine;
+
+ QQmlPropertyCache *parent;
+ int propertyIndexCacheStart;
+ int methodIndexCacheStart;
+ int signalHanderIndexCacheStart;
+
+ IndexCache propertyIndexCache;
+ IndexCache methodIndexCache;
+ IndexCache signalHandlerIndexCache;
+ StringCache stringCache;
+ AllowedRevisionCache allowedRevisionCache;
+ v8::Persistent<v8::Function> constructor;
+
+ const QMetaObject *metaObject;
+ QQmlPropertyCacheMethodArguments *argumentsCache;
+};
+
+QQmlPropertyData::QQmlPropertyData()
+{
+ propType = 0;
+ coreIndex = -1;
+ notifyIndex = -1;
+ overrideIndexIsProperty = false;
+ overrideIndex = -1;
+ revision = 0;
+ metaObjectOffset = -1;
+ flags = 0;
+}
+
+QQmlPropertyData::QQmlPropertyData(const QQmlPropertyRawData &d)
+{
+ *(static_cast<QQmlPropertyRawData *>(this)) = d;
+}
+
+bool QQmlPropertyData::operator==(const QQmlPropertyRawData &other)
+{
+ return flags == other.flags &&
+ propType == other.propType &&
+ coreIndex == other.coreIndex &&
+ notifyIndex == other.notifyIndex &&
+ revision == other.revision &&
+ (!isValueTypeVirtual() ||
+ (valueTypeCoreIndex == other.valueTypeCoreIndex &&
+ valueTypePropType == other.valueTypePropType));
+}
+
+int QQmlPropertyRawData::getValueTypeCoreIndex() const
+{
+ return isValueTypeVirtual()?valueTypeCoreIndex:-1;
+}
+
+int QQmlPropertyRawData::encodedIndex() const
+{
+ return isValueTypeVirtual()?(coreIndex | (valueTypeCoreIndex << 24)):coreIndex;
+}
+
+QQmlPropertyData *
+QQmlPropertyCache::overrideData(QQmlPropertyData *data) const
+{
+ if (!data->hasOverride())
+ return 0;
+
+ if (data->overrideIndexIsProperty)
+ return property(data->overrideIndex);
+ else
+ return method(data->overrideIndex);
+}
+
+bool QQmlPropertyCache::isAllowedInRevision(QQmlPropertyData *data) const
+{
+ return (data->hasAccessors() || (data->metaObjectOffset == -1 && data->revision == 0)) ||
+ (allowedRevisionCache[data->metaObjectOffset] >= data->revision);
+}
+
+QQmlEngine *QQmlPropertyCache::qmlEngine() const
+{
+ return engine;
+}
+
+QQmlPropertyData *QQmlPropertyCache::property(const QHashedV8String &str) const
+{
+ QQmlPropertyData **rv = stringCache.value(str);
+ if (rv && (*rv)->notFullyResolved()) resolve(*rv);
+ return rv?*rv:0;
+}
+
+QT_END_NAMESPACE
+
+#endif // QQMLPROPERTYCACHE_P_H
diff --git a/src/qml/qml/qqmlpropertyvalueinterceptor.cpp b/src/qml/qml/qqmlpropertyvalueinterceptor.cpp
new file mode 100644
index 0000000000..331b90da5c
--- /dev/null
+++ b/src/qml/qml/qqmlpropertyvalueinterceptor.cpp
@@ -0,0 +1,79 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qqmlpropertyvalueinterceptor_p.h"
+
+#include "qqml.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QQmlPropertyValueInterceptor
+ \brief The QQmlPropertyValueInterceptor class is inherited by property interceptors such as Behavior.
+ \internal
+
+ This class intercepts property writes, allowing for custom handling. For example, Behavior uses this
+ interception to provide a default animation for all changes to a property's value.
+ */
+
+/*!
+ Constructs a QQmlPropertyValueInterceptor.
+*/
+QQmlPropertyValueInterceptor::QQmlPropertyValueInterceptor()
+{
+}
+
+QQmlPropertyValueInterceptor::~QQmlPropertyValueInterceptor()
+{
+}
+
+/*!
+ \fn void QQmlPropertyValueInterceptor::setTarget(const QQmlProperty &property)
+ Set the target \a property for the value interceptor. This method will
+ be called by the QML engine when assigning a value interceptor.
+*/
+
+/*!
+ \fn void QQmlPropertyValueInterceptor::write(const QVariant &value)
+ This method will be called when a new \a value is assigned to the property being intercepted.
+*/
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlpropertyvalueinterceptor_p.h b/src/qml/qml/qqmlpropertyvalueinterceptor_p.h
new file mode 100644
index 0000000000..f8b8643a00
--- /dev/null
+++ b/src/qml/qml/qqmlpropertyvalueinterceptor_p.h
@@ -0,0 +1,74 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLPROPERTYVALUEINTERCEPTOR_P_H
+#define QQMLPROPERTYVALUEINTERCEPTOR_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtQml/qtqmlglobal.h>
+#include <QtCore/qobject.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQmlProperty;
+class Q_QML_EXPORT QQmlPropertyValueInterceptor
+{
+public:
+ QQmlPropertyValueInterceptor();
+ virtual ~QQmlPropertyValueInterceptor();
+ virtual void setTarget(const QQmlProperty &property) = 0;
+ virtual void write(const QVariant &value) = 0;
+};
+Q_DECLARE_INTERFACE(QQmlPropertyValueInterceptor, "com.trolltech.qml.QQmlPropertyValueInterceptor")
+
+QT_END_NAMESPACE
+
+#endif // QQMLPROPERTYVALUEINTERCEPTOR_P_H
diff --git a/src/qml/qml/qqmlpropertyvaluesource.cpp b/src/qml/qml/qqmlpropertyvaluesource.cpp
new file mode 100644
index 0000000000..bd1ca05b81
--- /dev/null
+++ b/src/qml/qml/qqmlpropertyvaluesource.cpp
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qqmlpropertyvaluesource.h"
+
+#include "qqml.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QQmlPropertyValueSource
+ \brief The QQmlPropertyValueSource class is an interface for property value sources such as animations and bindings.
+
+ See \l{Property Value Sources} for information on writing custom property
+ value sources.
+ */
+
+/*!
+ Constructs a QQmlPropertyValueSource.
+*/
+QQmlPropertyValueSource::QQmlPropertyValueSource()
+{
+}
+
+/*!
+ Destroys the value source.
+*/
+QQmlPropertyValueSource::~QQmlPropertyValueSource()
+{
+}
+
+/*!
+ \fn void QQmlPropertyValueSource::setTarget(const QQmlProperty &property)
+ Set the target \a property for the value source. This method will
+ be called by the QML engine when assigning a value source.
+*/
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlpropertyvaluesource.h b/src/qml/qml/qqmlpropertyvaluesource.h
new file mode 100644
index 0000000000..910b23877e
--- /dev/null
+++ b/src/qml/qml/qqmlpropertyvaluesource.h
@@ -0,0 +1,67 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLPROPERTYVALUESOURCE_H
+#define QQMLPROPERTYVALUESOURCE_H
+
+#include <QtQml/qtqmlglobal.h>
+#include <QtCore/qobject.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+
+class QQmlProperty;
+class Q_QML_EXPORT QQmlPropertyValueSource
+{
+public:
+ QQmlPropertyValueSource();
+ virtual ~QQmlPropertyValueSource();
+ virtual void setTarget(const QQmlProperty &) = 0;
+};
+Q_DECLARE_INTERFACE(QQmlPropertyValueSource, "com.trolltech.qml.QQmlPropertyValueSource")
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QQMLPROPERTYVALUESOURCE_H
diff --git a/src/qml/qml/qqmlproxymetaobject.cpp b/src/qml/qml/qqmlproxymetaobject.cpp
new file mode 100644
index 0000000000..55bf67739d
--- /dev/null
+++ b/src/qml/qml/qqmlproxymetaobject.cpp
@@ -0,0 +1,124 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qqmlproxymetaobject_p.h"
+#include "qqmlproperty_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QQmlProxyMetaObject::QQmlProxyMetaObject(QObject *obj, QList<ProxyData> *mList)
+: metaObjects(mList), proxies(0), parent(0), object(obj)
+{
+ *static_cast<QMetaObject *>(this) = *metaObjects->first().metaObject;
+
+ QObjectPrivate *op = QObjectPrivate::get(obj);
+ if (op->metaObject)
+ parent = static_cast<QAbstractDynamicMetaObject*>(op->metaObject);
+
+ op->metaObject = this;
+}
+
+QQmlProxyMetaObject::~QQmlProxyMetaObject()
+{
+ if (parent)
+ delete parent;
+ parent = 0;
+
+ if (proxies)
+ delete [] proxies;
+ proxies = 0;
+}
+
+int QQmlProxyMetaObject::metaCall(QMetaObject::Call c, int id, void **a)
+{
+ if ((c == QMetaObject::ReadProperty ||
+ c == QMetaObject::WriteProperty) &&
+ id >= metaObjects->last().propertyOffset) {
+
+ for (int ii = 0; ii < metaObjects->count(); ++ii) {
+ const ProxyData &data = metaObjects->at(ii);
+ if (id >= data.propertyOffset) {
+ if (!proxies) {
+ proxies = new QObject*[metaObjects->count()];
+ ::memset(proxies, 0,
+ sizeof(QObject *) * metaObjects->count());
+ }
+
+ if (!proxies[ii]) {
+ QObject *proxy = data.createFunc(object);
+ const QMetaObject *metaObject = proxy->metaObject();
+ proxies[ii] = proxy;
+
+ int localOffset = data.metaObject->methodOffset();
+ int methodOffset = metaObject->methodOffset();
+ int methods = metaObject->methodCount() - methodOffset;
+
+ // ### - Can this be done more optimally?
+ for (int jj = 0; jj < methods; ++jj) {
+ QMetaMethod method =
+ metaObject->method(jj + methodOffset);
+ if (method.methodType() == QMetaMethod::Signal)
+ QQmlPropertyPrivate::connect(proxy, methodOffset + jj, object, localOffset + jj);
+ }
+ }
+
+ int proxyOffset = proxies[ii]->metaObject()->propertyOffset();
+ int proxyId = id - data.propertyOffset + proxyOffset;
+
+ return proxies[ii]->qt_metacall(c, proxyId, a);
+ }
+ }
+ } else if (c == QMetaObject::InvokeMetaMethod &&
+ id >= metaObjects->last().methodOffset) {
+ QMetaMethod m = object->metaObject()->method(id);
+ if (m.methodType() == QMetaMethod::Signal) {
+ QMetaObject::activate(object, id, a);
+ return -1;
+ }
+ }
+
+ if (parent)
+ return parent->metaCall(c, id, a);
+ else
+ return object->qt_metacall(c, id, a);
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlproxymetaobject_p.h b/src/qml/qml/qqmlproxymetaobject_p.h
new file mode 100644
index 0000000000..ec9df42f7f
--- /dev/null
+++ b/src/qml/qml/qqmlproxymetaobject_p.h
@@ -0,0 +1,99 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLPROXYMETAOBJECT_P_H
+#define QQMLPROXYMETAOBJECT_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qmetaobjectbuilder_p.h>
+#include "qqml.h"
+
+#include <QtCore/QMetaObject>
+#include <QtCore/QObject>
+
+#include <private/qobject_p.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+
+class QQmlProxyMetaObject : public QAbstractDynamicMetaObject
+{
+public:
+ struct ProxyData {
+ typedef QObject *(*CreateFunc)(QObject *);
+ QMetaObject *metaObject;
+ CreateFunc createFunc;
+ int propertyOffset;
+ int methodOffset;
+ };
+
+ QQmlProxyMetaObject(QObject *, QList<ProxyData> *);
+ virtual ~QQmlProxyMetaObject();
+
+protected:
+ virtual int metaCall(QMetaObject::Call _c, int _id, void **_a);
+
+private:
+ QList<ProxyData> *metaObjects;
+ QObject **proxies;
+
+ QAbstractDynamicMetaObject *parent;
+ QObject *object;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QQMLPROXYMETAOBJECT_P_H
+
diff --git a/src/qml/qml/qqmlrewrite.cpp b/src/qml/qml/qqmlrewrite.cpp
new file mode 100644
index 0000000000..828f7bf641
--- /dev/null
+++ b/src/qml/qml/qqmlrewrite.cpp
@@ -0,0 +1,441 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qqmlrewrite_p.h"
+
+#include <private/qqmlglobal_p.h>
+
+#include <QtCore/qdebug.h>
+
+QT_BEGIN_NAMESPACE
+
+DEFINE_BOOL_CONFIG_OPTION(rewriteDump, QML_REWRITE_DUMP);
+
+namespace QQmlRewrite {
+
+bool SharedBindingTester::isSharable(const QString &code)
+{
+ Engine engine;
+ Lexer lexer(&engine);
+ Parser parser(&engine);
+ lexer.setCode(code, 0);
+ parser.parseStatement();
+ if (!parser.statement())
+ return false;
+
+ return isSharable(parser.statement());
+}
+
+bool SharedBindingTester::isSharable(AST::Node *node)
+{
+ _sharable = true;
+ AST::Node::acceptChild(node, this);
+ return _sharable;
+}
+
+QString RewriteBinding::operator()(const QString &code, bool *ok, bool *sharable)
+{
+ Engine engine;
+ Lexer lexer(&engine);
+ Parser parser(&engine);
+ lexer.setCode(code, 0);
+ parser.parseStatement();
+ if (!parser.statement()) {
+ if (ok) *ok = false;
+ return QString();
+ } else {
+ if (ok) *ok = true;
+ if (sharable) {
+ SharedBindingTester tester;
+ *sharable = tester.isSharable(parser.statement());
+ }
+ }
+ return rewrite(code, 0, parser.statement());
+}
+
+QString RewriteBinding::operator()(QQmlJS::AST::Node *node, const QString &code, bool *sharable)
+{
+ if (!node)
+ return code;
+
+ if (sharable) {
+ SharedBindingTester tester;
+ *sharable = tester.isSharable(node);
+ }
+
+ QQmlJS::AST::ExpressionNode *expression = node->expressionCast();
+ QQmlJS::AST::Statement *statement = node->statementCast();
+ if(!expression && !statement)
+ return code;
+
+ TextWriter w;
+ _writer = &w;
+ _position = expression ? expression->firstSourceLocation().begin() : statement->firstSourceLocation().begin();
+ _inLoop = 0;
+ _code = &code;
+
+ accept(node);
+
+ unsigned startOfStatement = 0;
+ unsigned endOfStatement = (expression ? expression->lastSourceLocation().end() : statement->lastSourceLocation().end()) - _position;
+
+ QString startString = QLatin1String("(function ") + _name + QLatin1String("() { ");
+ if (expression)
+ startString += QLatin1String("return ");
+ _writer->replace(startOfStatement, 0, startString);
+ _writer->replace(endOfStatement, 0, QLatin1String(" })"));
+
+ if (rewriteDump()) {
+ qWarning() << "=============================================================";
+ qWarning() << "Rewrote:";
+ qWarning() << qPrintable(code);
+ }
+
+ QString codeCopy = code;
+ w.write(&codeCopy);
+
+ if (rewriteDump()) {
+ qWarning() << "To:";
+ qWarning() << qPrintable(codeCopy);
+ qWarning() << "=============================================================";
+ }
+
+ return codeCopy;
+}
+
+void RewriteBinding::accept(AST::Node *node)
+{
+ AST::Node::acceptChild(node, this);
+}
+
+QString RewriteBinding::rewrite(QString code, unsigned position,
+ AST::Statement *node)
+{
+ TextWriter w;
+ _writer = &w;
+ _position = position;
+ _inLoop = 0;
+ _code = &code;
+
+ accept(node);
+
+ unsigned startOfStatement = node->firstSourceLocation().begin() - _position;
+ unsigned endOfStatement = node->lastSourceLocation().end() - _position;
+
+ _writer->replace(startOfStatement, 0, QLatin1String("(function ") + _name + QLatin1String("() { "));
+ _writer->replace(endOfStatement, 0, QLatin1String(" })"));
+
+ if (rewriteDump()) {
+ qWarning() << "=============================================================";
+ qWarning() << "Rewrote:";
+ qWarning() << qPrintable(code);
+ }
+
+ w.write(&code);
+
+ if (rewriteDump()) {
+ qWarning() << "To:";
+ qWarning() << qPrintable(code);
+ qWarning() << "=============================================================";
+ }
+
+ return code;
+}
+
+bool RewriteBinding::visit(AST::Block *ast)
+{
+ for (AST::StatementList *it = ast->statements; it; it = it->next) {
+ if (! it->next) {
+ // we need to rewrite only the last statement of a block.
+ accept(it->statement);
+ }
+ }
+
+ return false;
+}
+
+bool RewriteBinding::visit(AST::ExpressionStatement *ast)
+{
+ if (! _inLoop) {
+ unsigned startOfExpressionStatement = ast->firstSourceLocation().begin() - _position;
+ _writer->replace(startOfExpressionStatement, 0, QLatin1String("return "));
+ }
+
+ return false;
+}
+
+bool RewriteBinding::visit(AST::StringLiteral *ast)
+{
+ /* When rewriting the code for bindings, we have to remove ILLEGAL JS tokens like newlines.
+ They're still in multi-line strings, because the QML parser allows them, but we have to
+ rewrite them to be JS compliant.
+
+ For performance reasons, we don't go for total correctness. \r is only replaced if a
+ \n was found (since most line endings are \n or \r\n) and QChar::LineSeparator is not
+ even considered. QTBUG-24064.
+
+ Note that rewriteSignalHandler has a function just like this one, for the same reason.
+ */
+
+ unsigned startOfString = ast->firstSourceLocation().begin() + 1 - _position;
+ unsigned stringLength = ast->firstSourceLocation().length - 2;
+
+ int lastIndex = -1;
+ bool foundNewLine = false;
+ QStringRef subStr(_code, startOfString, stringLength);
+ while (true) {
+ lastIndex = subStr.indexOf(QLatin1Char('\n'), lastIndex + 1);
+ if (lastIndex == -1)
+ break;
+ foundNewLine = true;
+ _writer->replace(startOfString+lastIndex, 1, QLatin1String("\\n"));
+ }
+
+ if (foundNewLine) {
+ while (true) {
+ lastIndex = subStr.indexOf(QLatin1Char('\r'), lastIndex + 1);
+ if (lastIndex == -1)
+ break;
+ _writer->replace(startOfString+lastIndex, 1, QLatin1String("\\r"));
+ }
+ }
+
+ return false;
+}
+
+bool RewriteBinding::visit(AST::DoWhileStatement *)
+{
+ ++_inLoop;
+ return true;
+}
+
+void RewriteBinding::endVisit(AST::DoWhileStatement *)
+{
+ --_inLoop;
+}
+
+bool RewriteBinding::visit(AST::WhileStatement *)
+{
+ ++_inLoop;
+ return true;
+}
+
+void RewriteBinding::endVisit(AST::WhileStatement *)
+{
+ --_inLoop;
+}
+
+bool RewriteBinding::visit(AST::ForStatement *)
+{
+ ++_inLoop;
+ return true;
+}
+
+void RewriteBinding::endVisit(AST::ForStatement *)
+{
+ --_inLoop;
+}
+
+bool RewriteBinding::visit(AST::LocalForStatement *)
+{
+ ++_inLoop;
+ return true;
+}
+
+void RewriteBinding::endVisit(AST::LocalForStatement *)
+{
+ --_inLoop;
+}
+
+bool RewriteBinding::visit(AST::ForEachStatement *)
+{
+ ++_inLoop;
+ return true;
+}
+
+void RewriteBinding::endVisit(AST::ForEachStatement *)
+{
+ --_inLoop;
+}
+
+bool RewriteBinding::visit(AST::LocalForEachStatement *)
+{
+ ++_inLoop;
+ return true;
+}
+
+void RewriteBinding::endVisit(AST::LocalForEachStatement *)
+{
+ --_inLoop;
+}
+
+bool RewriteBinding::visit(AST::CaseBlock *ast)
+{
+ // Process the initial sequence of the case clauses.
+ for (AST::CaseClauses *it = ast->clauses; it; it = it->next) {
+ // Return the value of the last statement in the block, if this is the last `case clause'
+ // of the switch statement.
+ bool returnTheValueOfLastStatement = (it->next == 0) && (ast->defaultClause == 0) && (ast->moreClauses == 0);
+
+ if (AST::CaseClause *clause = it->clause) {
+ accept(clause->expression);
+ rewriteCaseStatements(clause->statements, returnTheValueOfLastStatement);
+ }
+ }
+
+ // Process the default case clause
+ if (ast->defaultClause) {
+ // Return the value of the last statement in the block, if this is the last `case clause'
+ // of the switch statement.
+ bool rewriteTheLastStatement = (ast->moreClauses == 0);
+
+ rewriteCaseStatements(ast->defaultClause->statements, rewriteTheLastStatement);
+ }
+
+ // Process trailing `case clauses'
+ for (AST::CaseClauses *it = ast->moreClauses; it; it = it->next) {
+ // Return the value of the last statement in the block, if this is the last `case clause'
+ // of the switch statement.
+ bool returnTheValueOfLastStatement = (it->next == 0);
+
+ if (AST::CaseClause *clause = it->clause) {
+ accept(clause->expression);
+ rewriteCaseStatements(clause->statements, returnTheValueOfLastStatement);
+ }
+ }
+
+ return false;
+}
+
+void RewriteBinding::rewriteCaseStatements(AST::StatementList *statements, bool rewriteTheLastStatement)
+{
+ for (AST::StatementList *it = statements; it; it = it->next) {
+ if (it->next && AST::cast<AST::BreakStatement *>(it->next->statement) != 0) {
+ // The value of the first statement followed by a `break'.
+ accept(it->statement);
+ break;
+ } else if (!it->next) {
+ if (rewriteTheLastStatement)
+ accept(it->statement);
+ else if (AST::Block *block = AST::cast<AST::Block *>(it->statement))
+ rewriteCaseStatements(block->statements, rewriteTheLastStatement);
+ }
+ }
+}
+
+void RewriteSignalHandler::accept(AST::Node *node)
+{
+ AST::Node::acceptChild(node, this);
+}
+
+bool RewriteSignalHandler::visit(AST::StringLiteral *ast)
+{
+ unsigned startOfExpressionStatement = ast->firstSourceLocation().begin() - _position;
+ _strStarts << startOfExpressionStatement + 1;
+ _strLens << ast->firstSourceLocation().length - 2;
+
+ return false;
+}
+
+void RewriteSignalHandler::rewriteMultilineStrings(QString &code)
+{
+ QList<int> replaceR, replaceN;
+ for (int i=0; i < _strStarts.count(); i++) {
+ QStringRef curSubstr = QStringRef(&code, _strStarts[i], _strLens[i]);
+ int lastIndex = -1;
+ while (true) {
+ lastIndex = curSubstr.indexOf(QLatin1Char('\n'), lastIndex + 1);
+ if (lastIndex == -1)
+ break;
+ replaceN << _strStarts[i]+lastIndex;
+ }
+
+ if (replaceN.count()) {
+ while (true) {
+ lastIndex = curSubstr.indexOf(QLatin1Char('\r'), lastIndex + 1);
+ if (lastIndex == -1)
+ break;
+ replaceR << _strStarts[i]+lastIndex;
+ }
+ }
+ }
+ for (int ii = replaceN.count() - 1; ii >= 0; ii--)
+ code.replace(replaceN[ii], 1, QLatin1String("\\n"));
+ if (replaceR.count())
+ for (int ii = replaceR.count() - 1; ii >= 0; ii--)
+ code.replace(replaceR[ii], 1, QLatin1String("\\r"));
+}
+
+QString RewriteSignalHandler::operator()(QQmlJS::AST::Node *node, const QString &code, const QString &name)
+{
+ if (rewriteDump()) {
+ qWarning() << "=============================================================";
+ qWarning() << "Rewrote:";
+ qWarning() << qPrintable(code);
+ }
+
+ QQmlJS::AST::ExpressionNode *expression = node->expressionCast();
+ QQmlJS::AST::Statement *statement = node->statementCast();
+ if (!expression && !statement)
+ return code;
+
+ _strStarts.clear();
+ _strLens.clear();
+ _position = expression ? expression->firstSourceLocation().begin() : statement->firstSourceLocation().begin();
+ accept(node);
+
+ QString rewritten = code;
+ rewriteMultilineStrings(rewritten);
+
+ rewritten = QStringLiteral("(function ") + name + QStringLiteral("() { ") + rewritten + QStringLiteral(" })");
+
+ if (rewriteDump()) {
+ qWarning() << "To:";
+ qWarning() << qPrintable(rewritten);
+ qWarning() << "=============================================================";
+ }
+
+ return rewritten;
+}
+
+} // namespace QQmlRewrite
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlrewrite_p.h b/src/qml/qml/qqmlrewrite_p.h
new file mode 100644
index 0000000000..e915d797df
--- /dev/null
+++ b/src/qml/qml/qqmlrewrite_p.h
@@ -0,0 +1,149 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLREWRITE_P_H
+#define QQMLREWRITE_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/textwriter_p.h>
+#include <private/qqmljslexer_p.h>
+#include <private/qqmljsparser_p.h>
+#include <private/qqmljsmemorypool_p.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace QQmlRewrite {
+using namespace QQmlJS;
+
+class SharedBindingTester : protected AST::Visitor
+{
+ bool _sharable;
+public:
+ bool isSharable(const QString &code);
+ bool isSharable(AST::Node *Node);
+
+ virtual bool visit(AST::FunctionDeclaration *) { _sharable = false; return false; }
+ virtual bool visit(AST::FunctionExpression *) { _sharable = false; return false; }
+ virtual bool visit(AST::CallExpression *) { _sharable = false; return false; }
+};
+
+class RewriteBinding: protected AST::Visitor
+{
+ unsigned _position;
+ TextWriter *_writer;
+ QString _name;
+ const QString *_code;
+
+public:
+ QString operator()(const QString &code, bool *ok = 0, bool *sharable = 0);
+ QString operator()(QQmlJS::AST::Node *node, const QString &code, bool *sharable = 0);
+
+ //name of the function: used for the debugger
+ void setName(const QString &name) { _name = name; }
+
+protected:
+ using AST::Visitor::visit;
+
+ void accept(AST::Node *node);
+ QString rewrite(QString code, unsigned position, AST::Statement *node);
+ void rewriteCaseStatements(AST::StatementList *statements, bool rewriteTheLastStatement);
+
+ virtual bool visit(AST::StringLiteral *ast);
+ virtual bool visit(AST::Block *ast);
+ virtual bool visit(AST::ExpressionStatement *ast);
+
+ virtual bool visit(AST::DoWhileStatement *ast);
+ virtual void endVisit(AST::DoWhileStatement *ast);
+
+ virtual bool visit(AST::WhileStatement *ast);
+ virtual void endVisit(AST::WhileStatement *ast);
+
+ virtual bool visit(AST::ForStatement *ast);
+ virtual void endVisit(AST::ForStatement *ast);
+
+ virtual bool visit(AST::LocalForStatement *ast);
+ virtual void endVisit(AST::LocalForStatement *ast);
+
+ virtual bool visit(AST::ForEachStatement *ast);
+ virtual void endVisit(AST::ForEachStatement *ast);
+
+ virtual bool visit(AST::LocalForEachStatement *ast);
+ virtual void endVisit(AST::LocalForEachStatement *ast);
+
+ virtual bool visit(AST::CaseBlock *ast);
+
+private:
+ int _inLoop;
+};
+
+class RewriteSignalHandler: protected AST::Visitor
+{
+ QList<int> _strStarts;
+ QList<int> _strLens;
+ int _position;
+
+public:
+ QString operator()(QQmlJS::AST::Node *node, const QString &code, const QString &name);
+
+protected:
+ void rewriteMultilineStrings(QString &code);
+
+ using AST::Visitor::visit;
+ void accept(AST::Node *node);
+ virtual bool visit(AST::StringLiteral *ast);
+};
+
+} // namespace QQmlRewrite
+
+QT_END_NAMESPACE
+
+#endif // QQMLREWRITE_P_H
+
diff --git a/src/qml/qml/qqmlscript.cpp b/src/qml/qml/qqmlscript.cpp
new file mode 100644
index 0000000000..d1c2faa138
--- /dev/null
+++ b/src/qml/qml/qqmlscript.cpp
@@ -0,0 +1,1700 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qqmlscript_p.h"
+
+#include "parser/qqmljsengine_p.h"
+#include "parser/qqmljsparser_p.h"
+#include "parser/qqmljslexer_p.h"
+#include "parser/qqmljsmemorypool_p.h"
+#include "parser/qqmljsastvisitor_p.h"
+#include "parser/qqmljsast_p.h"
+#include <private/qqmlrewrite_p.h>
+
+#include <QStack>
+#include <QCoreApplication>
+#include <QtDebug>
+
+QT_BEGIN_NAMESPACE
+
+using namespace QQmlJS;
+using namespace QQmlScript;
+
+//
+// Parser IR classes
+//
+QQmlScript::Object::Object()
+: type(-1), idIndex(-1), metatype(0), synthCache(0), defaultProperty(0), parserStatusCast(-1),
+ componentCompileState(0), nextAliasingObject(0), nextIdObject(0)
+{
+}
+
+QQmlScript::Object::~Object()
+{
+ if (synthCache) synthCache->release();
+}
+
+void Object::setBindingBit(int b)
+{
+ while (bindingBitmask.size() < 4 * (1 + b / 32))
+ bindingBitmask.append(char(0));
+
+ quint32 *bits = (quint32 *)bindingBitmask.data();
+ bits[b / 32] |= (1 << (b % 32));
+}
+
+const QMetaObject *Object::metaObject() const
+{
+ if (!metadata.isEmpty() && metatype)
+ return &extObject;
+ else
+ return metatype;
+}
+
+QQmlScript::Property *Object::getDefaultProperty()
+{
+ if (!defaultProperty) {
+ defaultProperty = pool()->New<Property>();
+ defaultProperty->parent = this;
+ }
+ return defaultProperty;
+}
+
+void QQmlScript::Object::addValueProperty(Property *p)
+{
+ valueProperties.append(p);
+}
+
+void QQmlScript::Object::addSignalProperty(Property *p)
+{
+ signalProperties.append(p);
+}
+
+void QQmlScript::Object::addAttachedProperty(Property *p)
+{
+ attachedProperties.append(p);
+}
+
+void QQmlScript::Object::addGroupedProperty(Property *p)
+{
+ groupedProperties.append(p);
+}
+
+void QQmlScript::Object::addValueTypeProperty(Property *p)
+{
+ valueTypeProperties.append(p);
+}
+
+void QQmlScript::Object::addScriptStringProperty(Property *p)
+{
+ scriptStringProperties.append(p);
+}
+
+// This lookup is optimized for missing, and having to create a new property.
+Property *QQmlScript::Object::getProperty(const QHashedStringRef &name, bool create)
+{
+ if (create) {
+ quint32 h = name.hash();
+ if (propertiesHashField.testAndSet(h)) {
+ for (Property *p = properties.first(); p; p = properties.next(p)) {
+ if (p->name() == name)
+ return p;
+ }
+ }
+
+ Property *property = pool()->New<Property>();
+ property->parent = this;
+ property->_name = name;
+ property->isDefault = false;
+ properties.prepend(property);
+ return property;
+ } else {
+ for (Property *p = properties.first(); p; p = properties.next(p)) {
+ if (p->name() == name)
+ return p;
+ }
+ }
+
+ return 0;
+}
+
+Property *QQmlScript::Object::getProperty(const QStringRef &name, bool create)
+{
+ return getProperty(QHashedStringRef(name), create);
+}
+
+Property *QQmlScript::Object::getProperty(const QString &name, bool create)
+{
+ for (Property *p = properties.first(); p; p = properties.next(p)) {
+ if (p->name() == name)
+ return p;
+ }
+
+ if (create) {
+ Property *property = pool()->New<Property>();
+ property->parent = this;
+ property->_name = QStringRef(pool()->NewString(name));
+ propertiesHashField.testAndSet(property->_name.hash());
+ property->isDefault = false;
+ properties.prepend(property);
+ return property;
+ } else {
+ return 0;
+ }
+}
+
+QQmlScript::Object::DynamicProperty::DynamicProperty()
+: isDefaultProperty(false), isReadOnly(false), type(Variant), defaultValue(0), nextProperty(0),
+ resolvedCustomTypeName(0)
+{
+}
+
+QQmlScript::Object::DynamicSignal::DynamicSignal()
+: nextSignal(0)
+{
+}
+
+// Returns length in utf8 bytes
+int QQmlScript::Object::DynamicSignal::parameterTypesLength() const
+{
+ int rv = 0;
+ for (int ii = 0; ii < parameterTypes.count(); ++ii)
+ rv += parameterTypes.at(ii).length();
+ return rv;
+}
+
+// Returns length in utf8 bytes
+int QQmlScript::Object::DynamicSignal::parameterNamesLength() const
+{
+ int rv = 0;
+ for (int ii = 0; ii < parameterNames.count(); ++ii)
+ rv += parameterNames.at(ii).utf8length();
+ return rv;
+}
+
+QQmlScript::Object::DynamicSlot::DynamicSlot()
+: nextSlot(0)
+{
+}
+
+int QQmlScript::Object::DynamicSlot::parameterNamesLength() const
+{
+ int rv = 0;
+ for (int ii = 0; ii < parameterNames.count(); ++ii)
+ rv += parameterNames.at(ii).length();
+ return rv;
+}
+
+QQmlScript::Property::Property()
+: parent(0), type(0), index(-1), value(0), isDefault(true), isDeferred(false),
+ isValueTypeSubProperty(false), isAlias(false), isReadOnlyDeclaration(false),
+ scriptStringScope(-1), nextMainProperty(0), nextProperty(0)
+{
+}
+
+QQmlScript::Object *QQmlScript::Property::getValue(const LocationSpan &l)
+{
+ if (!value) { value = pool()->New<Object>(); value->location = l; }
+ return value;
+}
+
+void QQmlScript::Property::addValue(Value *v)
+{
+ values.append(v);
+}
+
+void QQmlScript::Property::addOnValue(Value *v)
+{
+ onValues.append(v);
+}
+
+bool QQmlScript::Property::isEmpty() const
+{
+ return !value && values.isEmpty() && onValues.isEmpty();
+}
+
+QQmlScript::Value::Value()
+: type(Unknown), object(0), bindingReference(0), nextValue(0)
+{
+}
+
+QQmlScript::Variant::Variant()
+: t(Invalid)
+{
+}
+
+QQmlScript::Variant::Variant(const Variant &o)
+: t(o.t), d(o.d), asWritten(o.asWritten)
+{
+}
+
+QQmlScript::Variant::Variant(bool v)
+: t(Boolean), b(v)
+{
+}
+
+QQmlScript::Variant::Variant(double v, const QStringRef &asWritten)
+: t(Number), d(v), asWritten(asWritten)
+{
+}
+
+QQmlScript::Variant::Variant(QQmlJS::AST::StringLiteral *v)
+: t(String), l(v)
+{
+}
+
+QQmlScript::Variant::Variant(const QStringRef &asWritten, QQmlJS::AST::Node *n)
+: t(Script), n(n), asWritten(asWritten)
+{
+}
+
+QQmlScript::Variant &QQmlScript::Variant::operator=(const Variant &o)
+{
+ t = o.t;
+ d = o.d;
+ asWritten = o.asWritten;
+ return *this;
+}
+
+QQmlScript::Variant::Type QQmlScript::Variant::type() const
+{
+ return t;
+}
+
+bool QQmlScript::Variant::asBoolean() const
+{
+ return b;
+}
+
+QString QQmlScript::Variant::asString() const
+{
+ if (t == String) {
+ return l->value.toString();
+ } else {
+ return asWritten.toString();
+ }
+}
+
+double QQmlScript::Variant::asNumber() const
+{
+ return d;
+}
+
+//reverse of Lexer::singleEscape()
+QString escapedString(const QString &string)
+{
+ QString tmp = QLatin1String("\"");
+ for (int i = 0; i < string.length(); ++i) {
+ const QChar &c = string.at(i);
+ switch(c.unicode()) {
+ case 0x08:
+ tmp += QLatin1String("\\b");
+ break;
+ case 0x09:
+ tmp += QLatin1String("\\t");
+ break;
+ case 0x0A:
+ tmp += QLatin1String("\\n");
+ break;
+ case 0x0B:
+ tmp += QLatin1String("\\v");
+ break;
+ case 0x0C:
+ tmp += QLatin1String("\\f");
+ break;
+ case 0x0D:
+ tmp += QLatin1String("\\r");
+ break;
+ case 0x22:
+ tmp += QLatin1String("\\\"");
+ break;
+ case 0x27:
+ tmp += QLatin1String("\\\'");
+ break;
+ case 0x5C:
+ tmp += QLatin1String("\\\\");
+ break;
+ default:
+ tmp += c;
+ break;
+ }
+ }
+ tmp += QLatin1Char('\"');
+ return tmp;
+}
+
+QString QQmlScript::Variant::asScript() const
+{
+ switch(type()) {
+ default:
+ case Invalid:
+ return QString();
+ case Boolean:
+ return b?QLatin1String("true"):QLatin1String("false");
+ case Number:
+ if (asWritten.isEmpty())
+ return QString::number(d);
+ else
+ return asWritten.toString();
+ case String:
+ return escapedString(asString());
+ case Script:
+ if (AST::IdentifierExpression *i = AST::cast<AST::IdentifierExpression *>(n)) {
+ return i->name.toString();
+ } else
+ return asWritten.toString();
+ }
+}
+
+QQmlJS::AST::Node *QQmlScript::Variant::asAST() const
+{
+ if (type() == Script)
+ return n;
+ else
+ return 0;
+}
+
+bool QQmlScript::Variant::isStringList() const
+{
+ if (isString())
+ return true;
+
+ if (type() != Script || !n)
+ return false;
+
+ AST::ArrayLiteral *array = AST::cast<AST::ArrayLiteral *>(n);
+ if (!array)
+ return false;
+
+ AST::ElementList *elements = array->elements;
+
+ while (elements) {
+
+ if (!AST::cast<AST::StringLiteral *>(elements->expression))
+ return false;
+
+ elements = elements->next;
+ }
+
+ return true;
+}
+
+QStringList QQmlScript::Variant::asStringList() const
+{
+ QStringList rv;
+ if (isString()) {
+ rv << asString();
+ return rv;
+ }
+
+ AST::ArrayLiteral *array = AST::cast<AST::ArrayLiteral *>(n);
+ if (!array)
+ return rv;
+
+ AST::ElementList *elements = array->elements;
+ while (elements) {
+
+ AST::StringLiteral *string = AST::cast<AST::StringLiteral *>(elements->expression);
+ if (!string)
+ return QStringList();
+ rv.append(string->value.toString());
+
+ elements = elements->next;
+ }
+
+ return rv;
+}
+
+//
+// Actual parser classes
+//
+void QQmlScript::Import::extractVersion(int *maj, int *min) const
+{
+ *maj = -1; *min = -1;
+
+ if (!version.isEmpty()) {
+ int dot = version.indexOf(QLatin1Char('.'));
+ if (dot < 0) {
+ *maj = version.toInt();
+ *min = 0;
+ } else {
+ *maj = version.left(dot).toInt();
+ *min = version.mid(dot+1).toInt();
+ }
+ }
+}
+
+namespace {
+
+class ProcessAST: protected AST::Visitor
+{
+ struct State {
+ State() : object(0), property(0) {}
+ State(QQmlScript::Object *o) : object(o), property(0) {}
+ State(QQmlScript::Object *o, Property *p) : object(o), property(p) {}
+
+ QQmlScript::Object *object;
+ Property *property;
+ };
+
+ struct StateStack : public QStack<State>
+ {
+ void pushObject(QQmlScript::Object *obj)
+ {
+ push(State(obj));
+ }
+
+ void pushProperty(const QString &name, const LocationSpan &location)
+ {
+ const State &state = top();
+ if (state.property) {
+ State s(state.property->getValue(location),
+ state.property->getValue(location)->getProperty(name));
+ s.property->location = location;
+ push(s);
+ } else {
+ State s(state.object, state.object->getProperty(name));
+
+ s.property->location = location;
+ push(s);
+ }
+ }
+
+ void pushProperty(const QStringRef &name, const LocationSpan &location)
+ {
+ const State &state = top();
+ if (state.property) {
+ State s(state.property->getValue(location),
+ state.property->getValue(location)->getProperty(name));
+ s.property->location = location;
+ push(s);
+ } else {
+ State s(state.object, state.object->getProperty(name));
+
+ s.property->location = location;
+ push(s);
+ }
+ }
+ };
+
+public:
+ ProcessAST(QQmlScript::Parser *parser);
+ virtual ~ProcessAST();
+
+ void operator()(const QString &code, AST::Node *node);
+
+protected:
+
+ QQmlScript::Object *defineObjectBinding(AST::UiQualifiedId *propertyName, bool onAssignment,
+ const QString &objectType,
+ AST::SourceLocation typeLocation,
+ LocationSpan location,
+ AST::UiObjectInitializer *initializer = 0);
+
+ QQmlScript::Variant getVariant(AST::Statement *stmt);
+ QQmlScript::Variant getVariant(AST::ExpressionNode *expr);
+
+ LocationSpan location(AST::SourceLocation start, AST::SourceLocation end);
+ LocationSpan location(AST::UiQualifiedId *);
+
+ using AST::Visitor::visit;
+ using AST::Visitor::endVisit;
+
+ virtual bool visit(AST::UiProgram *node);
+ virtual bool visit(AST::UiImport *node);
+ virtual bool visit(AST::UiObjectDefinition *node);
+ virtual bool visit(AST::UiPublicMember *node);
+ virtual bool visit(AST::UiObjectBinding *node);
+
+ virtual bool visit(AST::UiScriptBinding *node);
+ virtual bool visit(AST::UiArrayBinding *node);
+ virtual bool visit(AST::UiSourceElement *node);
+
+ void accept(AST::Node *node);
+
+ QString asString(AST::UiQualifiedId *node) const;
+
+ const State state() const;
+ QQmlScript::Object *currentObject() const;
+ Property *currentProperty() const;
+
+ QString qualifiedNameId() const;
+
+ QString textAt(const AST::SourceLocation &loc) const
+ { return _contents->mid(loc.offset, loc.length); }
+
+ QStringRef textRefAt(const AST::SourceLocation &loc) const
+ { return QStringRef(_contents, loc.offset, loc.length); }
+
+ QString textAt(const AST::SourceLocation &first,
+ const AST::SourceLocation &last) const
+ { return _contents->mid(first.offset, last.offset + last.length - first.offset); }
+
+ QStringRef textRefAt(const AST::SourceLocation &first,
+ const AST::SourceLocation &last) const
+ { return QStringRef(_contents, first.offset, last.offset + last.length - first.offset); }
+
+ QString asString(AST::ExpressionNode *expr)
+ {
+ if (! expr)
+ return QString();
+
+ return textAt(expr->firstSourceLocation(), expr->lastSourceLocation());
+ }
+
+ QStringRef asStringRef(AST::ExpressionNode *expr)
+ {
+ if (! expr)
+ return QStringRef();
+
+ return textRefAt(expr->firstSourceLocation(), expr->lastSourceLocation());
+ }
+
+ QString asString(AST::Statement *stmt)
+ {
+ if (! stmt)
+ return QString();
+
+ QString s = textAt(stmt->firstSourceLocation(), stmt->lastSourceLocation());
+ s += QLatin1Char('\n');
+ return s;
+ }
+
+ QStringRef asStringRef(AST::Statement *stmt)
+ {
+ if (! stmt)
+ return QStringRef();
+
+ return textRefAt(stmt->firstSourceLocation(), stmt->lastSourceLocation());
+ }
+
+private:
+ QQmlScript::Parser *_parser;
+ StateStack _stateStack;
+ QStringList _scope;
+ const QString *_contents;
+};
+
+ProcessAST::ProcessAST(QQmlScript::Parser *parser)
+ : _parser(parser)
+{
+}
+
+ProcessAST::~ProcessAST()
+{
+}
+
+void ProcessAST::operator()(const QString &code, AST::Node *node)
+{
+ _contents = &code;
+ accept(node);
+}
+
+void ProcessAST::accept(AST::Node *node)
+{
+ AST::Node::acceptChild(node, this);
+}
+
+const ProcessAST::State ProcessAST::state() const
+{
+ if (_stateStack.isEmpty())
+ return State();
+
+ return _stateStack.back();
+}
+
+QQmlScript::Object *ProcessAST::currentObject() const
+{
+ return state().object;
+}
+
+Property *ProcessAST::currentProperty() const
+{
+ return state().property;
+}
+
+QString ProcessAST::qualifiedNameId() const
+{
+ return _scope.join(QLatin1String("/"));
+}
+
+QString ProcessAST::asString(AST::UiQualifiedId *node) const
+{
+ QString s;
+
+ for (AST::UiQualifiedId *it = node; it; it = it->next) {
+ s.append(it->name.toString());
+
+ if (it->next)
+ s.append(QLatin1Char('.'));
+ }
+
+ return s;
+}
+
+QQmlScript::Object *
+ProcessAST::defineObjectBinding(AST::UiQualifiedId *propertyName,
+ bool onAssignment,
+ const QString &objectType,
+ AST::SourceLocation typeLocation,
+ LocationSpan location,
+ AST::UiObjectInitializer *initializer)
+{
+ int lastTypeDot = objectType.lastIndexOf(QLatin1Char('.'));
+
+ // With no preceding qualification, first char is at (-1 + 1) == 0
+ bool isType = !objectType.isEmpty() && objectType.at(lastTypeDot+1).isUpper();
+
+ int propertyCount = 0;
+ for (AST::UiQualifiedId *name = propertyName; name; name = name->next){
+ ++propertyCount;
+ _stateStack.pushProperty(name->name,
+ this->location(name));
+ }
+
+ if (!onAssignment && propertyCount && currentProperty() && !currentProperty()->values.isEmpty()) {
+ QQmlError error;
+ error.setDescription(QCoreApplication::translate("QQmlParser","Property value set multiple times"));
+ error.setLine(this->location(propertyName).start.line);
+ error.setColumn(this->location(propertyName).start.column);
+ _parser->_errors << error;
+ return 0;
+ }
+
+ if (!isType) {
+
+ // Is the identifier qualified by a namespace?
+ int namespaceLength = 0;
+ if (lastTypeDot > 0) {
+ const QString qualifier(objectType.left(lastTypeDot));
+
+ for (int ii = 0; ii < _parser->_imports.count(); ++ii) {
+ const QQmlScript::Import &import = _parser->_imports.at(ii);
+ if (import.qualifier == qualifier) {
+ // The qualifier is a namespace - expect a type here
+ namespaceLength = qualifier.length() + 1;
+ break;
+ }
+ }
+ }
+
+ if (propertyCount || !currentObject() || namespaceLength) {
+ QQmlError error;
+ error.setDescription(QCoreApplication::translate("QQmlParser","Expected type name"));
+ error.setLine(typeLocation.startLine);
+ error.setColumn(typeLocation.startColumn + namespaceLength);
+ _parser->_errors << error;
+ return 0;
+ }
+
+ LocationSpan loc = ProcessAST::location(typeLocation, typeLocation);
+ if (propertyName)
+ loc = ProcessAST::location(propertyName);
+
+ _stateStack.pushProperty(objectType, loc);
+ accept(initializer);
+ _stateStack.pop();
+
+ return 0;
+
+ } else {
+ // Class
+
+ QString resolvableObjectType = objectType;
+ if (lastTypeDot >= 0)
+ resolvableObjectType.replace(QLatin1Char('.'),QLatin1Char('/'));
+
+ QQmlScript::Object *obj = _parser->_pool.New<QQmlScript::Object>();
+
+ QQmlScript::TypeReference *typeRef = _parser->findOrCreateType(resolvableObjectType);
+ obj->type = typeRef->id;
+
+ typeRef->refObjects.append(obj);
+
+ // XXX this doesn't do anything (_scope never builds up)
+ _scope.append(resolvableObjectType);
+ obj->typeName = qualifiedNameId();
+ _scope.removeLast();
+
+ obj->location = location;
+
+ if (propertyCount) {
+ Property *prop = currentProperty();
+ QQmlScript::Value *v = _parser->_pool.New<QQmlScript::Value>();
+ v->object = obj;
+ v->location = obj->location;
+ if (onAssignment)
+ prop->addOnValue(v);
+ else
+ prop->addValue(v);
+
+ while (propertyCount--)
+ _stateStack.pop();
+
+ } else {
+
+ if (! _parser->tree()) {
+ _parser->setTree(obj);
+ } else {
+ const State state = _stateStack.top();
+ QQmlScript::Value *v = _parser->_pool.New<QQmlScript::Value>();
+ v->object = obj;
+ v->location = obj->location;
+ if (state.property) {
+ state.property->addValue(v);
+ } else {
+ Property *defaultProp = state.object->getDefaultProperty();
+ if (defaultProp->location.start.line == -1) {
+ defaultProp->location = v->location;
+ defaultProp->location.end = defaultProp->location.start;
+ defaultProp->location.range.length = 0;
+ }
+ defaultProp->addValue(v);
+ }
+ }
+ }
+
+ _stateStack.pushObject(obj);
+ accept(initializer);
+ _stateStack.pop();
+
+ return obj;
+ }
+}
+
+LocationSpan ProcessAST::location(AST::UiQualifiedId *id)
+{
+ return location(id->identifierToken, id->identifierToken);
+}
+
+LocationSpan ProcessAST::location(AST::SourceLocation start, AST::SourceLocation end)
+{
+ LocationSpan rv;
+ rv.start.line = start.startLine;
+ rv.start.column = start.startColumn;
+ rv.end.line = end.startLine;
+ rv.end.column = end.startColumn + end.length - 1;
+ rv.range.offset = start.offset;
+ rv.range.length = end.offset + end.length - start.offset;
+ return rv;
+}
+
+// UiProgram: UiImportListOpt UiObjectMemberList ;
+bool ProcessAST::visit(AST::UiProgram *node)
+{
+ accept(node->imports);
+ accept(node->members->member);
+ return false;
+}
+
+// UiImport: T_IMPORT T_STRING_LITERAL ;
+bool ProcessAST::visit(AST::UiImport *node)
+{
+ QString uri;
+ QQmlScript::Import import;
+
+ if (!node->fileName.isNull()) {
+ uri = node->fileName.toString();
+
+ if (uri.endsWith(QLatin1String(".js"))) {
+ import.type = QQmlScript::Import::Script;
+ } else {
+ import.type = QQmlScript::Import::File;
+ }
+ } else {
+ import.type = QQmlScript::Import::Library;
+ uri = asString(node->importUri);
+ }
+
+ AST::SourceLocation startLoc = node->importToken;
+ AST::SourceLocation endLoc = node->semicolonToken;
+
+ // Qualifier
+ if (!node->importId.isNull()) {
+ import.qualifier = node->importId.toString();
+ if (!import.qualifier.at(0).isUpper()) {
+ QQmlError error;
+ error.setDescription(QCoreApplication::translate("QQmlParser","Invalid import qualifier ID"));
+ error.setLine(node->importIdToken.startLine);
+ error.setColumn(node->importIdToken.startColumn);
+ _parser->_errors << error;
+ return false;
+ }
+ if (import.qualifier == QLatin1String("Qt")) {
+ QQmlError error;
+ error.setDescription(QCoreApplication::translate("QQmlParser","Reserved name \"Qt\" cannot be used as an qualifier"));
+ error.setLine(node->importIdToken.startLine);
+ error.setColumn(node->importIdToken.startColumn);
+ _parser->_errors << error;
+ return false;
+ }
+
+ // Check for script qualifier clashes
+ bool isScript = import.type == QQmlScript::Import::Script;
+ for (int ii = 0; ii < _parser->_imports.count(); ++ii) {
+ const QQmlScript::Import &other = _parser->_imports.at(ii);
+ bool otherIsScript = other.type == QQmlScript::Import::Script;
+
+ if ((isScript || otherIsScript) && import.qualifier == other.qualifier) {
+ QQmlError error;
+ error.setDescription(QCoreApplication::translate("QQmlParser","Script import qualifiers must be unique."));
+ error.setLine(node->importIdToken.startLine);
+ error.setColumn(node->importIdToken.startColumn);
+ _parser->_errors << error;
+ return false;
+ }
+ }
+
+ } else if (import.type == QQmlScript::Import::Script) {
+ QQmlError error;
+ error.setDescription(QCoreApplication::translate("QQmlParser","Script import requires a qualifier"));
+ error.setLine(node->fileNameToken.startLine);
+ error.setColumn(node->fileNameToken.startColumn);
+ _parser->_errors << error;
+ return false;
+ }
+
+ if (node->versionToken.isValid()) {
+ import.version = textAt(node->versionToken);
+ } else if (import.type == QQmlScript::Import::Library) {
+ QQmlError error;
+ error.setDescription(QCoreApplication::translate("QQmlParser","Library import requires a version"));
+ error.setLine(node->importIdToken.startLine);
+ error.setColumn(node->importIdToken.startColumn);
+ _parser->_errors << error;
+ return false;
+ }
+
+
+ import.location = location(startLoc, endLoc);
+ import.uri = uri;
+
+ _parser->_imports << import;
+
+ return false;
+}
+
+bool ProcessAST::visit(AST::UiPublicMember *node)
+{
+ static const struct TypeNameToType {
+ const char *name;
+ int nameLength;
+ Object::DynamicProperty::Type type;
+ const char *qtName;
+ int qtNameLength;
+ } propTypeNameToTypes[] = {
+ { "int", strlen("int"), Object::DynamicProperty::Int, "int", strlen("int") },
+ { "bool", strlen("bool"), Object::DynamicProperty::Bool, "bool", strlen("bool") },
+ { "double", strlen("double"), Object::DynamicProperty::Real, "double", strlen("double") },
+ { "real", strlen("real"), Object::DynamicProperty::Real, "qreal", strlen("qreal") },
+ { "string", strlen("string"), Object::DynamicProperty::String, "QString", strlen("QString") },
+ { "url", strlen("url"), Object::DynamicProperty::Url, "QUrl", strlen("QUrl") },
+ { "color", strlen("color"), Object::DynamicProperty::Color, "QColor", strlen("QColor") },
+ // Internally QTime, QDate and QDateTime are all supported.
+ // To be more consistent with JavaScript we expose only
+ // QDateTime as it matches closely with the Date JS type.
+ // We also call it "date" to match.
+ // { "time", strlen("time"), Object::DynamicProperty::Time, "QTime", strlen("QTime") },
+ // { "date", strlen("date"), Object::DynamicProperty::Date, "QDate", strlen("QDate") },
+ { "date", strlen("date"), Object::DynamicProperty::DateTime, "QDateTime", strlen("QDateTime") },
+ { "variant", strlen("variant"), Object::DynamicProperty::Variant, "QVariant", strlen("QVariant") },
+ { "var", strlen("var"), Object::DynamicProperty::Var, "QVariant", strlen("QVariant") }
+ };
+ static const int propTypeNameToTypesCount = sizeof(propTypeNameToTypes) /
+ sizeof(propTypeNameToTypes[0]);
+
+ if(node->type == AST::UiPublicMember::Signal) {
+ Object::DynamicSignal *signal = _parser->_pool.New<Object::DynamicSignal>();
+ signal->name = node->name;
+
+ AST::UiParameterList *p = node->parameters;
+ int paramLength = 0;
+ while (p) { paramLength++; p = p->next; }
+ p = node->parameters;
+
+ if (paramLength) {
+ signal->parameterTypes = _parser->_pool.NewRawList<QHashedCStringRef>(paramLength);
+ signal->parameterNames = _parser->_pool.NewRawList<QHashedStringRef>(paramLength);
+ }
+
+ int index = 0;
+ while (p) {
+ const QStringRef &memberType = p->type;
+
+ const TypeNameToType *type = 0;
+ for(int typeIndex = 0; typeIndex < propTypeNameToTypesCount; ++typeIndex) {
+ const TypeNameToType *t = propTypeNameToTypes + typeIndex;
+ if (t->nameLength == memberType.length() &&
+ QHashedString::compare(memberType.constData(), t->name, t->nameLength)) {
+ type = t;
+ break;
+ }
+ }
+
+ if (!type) {
+ QQmlError error;
+ error.setDescription(QCoreApplication::translate("QQmlParser","Expected parameter type"));
+ error.setLine(node->typeToken.startLine);
+ error.setColumn(node->typeToken.startColumn);
+ _parser->_errors << error;
+ return false;
+ }
+
+ signal->parameterTypes[index] = QHashedCStringRef(type->qtName, type->qtNameLength);
+ signal->parameterNames[index] = QHashedStringRef(p->name);
+ p = p->next;
+ index++;
+ }
+
+ signal->location = location(node->typeToken, node->semicolonToken);
+ _stateStack.top().object->dynamicSignals.append(signal);
+ } else {
+ const QStringRef &memberType = node->memberType;
+ const QStringRef &name = node->name;
+
+ bool typeFound = false;
+ Object::DynamicProperty::Type type;
+
+ if ((unsigned)memberType.length() == strlen("alias") &&
+ QHashedString::compare(memberType.constData(), "alias", strlen("alias"))) {
+ type = Object::DynamicProperty::Alias;
+ typeFound = true;
+ }
+
+ for(int ii = 0; !typeFound && ii < propTypeNameToTypesCount; ++ii) {
+ const TypeNameToType *t = propTypeNameToTypes + ii;
+ if (t->nameLength == memberType.length() &&
+ QHashedString::compare(memberType.constData(), t->name, t->nameLength)) {
+ type = t->type;
+ typeFound = true;
+ }
+ }
+
+ if (!typeFound && memberType.at(0).isUpper()) {
+ const QStringRef &typeModifier = node->typeModifier;
+
+ if (typeModifier.isEmpty()) {
+ type = Object::DynamicProperty::Custom;
+ } else if((unsigned)typeModifier.length() == strlen("list") &&
+ QHashedString::compare(typeModifier.constData(), "list", strlen("list"))) {
+ type = Object::DynamicProperty::CustomList;
+ } else {
+ QQmlError error;
+ error.setDescription(QCoreApplication::translate("QQmlParser","Invalid property type modifier"));
+ error.setLine(node->typeModifierToken.startLine);
+ error.setColumn(node->typeModifierToken.startColumn);
+ _parser->_errors << error;
+ return false;
+ }
+ typeFound = true;
+ } else if (!node->typeModifier.isNull()) {
+ QQmlError error;
+ error.setDescription(QCoreApplication::translate("QQmlParser","Unexpected property type modifier"));
+ error.setLine(node->typeModifierToken.startLine);
+ error.setColumn(node->typeModifierToken.startColumn);
+ _parser->_errors << error;
+ return false;
+ }
+
+ if(!typeFound) {
+ QQmlError error;
+ error.setDescription(QCoreApplication::translate("QQmlParser","Expected property type"));
+ error.setLine(node->typeToken.startLine);
+ error.setColumn(node->typeToken.startColumn);
+ _parser->_errors << error;
+ return false;
+ }
+
+ Object::DynamicProperty *property = _parser->_pool.New<Object::DynamicProperty>();
+ property->isDefaultProperty = node->isDefaultMember;
+ property->isReadOnly = node->isReadonlyMember;
+ property->type = type;
+ property->nameLocation.line = node->identifierToken.startLine;
+ property->nameLocation.column = node->identifierToken.startColumn;
+ if (type >= Object::DynamicProperty::Custom) {
+ QQmlScript::TypeReference *typeRef =
+ _parser->findOrCreateType(memberType.toString());
+ typeRef->refObjects.append(_stateStack.top().object);
+ property->customType = memberType;
+ }
+
+ property->name = QHashedStringRef(name);
+ property->location = location(node->firstSourceLocation(),
+ node->lastSourceLocation());
+
+ if (node->statement) { // default value
+ property->defaultValue = _parser->_pool.New<Property>();
+ property->defaultValue->parent = _stateStack.top().object;
+ property->defaultValue->location =
+ location(node->statement->firstSourceLocation(),
+ node->statement->lastSourceLocation());
+ QQmlScript::Value *value = _parser->_pool.New<QQmlScript::Value>();
+ value->location = location(node->statement->firstSourceLocation(),
+ node->statement->lastSourceLocation());
+ value->value = getVariant(node->statement);
+ property->defaultValue->values.append(value);
+ }
+
+ _stateStack.top().object->dynamicProperties.append(property);
+
+ // process QML-like initializers (e.g. property Object o: Object {})
+ accept(node->binding);
+ }
+
+ return false;
+}
+
+
+// UiObjectMember: UiQualifiedId UiObjectInitializer ;
+bool ProcessAST::visit(AST::UiObjectDefinition *node)
+{
+ LocationSpan l = location(node->firstSourceLocation(),
+ node->lastSourceLocation());
+
+ const QString objectType = asString(node->qualifiedTypeNameId);
+ const AST::SourceLocation typeLocation = node->qualifiedTypeNameId->identifierToken;
+
+ defineObjectBinding(/*propertyName = */ 0, false, objectType,
+ typeLocation, l, node->initializer);
+
+ return false;
+}
+
+
+// UiObjectMember: UiQualifiedId T_COLON UiQualifiedId UiObjectInitializer ;
+bool ProcessAST::visit(AST::UiObjectBinding *node)
+{
+ LocationSpan l = location(node->qualifiedTypeNameId->identifierToken,
+ node->initializer->rbraceToken);
+
+ const QString objectType = asString(node->qualifiedTypeNameId);
+ const AST::SourceLocation typeLocation = node->qualifiedTypeNameId->identifierToken;
+
+ defineObjectBinding(node->qualifiedId, node->hasOnToken, objectType,
+ typeLocation, l, node->initializer);
+
+ return false;
+}
+
+QQmlScript::Variant ProcessAST::getVariant(AST::Statement *stmt)
+{
+ if (stmt) {
+ if (AST::ExpressionStatement *exprStmt = AST::cast<AST::ExpressionStatement *>(stmt))
+ return getVariant(exprStmt->expression);
+
+ return QQmlScript::Variant(asStringRef(stmt), stmt);
+ }
+
+ return QQmlScript::Variant();
+}
+
+QQmlScript::Variant ProcessAST::getVariant(AST::ExpressionNode *expr)
+{
+ if (AST::StringLiteral *lit = AST::cast<AST::StringLiteral *>(expr)) {
+ return QQmlScript::Variant(lit);
+ } else if (expr->kind == AST::Node::Kind_TrueLiteral) {
+ return QQmlScript::Variant(true);
+ } else if (expr->kind == AST::Node::Kind_FalseLiteral) {
+ return QQmlScript::Variant(false);
+ } else if (AST::NumericLiteral *lit = AST::cast<AST::NumericLiteral *>(expr)) {
+ return QQmlScript::Variant(lit->value, asStringRef(expr));
+ } else {
+
+ if (AST::UnaryMinusExpression *unaryMinus = AST::cast<AST::UnaryMinusExpression *>(expr)) {
+ if (AST::NumericLiteral *lit = AST::cast<AST::NumericLiteral *>(unaryMinus->expression)) {
+ return QQmlScript::Variant(-lit->value, asStringRef(expr));
+ }
+ }
+
+ return QQmlScript::Variant(asStringRef(expr), expr);
+ }
+}
+
+
+// UiObjectMember: UiQualifiedId T_COLON Statement ;
+bool ProcessAST::visit(AST::UiScriptBinding *node)
+{
+ int propertyCount = 0;
+ AST::UiQualifiedId *propertyName = node->qualifiedId;
+ for (AST::UiQualifiedId *name = propertyName; name; name = name->next){
+ ++propertyCount;
+ _stateStack.pushProperty(name->name,
+ location(name));
+ }
+
+ Property *prop = currentProperty();
+
+ if (!prop->values.isEmpty()) {
+ QQmlError error;
+ error.setDescription(QCoreApplication::translate("QQmlParser","Property value set multiple times"));
+ error.setLine(this->location(propertyName).start.line);
+ error.setColumn(this->location(propertyName).start.column);
+ _parser->_errors << error;
+ return 0;
+ }
+
+ QQmlScript::Variant primitive;
+
+ if (AST::ExpressionStatement *stmt = AST::cast<AST::ExpressionStatement *>(node->statement)) {
+ primitive = getVariant(stmt->expression);
+ } else { // do binding
+ primitive = QQmlScript::Variant(asStringRef(node->statement), node->statement);
+ }
+
+ prop->location.range.length = prop->location.range.offset + prop->location.range.length - node->qualifiedId->identifierToken.offset;
+ prop->location.range.offset = node->qualifiedId->identifierToken.offset;
+ QQmlScript::Value *v = _parser->_pool.New<QQmlScript::Value>();
+ v->value = primitive;
+ v->location = location(node->statement->firstSourceLocation(),
+ node->statement->lastSourceLocation());
+
+ prop->addValue(v);
+
+ while (propertyCount--)
+ _stateStack.pop();
+
+ return false;
+}
+
+// UiObjectMember: UiQualifiedId T_COLON T_LBRACKET UiArrayMemberList T_RBRACKET ;
+bool ProcessAST::visit(AST::UiArrayBinding *node)
+{
+ int propertyCount = 0;
+ AST::UiQualifiedId *propertyName = node->qualifiedId;
+ for (AST::UiQualifiedId *name = propertyName; name; name = name->next){
+ ++propertyCount;
+ _stateStack.pushProperty(name->name,
+ location(name));
+ }
+
+ Property* prop = currentProperty();
+
+ if (!prop->values.isEmpty()) {
+ QQmlError error;
+ error.setDescription(QCoreApplication::translate("QQmlParser","Property value set multiple times"));
+ error.setLine(this->location(propertyName).start.line);
+ error.setColumn(this->location(propertyName).start.column);
+ _parser->_errors << error;
+ return false;
+ }
+
+ accept(node->members);
+
+ // For the DOM, store the position of the T_LBRACKET upto the T_RBRACKET as the range:
+ prop->listValueRange.offset = node->lbracketToken.offset;
+ prop->listValueRange.length = node->rbracketToken.offset + node->rbracketToken.length - node->lbracketToken.offset;
+
+ while (propertyCount--)
+ _stateStack.pop();
+
+ return false;
+}
+
+bool ProcessAST::visit(AST::UiSourceElement *node)
+{
+ QQmlScript::Object *obj = currentObject();
+
+ if (AST::FunctionDeclaration *funDecl = AST::cast<AST::FunctionDeclaration *>(node->sourceElement)) {
+
+ Object::DynamicSlot *slot = _parser->_pool.New<Object::DynamicSlot>();
+ slot->location = location(funDecl->identifierToken, funDecl->lastSourceLocation());
+
+ AST::FormalParameterList *f = funDecl->formals;
+ while (f) {
+ slot->parameterNames << f->name.toUtf8();
+ f = f->next;
+ }
+
+ AST::SourceLocation loc = funDecl->rparenToken;
+ loc.offset = loc.end();
+ loc.startColumn += 1;
+ QString body = textAt(loc, funDecl->rbraceToken);
+ slot->name = funDecl->name;
+ slot->body = body;
+ obj->dynamicSlots.append(slot);
+
+ } else {
+ QQmlError error;
+ error.setDescription(QCoreApplication::translate("QQmlParser","JavaScript declaration outside Script element"));
+ error.setLine(node->firstSourceLocation().startLine);
+ error.setColumn(node->firstSourceLocation().startColumn);
+ _parser->_errors << error;
+ }
+ return false;
+}
+
+} // end of anonymous namespace
+
+
+QQmlScript::Parser::Parser()
+: root(0), data(0)
+{
+
+}
+
+QQmlScript::Parser::~Parser()
+{
+ clear();
+}
+
+namespace QQmlScript {
+class ParserJsASTData
+{
+public:
+ ParserJsASTData(const QString &filename)
+ : filename(filename) {}
+
+ QString filename;
+ Engine engine;
+};
+}
+
+bool QQmlScript::Parser::parse(const QByteArray &qmldata, const QUrl &url,
+ const QString &urlString)
+{
+ clear();
+
+ if (urlString.isEmpty()) {
+ _scriptFile = url.toString();
+ } else {
+ // Q_ASSERT(urlString == url.toString());
+ _scriptFile = urlString;
+ }
+
+ QTextStream stream(qmldata, QIODevice::ReadOnly);
+#ifndef QT_NO_TEXTCODEC
+ stream.setCodec("UTF-8");
+#endif
+ QString *code = _pool.NewString(stream.readAll());
+
+ data = new QQmlScript::ParserJsASTData(_scriptFile);
+
+ Lexer lexer(&data->engine);
+ lexer.setCode(*code, /*line = */ 1);
+
+ QQmlJS::Parser parser(&data->engine);
+
+ if (! parser.parse() || !_errors.isEmpty()) {
+
+ // Extract errors from the parser
+ foreach (const DiagnosticMessage &m, parser.diagnosticMessages()) {
+
+ if (m.isWarning())
+ continue;
+
+ QQmlError error;
+ error.setUrl(url);
+ error.setDescription(m.message);
+ error.setLine(m.loc.startLine);
+ error.setColumn(m.loc.startColumn);
+ _errors << error;
+
+ }
+ }
+
+ if (_errors.isEmpty()) {
+ ProcessAST process(this);
+ process(*code, parser.ast());
+
+ // Set the url for process errors
+ for(int ii = 0; ii < _errors.count(); ++ii)
+ _errors[ii].setUrl(url);
+ }
+
+ return _errors.isEmpty();
+}
+
+QList<QQmlScript::TypeReference*> QQmlScript::Parser::referencedTypes() const
+{
+ return _refTypes;
+}
+
+QQmlScript::Object *QQmlScript::Parser::tree() const
+{
+ return root;
+}
+
+QList<QQmlScript::Import> QQmlScript::Parser::imports() const
+{
+ return _imports;
+}
+
+QList<QQmlError> QQmlScript::Parser::errors() const
+{
+ return _errors;
+}
+
+static void replaceWithSpace(QString &str, int idx, int n)
+{
+ QChar *data = str.data() + idx;
+ const QChar space(QLatin1Char(' '));
+ for (int ii = 0; ii < n; ++ii)
+ *data++ = space;
+}
+
+static QQmlScript::LocationSpan
+locationFromLexer(const QQmlJS::Lexer &lex, int startLine, int startColumn, int startOffset)
+{
+ QQmlScript::LocationSpan l;
+
+ l.start.line = startLine; l.start.column = startColumn;
+ l.end.line = lex.tokenEndLine(); l.end.column = lex.tokenEndColumn();
+ l.range.offset = startOffset;
+ l.range.length = lex.tokenOffset() + lex.tokenLength() - startOffset;
+
+ return l;
+}
+
+/*
+Searches for ".pragma <value>" declarations within \a script. Currently supported pragmas
+are:
+ library
+*/
+QQmlScript::Object::ScriptBlock::Pragmas QQmlScript::Parser::extractPragmas(QString &script)
+{
+ QQmlScript::Object::ScriptBlock::Pragmas rv = QQmlScript::Object::ScriptBlock::None;
+
+ const QString pragma(QLatin1String("pragma"));
+ const QString library(QLatin1String("library"));
+
+ QQmlJS::Lexer l(0);
+ l.setCode(script, 0);
+
+ int token = l.lex();
+
+ while (true) {
+ if (token != QQmlJSGrammar::T_DOT)
+ return rv;
+
+ int startOffset = l.tokenOffset();
+ int startLine = l.tokenStartLine();
+
+ token = l.lex();
+
+ if (token != QQmlJSGrammar::T_IDENTIFIER ||
+ l.tokenStartLine() != startLine ||
+ script.mid(l.tokenOffset(), l.tokenLength()) != pragma)
+ return rv;
+
+ token = l.lex();
+
+ if (token != QQmlJSGrammar::T_IDENTIFIER ||
+ l.tokenStartLine() != startLine)
+ return rv;
+
+ QString pragmaValue = script.mid(l.tokenOffset(), l.tokenLength());
+ int endOffset = l.tokenLength() + l.tokenOffset();
+
+ token = l.lex();
+ if (l.tokenStartLine() == startLine)
+ return rv;
+
+ if (pragmaValue == library) {
+ rv |= QQmlScript::Object::ScriptBlock::Shared;
+ replaceWithSpace(script, startOffset, endOffset - startOffset);
+ } else {
+ return rv;
+ }
+ }
+ return rv;
+}
+
+#define CHECK_LINE if (l.tokenStartLine() != startLine) return rv;
+#define CHECK_TOKEN(t) if (token != QQmlJSGrammar:: t) return rv;
+
+static const int uriTokens[] = {
+ QQmlJSGrammar::T_IDENTIFIER,
+ QQmlJSGrammar::T_PROPERTY,
+ QQmlJSGrammar::T_SIGNAL,
+ QQmlJSGrammar::T_READONLY,
+ QQmlJSGrammar::T_ON,
+ QQmlJSGrammar::T_BREAK,
+ QQmlJSGrammar::T_CASE,
+ QQmlJSGrammar::T_CATCH,
+ QQmlJSGrammar::T_CONTINUE,
+ QQmlJSGrammar::T_DEFAULT,
+ QQmlJSGrammar::T_DELETE,
+ QQmlJSGrammar::T_DO,
+ QQmlJSGrammar::T_ELSE,
+ QQmlJSGrammar::T_FALSE,
+ QQmlJSGrammar::T_FINALLY,
+ QQmlJSGrammar::T_FOR,
+ QQmlJSGrammar::T_FUNCTION,
+ QQmlJSGrammar::T_IF,
+ QQmlJSGrammar::T_IN,
+ QQmlJSGrammar::T_INSTANCEOF,
+ QQmlJSGrammar::T_NEW,
+ QQmlJSGrammar::T_NULL,
+ QQmlJSGrammar::T_RETURN,
+ QQmlJSGrammar::T_SWITCH,
+ QQmlJSGrammar::T_THIS,
+ QQmlJSGrammar::T_THROW,
+ QQmlJSGrammar::T_TRUE,
+ QQmlJSGrammar::T_TRY,
+ QQmlJSGrammar::T_TYPEOF,
+ QQmlJSGrammar::T_VAR,
+ QQmlJSGrammar::T_VOID,
+ QQmlJSGrammar::T_WHILE,
+ QQmlJSGrammar::T_CONST,
+ QQmlJSGrammar::T_DEBUGGER,
+ QQmlJSGrammar::T_RESERVED_WORD,
+ QQmlJSGrammar::T_WITH,
+
+ QQmlJSGrammar::EOF_SYMBOL
+};
+static inline bool isUriToken(int token)
+{
+ const int *current = uriTokens;
+ while (*current != QQmlJSGrammar::EOF_SYMBOL) {
+ if (*current == token)
+ return true;
+ ++current;
+ }
+ return false;
+}
+
+QQmlScript::Parser::JavaScriptMetaData QQmlScript::Parser::extractMetaData(QString &script)
+{
+ JavaScriptMetaData rv;
+
+ QQmlScript::Object::ScriptBlock::Pragmas &pragmas = rv.pragmas;
+
+ const QString pragma(QLatin1String("pragma"));
+ const QString js(QLatin1String(".js"));
+ const QString library(QLatin1String("library"));
+
+ QQmlJS::Lexer l(0);
+ l.setCode(script, 0);
+
+ int token = l.lex();
+
+ while (true) {
+ if (token != QQmlJSGrammar::T_DOT)
+ return rv;
+
+ int startOffset = l.tokenOffset();
+ int startLine = l.tokenStartLine();
+ int startColumn = l.tokenStartColumn();
+
+ token = l.lex();
+
+ CHECK_LINE;
+
+ if (token == QQmlJSGrammar::T_IMPORT) {
+
+ // .import <URI> <Version> as <Identifier>
+ // .import <file.js> as <Identifier>
+
+ token = l.lex();
+
+ CHECK_LINE;
+
+ if (token == QQmlJSGrammar::T_STRING_LITERAL) {
+
+ QString file = l.tokenText();
+
+ if (!file.endsWith(js))
+ return rv;
+
+ token = l.lex();
+
+ CHECK_TOKEN(T_AS);
+ CHECK_LINE;
+
+ token = l.lex();
+
+ CHECK_TOKEN(T_IDENTIFIER);
+ CHECK_LINE;
+
+ int endOffset = l.tokenLength() + l.tokenOffset();
+
+ QString importId = script.mid(l.tokenOffset(), l.tokenLength());
+
+ if (!importId.at(0).isUpper())
+ return rv;
+
+ QQmlScript::LocationSpan location =
+ locationFromLexer(l, startLine, startColumn, startOffset);
+
+ token = l.lex();
+ if (l.tokenStartLine() == startLine)
+ return rv;
+
+ replaceWithSpace(script, startOffset, endOffset - startOffset);
+
+ Import import;
+ import.type = Import::Script;
+ import.uri = file;
+ import.qualifier = importId;
+ import.location = location;
+
+ rv.imports << import;
+ } else {
+ // URI
+ QString uri;
+ QString version;
+
+ while (true) {
+ if (!isUriToken(token))
+ return rv;
+
+ uri.append(l.tokenText());
+
+ token = l.lex();
+ CHECK_LINE;
+ if (token != QQmlJSGrammar::T_DOT)
+ break;
+
+ uri.append(QLatin1Char('.'));
+
+ token = l.lex();
+ CHECK_LINE;
+ }
+
+ CHECK_TOKEN(T_NUMERIC_LITERAL);
+ version = script.mid(l.tokenOffset(), l.tokenLength());
+
+ token = l.lex();
+
+ CHECK_TOKEN(T_AS);
+ CHECK_LINE;
+
+ token = l.lex();
+
+ CHECK_TOKEN(T_IDENTIFIER);
+ CHECK_LINE;
+
+ int endOffset = l.tokenLength() + l.tokenOffset();
+
+ QString importId = script.mid(l.tokenOffset(), l.tokenLength());
+
+ if (!importId.at(0).isUpper())
+ return rv;
+
+ QQmlScript::LocationSpan location =
+ locationFromLexer(l, startLine, startColumn, startOffset);
+
+ token = l.lex();
+ if (l.tokenStartLine() == startLine)
+ return rv;
+
+ replaceWithSpace(script, startOffset, endOffset - startOffset);
+
+ Import import;
+ import.type = Import::Library;
+ import.uri = uri;
+ import.version = version;
+ import.qualifier = importId;
+ import.location = location;
+
+ rv.imports << import;
+ }
+
+ } else if (token == QQmlJSGrammar::T_IDENTIFIER &&
+ script.mid(l.tokenOffset(), l.tokenLength()) == pragma) {
+
+ token = l.lex();
+
+ CHECK_TOKEN(T_IDENTIFIER);
+ CHECK_LINE;
+
+ QString pragmaValue = script.mid(l.tokenOffset(), l.tokenLength());
+ int endOffset = l.tokenLength() + l.tokenOffset();
+
+ if (pragmaValue == library) {
+ pragmas |= QQmlScript::Object::ScriptBlock::Shared;
+ replaceWithSpace(script, startOffset, endOffset - startOffset);
+ } else {
+ return rv;
+ }
+
+ token = l.lex();
+ if (l.tokenStartLine() == startLine)
+ return rv;
+
+ } else {
+ return rv;
+ }
+ }
+ return rv;
+}
+
+void QQmlScript::Parser::clear()
+{
+ _imports.clear();
+ qDeleteAll(_refTypes);
+ _refTypes.clear();
+ _errors.clear();
+
+ if (data) {
+ delete data;
+ data = 0;
+ }
+
+ _pool.clear();
+}
+
+QQmlScript::TypeReference *QQmlScript::Parser::findOrCreateType(const QString &name)
+{
+ TypeReference *type = 0;
+ int i = 0;
+ for (; i < _refTypes.size(); ++i) {
+ if (_refTypes.at(i)->name == name) {
+ type = _refTypes.at(i);
+ break;
+ }
+ }
+ if (!type) {
+ type = new TypeReference(i, name);
+ _refTypes.append(type);
+ }
+
+ return type;
+}
+
+void QQmlScript::Parser::setTree(QQmlScript::Object *tree)
+{
+ Q_ASSERT(! root);
+
+ root = tree;
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlscript_p.h b/src/qml/qml/qqmlscript_p.h
new file mode 100644
index 0000000000..ddf4c9a392
--- /dev/null
+++ b/src/qml/qml/qqmlscript_p.h
@@ -0,0 +1,533 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef QQMLSCRIPT_P_H
+#define QQMLSCRIPT_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtQml/qqmlerror.h>
+
+#include <private/qfieldlist_p.h>
+#include <private/qhashfield_p.h>
+#include <private/qfastmetabuilder_p.h>
+#include <private/qqmlpool_p.h>
+#include <private/qqmlpropertycache_p.h>
+
+#include <QtCore/QList>
+#include <QtCore/QUrl>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+
+class QByteArray;
+class QQmlPropertyCache;
+namespace QQmlJS { namespace AST { class Node; class StringLiteral; } }
+namespace QQmlCompilerTypes { struct BindingReference; struct ComponentCompileState; }
+
+namespace QQmlScript {
+
+struct Location
+{
+ Location() : line(-1), column(-1) {}
+ int line;
+ int column;
+
+ inline bool operator<(const Location &other) {
+ return line < other.line ||
+ (line == other.line && column < other.column);
+ }
+};
+
+struct LocationRange
+{
+ LocationRange() : offset(0), length(0) {}
+ quint32 offset;
+ quint32 length;
+};
+
+struct LocationSpan
+{
+ Location start;
+ Location end;
+ LocationRange range;
+
+ bool operator<(LocationSpan &o) const {
+ return (start.line < o.start.line) ||
+ (start.line == o.start.line && start.column < o.start.column);
+ }
+};
+
+class Import
+{
+public:
+ Import() : type(Library) {}
+
+ enum Type { Library, File, Script };
+ Type type;
+
+ QString uri;
+ QString qualifier;
+ QString version;
+
+ void extractVersion(int *maj, int *min) const;
+
+ QQmlScript::LocationSpan location;
+};
+
+class Object;
+class TypeReference
+{
+public:
+ TypeReference(int typeId, const QString &typeName) : id(typeId), name(typeName) {}
+
+ int id;
+ // type as it has been referenced in Qml
+ QString name;
+ // objects in parse tree referencing the type
+ QList<QQmlScript::Object*> refObjects;
+};
+
+class Object;
+class Property;
+
+class Q_QML_EXPORT Variant
+{
+public:
+ enum Type {
+ Invalid,
+ Boolean,
+ Number,
+ String,
+ Script
+ };
+
+ Variant();
+ Variant(const Variant &);
+ explicit Variant(bool);
+ explicit Variant(double, const QStringRef &asWritten = QStringRef());
+ explicit Variant(QQmlJS::AST::StringLiteral *);
+ explicit Variant(const QStringRef &asWritten, QQmlJS::AST::Node *);
+ Variant &operator=(const Variant &);
+
+ Type type() const;
+
+ bool isBoolean() const { return type() == Boolean; }
+ bool isNumber() const { return type() == Number; }
+ bool isString() const { return type() == String; }
+ bool isScript() const { return type() == Script; }
+ bool isStringList() const;
+
+ bool asBoolean() const;
+ QString asString() const;
+ double asNumber() const;
+ QString asScript() const;
+ QQmlJS::AST::Node *asAST() const;
+ QStringList asStringList() const;
+
+private:
+ Type t;
+ union {
+ bool b;
+ double d;
+ QQmlJS::AST::StringLiteral *l;
+ QQmlJS::AST::Node *n;
+ };
+ QStringRef asWritten;
+};
+
+class Value : public QQmlPool::POD
+{
+public:
+ Value();
+
+ enum Type {
+ // The type of this value assignment is not yet known
+ Unknown,
+ // This is used as a literal property assignment
+ Literal,
+ // This is used as a property binding assignment
+ PropertyBinding,
+ // This is used as a QQmlPropertyValueSource assignment
+ ValueSource,
+ // This is used as a QQmlPropertyValueInterceptor assignment
+ ValueInterceptor,
+ // This is used as a property QObject assignment
+ CreatedObject,
+ // This is used as a signal object assignment
+ SignalObject,
+ // This is used as a signal expression assignment
+ SignalExpression,
+ // This is used as an id assignment only
+ Id
+ };
+ Type type;
+
+ // ### Temporary (for id only)
+ QString primitive() const { return value.isString() ? value.asString() : value.asScript(); }
+
+ // Primitive value
+ Variant value;
+ // Object value
+ Object *object;
+
+ LocationSpan location;
+
+ // Used by compiler
+ union {
+ QQmlCompilerTypes::BindingReference *bindingReference;
+ int signalExpressionContextStack;
+ };
+
+ // Used in Property::ValueList lists
+ Value *nextValue;
+};
+
+class Property : public QQmlPool::POD
+{
+public:
+ Property();
+
+ // The Object to which this property is attached
+ Object *parent;
+
+ Object *getValue(const LocationSpan &);
+ void addValue(Value *v);
+ void addOnValue(Value *v);
+
+ // The QVariant::Type of the property, or 0 (QVariant::Invalid) if
+ // unknown.
+ int type;
+ // The metaobject index of this property, or -1 if unknown.
+ int index;
+ // The core data in the case of a regular property.
+ // XXX This has to be a value now as the synthCache may change during
+ // compilation which invalidates pointers. We should fix this.
+ QQmlPropertyData core;
+
+ // Returns true if this is an empty property - both value and values
+ // are unset.
+ bool isEmpty() const;
+
+ typedef QFieldList<Value, &Value::nextValue> ValueList;
+ // The list of values assigned to this property. Content in values
+ // and value are mutually exclusive
+ ValueList values;
+ // The list of values assigned to this property using the "on" syntax
+ ValueList onValues;
+ // The accessed property. This is used to represent dot properties.
+ // Content in value and values are mutually exclusive.
+ Object *value;
+ // The property name
+ const QHashedStringRef &name() const { return _name; }
+ void setName(const QString &n) { _name = QHashedStringRef(pool()->NewString(n)); }
+ void setName(const QHashedStringRef &n) { _name = n; }
+ // True if this property was accessed as the default property.
+ bool isDefault;
+ // True if the setting of this property will be deferred. Set by the
+ // QQmlCompiler
+ bool isDeferred;
+ // True if this property is a value-type pseudo-property
+ bool isValueTypeSubProperty;
+ // True if this property is a property alias. Set by the
+ // QQmlCompiler
+ bool isAlias;
+ // True if this is a readonly property declaration
+ bool isReadOnlyDeclaration;
+
+ // Used for scriptStringProperties
+ int scriptStringScope;
+
+ LocationSpan location;
+ LocationRange listValueRange;
+
+ // Used in Object::MainPropertyList
+ Property *nextMainProperty;
+
+ // Used in Object::PropertyList lists
+ Property *nextProperty;
+
+private:
+ friend class Object;
+ QHashedStringRef _name;
+};
+
+class Object : public QQmlPool::Class
+{
+public:
+ Object();
+ virtual ~Object();
+
+ // Type of the object. The integer is an index into the
+ // QQmlCompiledData::types array, or -1 if the object is a property
+ // group.
+ int type;
+
+ // The fully-qualified name of this type
+ QString typeName;
+ // The id assigned to the object (if any). Set by the QQmlCompiler
+ QString id;
+ // The id index assigned to the object (if any). Set by the QQmlCompiler
+ int idIndex;
+ // Custom parsed data
+ QByteArray custom;
+ // Bit mask of the properties assigned bindings
+ QByteArray bindingBitmask;
+ void setBindingBit(int);
+ // Returns the metaobject for this type, or 0 if not available.
+ // Internally selectd between the metatype and extObject variables
+ const QMetaObject *metaObject() const;
+
+ // The compile time metaobject for this type
+ const QMetaObject *metatype;
+ // The synthesized metaobject, if QML added signals or properties to
+ // this type. Otherwise null
+ QAbstractDynamicMetaObject extObject;
+ QByteArray metadata; // Generated by compiler
+ QByteArray synthdata; // Generated by compiler
+ QQmlPropertyCache *synthCache; // Generated by compiler
+
+ Property *getDefaultProperty();
+ // name ptr must be guarenteed to remain valid
+ Property *getProperty(const QHashedStringRef &name, bool create=true);
+ Property *getProperty(const QStringRef &name, bool create=true);
+ Property *getProperty(const QString &name, bool create=true);
+
+ Property *defaultProperty;
+
+ typedef QFieldList<Property, &Property::nextMainProperty> MainPropertyList;
+ MainPropertyList properties;
+ QHashField propertiesHashField;
+
+ // Output of the compilation phase (these properties continue to exist
+ // in either the defaultProperty or properties members too)
+ void addValueProperty(Property *);
+ void addSignalProperty(Property *);
+ void addAttachedProperty(Property *);
+ void addGroupedProperty(Property *);
+ void addValueTypeProperty(Property *);
+ void addScriptStringProperty(Property *);
+
+ typedef QFieldList<Property, &Property::nextProperty> PropertyList;
+ PropertyList valueProperties;
+ PropertyList signalProperties;
+ PropertyList attachedProperties;
+ PropertyList groupedProperties;
+ PropertyList valueTypeProperties;
+ PropertyList scriptStringProperties;
+
+ // Script blocks that were nested under this object
+ struct ScriptBlock {
+ enum Pragma {
+ None = 0x00000000,
+ Shared = 0x00000001
+ };
+ Q_DECLARE_FLAGS(Pragmas, Pragma)
+
+ QString code;
+ QString file;
+ Pragmas pragmas;
+ };
+
+ // The bytes to cast instances by to get to the QQmlParserStatus
+ // interface. -1 indicates the type doesn't support this interface.
+ // Set by the QQmlCompiler.
+ int parserStatusCast;
+
+ LocationSpan location;
+
+ struct DynamicProperty : public QQmlPool::POD
+ {
+ DynamicProperty();
+
+ enum Type { Var, Variant, Int, Bool, Real, String, Url, Color,
+ Time, Date, DateTime, Alias, Custom, CustomList };
+
+ quint32 isDefaultProperty:1;
+ quint32 isReadOnly:1;
+
+ Type type;
+
+ QHashedStringRef customType;
+ QHashedStringRef name;
+ QQmlScript::Property *defaultValue;
+ LocationSpan location;
+ Location nameLocation;
+
+ // Used by Object::DynamicPropertyList
+ DynamicProperty *nextProperty;
+
+ // Used by the compiler
+ QByteArray *resolvedCustomTypeName;
+ QFastMetaBuilder::StringRef typeRef;
+ QFastMetaBuilder::StringRef nameRef;
+ QFastMetaBuilder::StringRef changedSignatureRef;
+ };
+
+ struct DynamicSignal : public QQmlPool::POD
+ {
+ DynamicSignal();
+
+ QHashedStringRef name;
+ QQmlPool::List<QHashedCStringRef> parameterTypes;
+ QQmlPool::List<QHashedStringRef> parameterNames;
+
+ int parameterTypesLength() const;
+ int parameterNamesLength() const;
+
+ // Used by Object::DynamicSignalList
+ DynamicSignal *nextSignal;
+
+ // Used by the compiler
+ QFastMetaBuilder::StringRef signatureRef;
+ QFastMetaBuilder::StringRef parameterNamesRef;
+ LocationSpan location;
+ };
+
+ struct DynamicSlot : public QQmlPool::Class
+ {
+ DynamicSlot();
+
+ QHashedStringRef name;
+ QString body;
+ QList<QByteArray> parameterNames;
+ LocationSpan location;
+
+ int parameterNamesLength() const;
+
+ // Used by Object::DynamicSlotList
+ DynamicSlot *nextSlot;
+
+ // Used by the compiler
+ QFastMetaBuilder::StringRef signatureRef;
+ QFastMetaBuilder::StringRef parameterNamesRef;
+ };
+
+ // The list of dynamic properties
+ typedef QFieldList<DynamicProperty, &DynamicProperty::nextProperty> DynamicPropertyList;
+ DynamicPropertyList dynamicProperties;
+ // The list of dynamic signals
+ typedef QFieldList<DynamicSignal, &DynamicSignal::nextSignal> DynamicSignalList;
+ DynamicSignalList dynamicSignals;
+ // The list of dynamic slots
+ typedef QFieldList<DynamicSlot, &DynamicSlot::nextSlot> DynamicSlotList;
+ DynamicSlotList dynamicSlots;
+
+ // Used by compiler
+ QQmlCompilerTypes::ComponentCompileState *componentCompileState;
+
+ // Used by ComponentCompileState::AliasingObjectsList
+ Object *nextAliasingObject;
+ // Used by ComponentComppileState::IdList
+ Object *nextIdObject;
+};
+
+class ParserJsASTData;
+class Q_AUTOTEST_EXPORT Parser
+{
+public:
+ Parser();
+ ~Parser();
+
+ bool parse(const QByteArray &data, const QUrl &url = QUrl(),
+ const QString &urlString = QString());
+
+ QList<TypeReference*> referencedTypes() const;
+
+ QQmlScript::Object *tree() const;
+ QList<Import> imports() const;
+
+ void clear();
+
+ QList<QQmlError> errors() const;
+
+ class JavaScriptMetaData {
+ public:
+ JavaScriptMetaData()
+ : pragmas(QQmlScript::Object::ScriptBlock::None) {}
+
+ QQmlScript::Object::ScriptBlock::Pragmas pragmas;
+ QList<Import> imports;
+ };
+
+ static QQmlScript::Object::ScriptBlock::Pragmas extractPragmas(QString &);
+ static JavaScriptMetaData extractMetaData(QString &);
+
+
+// ### private:
+ TypeReference *findOrCreateType(const QString &name);
+ void setTree(QQmlScript::Object *tree);
+
+ void setScriptFile(const QString &filename) {_scriptFile = filename; }
+ QString scriptFile() const { return _scriptFile; }
+
+// ### private:
+ QList<QQmlError> _errors;
+
+ QQmlPool _pool;
+ QQmlScript::Object *root;
+ QList<Import> _imports;
+ QList<TypeReference*> _refTypes;
+ QString _scriptFile;
+ ParserJsASTData *data;
+};
+
+}
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QQmlScript::Object::ScriptBlock::Pragmas);
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(QQmlScript::Variant)
+
+QT_END_HEADER
+
+#endif // QQMLSCRIPT_P_H
diff --git a/src/qml/qml/qqmlscriptstring.cpp b/src/qml/qml/qqmlscriptstring.cpp
new file mode 100644
index 0000000000..ed7a6affa1
--- /dev/null
+++ b/src/qml/qml/qqmlscriptstring.cpp
@@ -0,0 +1,157 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qqmlscriptstring.h"
+#include "qqmlscriptstring_p.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+\class QQmlScriptString
+\since 4.7
+\brief The QQmlScriptString class encapsulates a script and its context.
+
+QQmlScriptString is used to create QObject properties that accept a script "assignment" from QML.
+
+Normally, the following QML would result in a binding being established for the \c script
+property; i.e. \c script would be assigned the value obtained from running \c {myObj.value = Math.max(myValue, 100)}
+
+\qml
+MyType {
+ script: myObj.value = Math.max(myValue, 100)
+}
+\endqml
+
+If instead the property had a type of QQmlScriptString,
+the script itself -- \e {myObj.value = Math.max(myValue, 100)} -- would be passed to the \c script property
+and the class could choose how to handle it. Typically, the class will evaluate
+the script at some later time using a QQmlExpression.
+
+\code
+QQmlExpression expr(scriptString);
+expr.evaluate();
+\endcode
+
+\sa QQmlExpression
+*/
+
+/*!
+Constructs an empty instance.
+*/
+QQmlScriptString::QQmlScriptString()
+: d(new QQmlScriptStringPrivate)
+{
+}
+
+/*!
+Copies \a other.
+*/
+QQmlScriptString::QQmlScriptString(const QQmlScriptString &other)
+: d(other.d)
+{
+}
+
+/*!
+\internal
+*/
+QQmlScriptString::~QQmlScriptString()
+{
+}
+
+/*!
+Assigns \a other to this.
+*/
+QQmlScriptString &QQmlScriptString::operator=(const QQmlScriptString &other)
+{
+ d = other.d;
+ return *this;
+}
+
+/*!
+Returns the context for the script.
+*/
+QQmlContext *QQmlScriptString::context() const
+{
+ return d->context;
+}
+
+/*!
+Sets the \a context for the script.
+*/
+void QQmlScriptString::setContext(QQmlContext *context)
+{
+ d->context = context;
+}
+
+/*!
+Returns the scope object for the script.
+*/
+QObject *QQmlScriptString::scopeObject() const
+{
+ return d->scope;
+}
+
+/*!
+Sets the scope \a object for the script.
+*/
+void QQmlScriptString::setScopeObject(QObject *object)
+{
+ d->scope = object;
+}
+
+/*!
+Returns the script text.
+*/
+QString QQmlScriptString::script() const
+{
+ return d->script;
+}
+
+/*!
+Sets the \a script text.
+*/
+void QQmlScriptString::setScript(const QString &script)
+{
+ d->script = script;
+}
+
+QT_END_NAMESPACE
+
diff --git a/src/qml/qml/qqmlscriptstring.h b/src/qml/qml/qqmlscriptstring.h
new file mode 100644
index 0000000000..15db9088f7
--- /dev/null
+++ b/src/qml/qml/qqmlscriptstring.h
@@ -0,0 +1,90 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLSCRIPTSTRING_H
+#define QQMLSCRIPTSTRING_H
+
+#include <QtQml/qtqmlglobal.h>
+#include <QtCore/qstring.h>
+#include <QtCore/qshareddata.h>
+#include <QtCore/qmetatype.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+
+class QObject;
+class QQmlContext;
+class QQmlScriptStringPrivate;
+class Q_QML_EXPORT QQmlScriptString
+{
+public:
+ QQmlScriptString();
+ QQmlScriptString(const QQmlScriptString &);
+ ~QQmlScriptString();
+
+ QQmlScriptString &operator=(const QQmlScriptString &);
+
+ QQmlContext *context() const;
+ void setContext(QQmlContext *);
+
+ QObject *scopeObject() const;
+ void setScopeObject(QObject *);
+
+ QString script() const;
+ void setScript(const QString &);
+
+private:
+ QSharedDataPointer<QQmlScriptStringPrivate> d;
+
+ friend class QQmlVME;
+ friend class QQmlExpression;
+};
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(QQmlScriptString)
+
+QT_END_HEADER
+
+#endif // QQMLSCRIPTSTRING_H
+
diff --git a/src/qml/qml/qqmlscriptstring_p.h b/src/qml/qml/qqmlscriptstring_p.h
new file mode 100644
index 0000000000..15786c7aae
--- /dev/null
+++ b/src/qml/qml/qqmlscriptstring_p.h
@@ -0,0 +1,64 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLSCRIPTSTRING_P_H
+#define QQMLSCRIPTSTRING_P_H
+
+#include <QtQml/qqmlcontext.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQmlScriptStringPrivate : public QSharedData
+{
+public:
+ QQmlScriptStringPrivate() : context(0), scope(0), bindingId(-1), lineNumber(-1), columnNumber(-1) {}
+
+ QQmlContext *context;
+ QObject *scope;
+ QString script;
+ int bindingId;
+ int lineNumber;
+ int columnNumber;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQMLSCRIPTSTRING_P_H
diff --git a/src/qml/qml/qqmlstringconverters.cpp b/src/qml/qml/qqmlstringconverters.cpp
new file mode 100644
index 0000000000..2c7f6c9f6e
--- /dev/null
+++ b/src/qml/qml/qqmlstringconverters.cpp
@@ -0,0 +1,311 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qqmlstringconverters_p.h"
+
+#include <QtGui/qcolor.h>
+#include <QtGui/qvector3d.h>
+#include <QtGui/qvector4d.h>
+#include <QtCore/qpoint.h>
+#include <QtCore/qrect.h>
+#include <QtCore/qsize.h>
+#include <QtCore/qvariant.h>
+#include <QtCore/qdatetime.h>
+
+QT_BEGIN_NAMESPACE
+
+static uchar fromHex(const uchar c, const uchar c2)
+{
+ uchar rv = 0;
+ if (c >= '0' && c <= '9')
+ rv += (c - '0') * 16;
+ else if (c >= 'A' && c <= 'F')
+ rv += (c - 'A' + 10) * 16;
+ else if (c >= 'a' && c <= 'f')
+ rv += (c - 'a' + 10) * 16;
+
+ if (c2 >= '0' && c2 <= '9')
+ rv += (c2 - '0');
+ else if (c2 >= 'A' && c2 <= 'F')
+ rv += (c2 - 'A' + 10);
+ else if (c2 >= 'a' && c2 <= 'f')
+ rv += (c2 - 'a' + 10);
+
+ return rv;
+}
+
+static uchar fromHex(const QString &s, int idx)
+{
+ uchar c = s.at(idx).toAscii();
+ uchar c2 = s.at(idx + 1).toAscii();
+ return fromHex(c, c2);
+}
+
+QVariant QQmlStringConverters::variantFromString(const QString &s)
+{
+ if (s.isEmpty())
+ return QVariant(s);
+ bool ok = false;
+ QRectF r = rectFFromString(s, &ok);
+ if (ok) return QVariant(r);
+ QColor c = colorFromString(s, &ok);
+ if (ok) return QVariant(c);
+ QPointF p = pointFFromString(s, &ok);
+ if (ok) return QVariant(p);
+ QSizeF sz = sizeFFromString(s, &ok);
+ if (ok) return QVariant(sz);
+ QVector3D v = vector3DFromString(s, &ok);
+ if (ok) return QVariant::fromValue(v);
+ QVector4D v4 = vector4DFromString(s, &ok);
+ if (ok) return QVariant::fromValue(v4);
+
+ return QVariant(s);
+}
+
+QVariant QQmlStringConverters::variantFromString(const QString &s, int preferredType, bool *ok)
+{
+ switch (preferredType) {
+ case QMetaType::Int:
+ return QVariant(int(qRound(s.toDouble(ok))));
+ case QMetaType::UInt:
+ return QVariant(uint(qRound(s.toDouble(ok))));
+ case QMetaType::QColor:
+ return QVariant::fromValue(colorFromString(s, ok));
+#ifndef QT_NO_DATESTRING
+ case QMetaType::QDate:
+ return QVariant::fromValue(dateFromString(s, ok));
+ case QMetaType::QTime:
+ return QVariant::fromValue(timeFromString(s, ok));
+ case QMetaType::QDateTime:
+ return QVariant::fromValue(dateTimeFromString(s, ok));
+#endif // QT_NO_DATESTRING
+ case QMetaType::QPointF:
+ return QVariant::fromValue(pointFFromString(s, ok));
+ case QMetaType::QPoint:
+ return QVariant::fromValue(pointFFromString(s, ok).toPoint());
+ case QMetaType::QSizeF:
+ return QVariant::fromValue(sizeFFromString(s, ok));
+ case QMetaType::QSize:
+ return QVariant::fromValue(sizeFFromString(s, ok).toSize());
+ case QMetaType::QRectF:
+ return QVariant::fromValue(rectFFromString(s, ok));
+ case QMetaType::QRect:
+ return QVariant::fromValue(rectFFromString(s, ok).toRect());
+ case QMetaType::QVector3D:
+ return QVariant::fromValue(vector3DFromString(s, ok));
+ case QMetaType::QVector4D:
+ return QVariant::fromValue(vector4DFromString(s, ok));
+ default:
+ if (ok) *ok = false;
+ return QVariant();
+ }
+}
+
+QColor QQmlStringConverters::colorFromString(const QString &s, bool *ok)
+{
+ if (s.length() == 9 && s.startsWith(QLatin1Char('#'))) {
+ uchar a = fromHex(s, 1);
+ uchar r = fromHex(s, 3);
+ uchar g = fromHex(s, 5);
+ uchar b = fromHex(s, 7);
+ if (ok) *ok = true;
+ return QColor(r, g, b, a);
+ } else {
+ QColor rv(s);
+ if (ok) *ok = rv.isValid();
+ return rv;
+ }
+}
+
+#ifndef QT_NO_DATESTRING
+QDate QQmlStringConverters::dateFromString(const QString &s, bool *ok)
+{
+ QDate d = QDate::fromString(s, Qt::ISODate);
+ if (ok) *ok = d.isValid();
+ return d;
+}
+
+QTime QQmlStringConverters::timeFromString(const QString &s, bool *ok)
+{
+ QTime t = QTime::fromString(s, Qt::ISODate);
+ if (ok) *ok = t.isValid();
+ return t;
+}
+
+QDateTime QQmlStringConverters::dateTimeFromString(const QString &s, bool *ok)
+{
+ QDateTime d = QDateTime::fromString(s, Qt::ISODate);
+ if (ok) *ok = d.isValid();
+ return d;
+}
+#endif // QT_NO_DATESTRING
+
+//expects input of "x,y"
+QPointF QQmlStringConverters::pointFFromString(const QString &s, bool *ok)
+{
+ if (s.count(QLatin1Char(',')) != 1) {
+ if (ok)
+ *ok = false;
+ return QPointF();
+ }
+
+ bool xGood, yGood;
+ int index = s.indexOf(QLatin1Char(','));
+ qreal xCoord = s.left(index).toDouble(&xGood);
+ qreal yCoord = s.mid(index+1).toDouble(&yGood);
+ if (!xGood || !yGood) {
+ if (ok)
+ *ok = false;
+ return QPointF();
+ }
+
+ if (ok)
+ *ok = true;
+ return QPointF(xCoord, yCoord);
+}
+
+//expects input of "widthxheight"
+QSizeF QQmlStringConverters::sizeFFromString(const QString &s, bool *ok)
+{
+ if (s.count(QLatin1Char('x')) != 1) {
+ if (ok)
+ *ok = false;
+ return QSizeF();
+ }
+
+ bool wGood, hGood;
+ int index = s.indexOf(QLatin1Char('x'));
+ qreal width = s.left(index).toDouble(&wGood);
+ qreal height = s.mid(index+1).toDouble(&hGood);
+ if (!wGood || !hGood) {
+ if (ok)
+ *ok = false;
+ return QSizeF();
+ }
+
+ if (ok)
+ *ok = true;
+ return QSizeF(width, height);
+}
+
+//expects input of "x,y,widthxheight" //### use space instead of second comma?
+QRectF QQmlStringConverters::rectFFromString(const QString &s, bool *ok)
+{
+ if (s.count(QLatin1Char(',')) != 2 || s.count(QLatin1Char('x')) != 1) {
+ if (ok)
+ *ok = false;
+ return QRectF();
+ }
+
+ bool xGood, yGood, wGood, hGood;
+ int index = s.indexOf(QLatin1Char(','));
+ qreal x = s.left(index).toDouble(&xGood);
+ int index2 = s.indexOf(QLatin1Char(','), index+1);
+ qreal y = s.mid(index+1, index2-index-1).toDouble(&yGood);
+ index = s.indexOf(QLatin1Char('x'), index2+1);
+ qreal width = s.mid(index2+1, index-index2-1).toDouble(&wGood);
+ qreal height = s.mid(index+1).toDouble(&hGood);
+ if (!xGood || !yGood || !wGood || !hGood) {
+ if (ok)
+ *ok = false;
+ return QRectF();
+ }
+
+ if (ok)
+ *ok = true;
+ return QRectF(x, y, width, height);
+}
+
+//expects input of "x,y,z"
+QVector3D QQmlStringConverters::vector3DFromString(const QString &s, bool *ok)
+{
+ if (s.count(QLatin1Char(',')) != 2) {
+ if (ok)
+ *ok = false;
+ return QVector3D();
+ }
+
+ bool xGood, yGood, zGood;
+ int index = s.indexOf(QLatin1Char(','));
+ int index2 = s.indexOf(QLatin1Char(','), index+1);
+ qreal xCoord = s.left(index).toDouble(&xGood);
+ qreal yCoord = s.mid(index+1, index2-index-1).toDouble(&yGood);
+ qreal zCoord = s.mid(index2+1).toDouble(&zGood);
+ if (!xGood || !yGood || !zGood) {
+ if (ok)
+ *ok = false;
+ return QVector3D();
+ }
+
+ if (ok)
+ *ok = true;
+ return QVector3D(xCoord, yCoord, zCoord);
+}
+
+//expects input of "x,y,z,w"
+QVector4D QQmlStringConverters::vector4DFromString(const QString &s, bool *ok)
+{
+ if (s.count(QLatin1Char(',')) != 3) {
+ if (ok)
+ *ok = false;
+ return QVector4D();
+ }
+
+ bool xGood, yGood, zGood, wGood;
+ int index = s.indexOf(QLatin1Char(','));
+ int index2 = s.indexOf(QLatin1Char(','), index+1);
+ int index3 = s.indexOf(QLatin1Char(','), index2+1);
+ qreal xCoord = s.left(index).toDouble(&xGood);
+ qreal yCoord = s.mid(index+1, index2-index-1).toDouble(&yGood);
+ qreal zCoord = s.mid(index2+1, index3-index2-1).toDouble(&zGood);
+ qreal wCoord = s.mid(index3+1).toDouble(&wGood);
+ if (!xGood || !yGood || !zGood || !wGood) {
+ if (ok)
+ *ok = false;
+ return QVector4D();
+ }
+
+ if (ok)
+ *ok = true;
+ return QVector4D(xCoord, yCoord, zCoord, wCoord);
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlstringconverters_p.h b/src/qml/qml/qqmlstringconverters_p.h
new file mode 100644
index 0000000000..8f6fb2485d
--- /dev/null
+++ b/src/qml/qml/qqmlstringconverters_p.h
@@ -0,0 +1,93 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLSTRINGCONVERTERS_P_H
+#define QQMLSTRINGCONVERTERS_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qglobal.h>
+#include <QtCore/qvariant.h>
+
+#include <private/qtqmlglobal_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QColor;
+class QPointF;
+class QSizeF;
+class QRectF;
+class QString;
+class QByteArray;
+class QVector3D;
+class QVector4D;
+
+// XXX - Bauhaus currently uses these methods which is why they're exported
+namespace QQmlStringConverters
+{
+ QVariant Q_QML_PRIVATE_EXPORT variantFromString(const QString &);
+ QVariant Q_QML_PRIVATE_EXPORT variantFromString(const QString &, int preferredType, bool *ok = 0);
+
+ QColor Q_QML_PRIVATE_EXPORT colorFromString(const QString &, bool *ok = 0);
+#ifndef QT_NO_DATESTRING
+ QDate Q_QML_PRIVATE_EXPORT dateFromString(const QString &, bool *ok = 0);
+ QTime Q_QML_PRIVATE_EXPORT timeFromString(const QString &, bool *ok = 0);
+ QDateTime Q_QML_PRIVATE_EXPORT dateTimeFromString(const QString &, bool *ok = 0);
+#endif
+ QPointF Q_QML_PRIVATE_EXPORT pointFFromString(const QString &, bool *ok = 0);
+ QSizeF Q_QML_PRIVATE_EXPORT sizeFFromString(const QString &, bool *ok = 0);
+ QRectF Q_QML_PRIVATE_EXPORT rectFFromString(const QString &, bool *ok = 0);
+ QVector3D Q_QML_PRIVATE_EXPORT vector3DFromString(const QString &, bool *ok = 0);
+ QVector4D Q_QML_PRIVATE_EXPORT vector4DFromString(const QString &, bool *ok = 0);
+}
+
+QT_END_NAMESPACE
+
+#endif // QQMLSTRINGCONVERTERS_P_H
diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp
new file mode 100644
index 0000000000..cde2885f0c
--- /dev/null
+++ b/src/qml/qml/qqmltypeloader.cpp
@@ -0,0 +1,1928 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qqmltypeloader_p.h"
+
+#include <private/qqmlengine_p.h>
+#include <private/qqmlglobal_p.h>
+#include <private/qqmlthread_p.h>
+#include <private/qqmlcompiler_p.h>
+#include <private/qqmlcomponent_p.h>
+#include <private/qqmlprofilerservice_p.h>
+
+#include <QtCore/qdir.h>
+#include <QtCore/qfile.h>
+#include <QtCore/qdebug.h>
+#include <QtCore/qmutex.h>
+#include <QtCore/qthread.h>
+#include <QtCore/qdiriterator.h>
+#include <QtCore/qwaitcondition.h>
+#include <QtQml/qqmlcomponent.h>
+#include <QtQml/qqmlextensioninterface.h>
+
+#if defined (Q_OS_UNIX)
+#include <sys/types.h>
+#include <dirent.h>
+#endif
+
+// #define DATABLOB_DEBUG
+
+#ifdef DATABLOB_DEBUG
+
+#define ASSERT_MAINTHREAD() do { if(m_thread->isThisThread()) qFatal("QQmlDataLoader: Caller not in main thread"); } while(false)
+#define ASSERT_LOADTHREAD() do { if(!m_thread->isThisThread()) qFatal("QQmlDataLoader: Caller not in load thread"); } while(false)
+#define ASSERT_CALLBACK() do { if(!m_manager || !m_manager->m_thread->isThisThread()) qFatal("QQmlDataBlob: An API call was made outside a callback"); } while(false)
+
+#else
+
+#define ASSERT_MAINTHREAD()
+#define ASSERT_LOADTHREAD()
+#define ASSERT_CALLBACK()
+
+#endif
+
+QT_BEGIN_NAMESPACE
+
+// This is a lame object that we need to ensure that slots connected to
+// QNetworkReply get called in the correct thread (the loader thread).
+// As QQmlDataLoader lives in the main thread, and we can't use
+// Qt::DirectConnection connections from a QNetworkReply (because then
+// sender() wont work), we need to insert this object in the middle.
+class QQmlDataLoaderNetworkReplyProxy : public QObject
+{
+ Q_OBJECT
+public:
+ QQmlDataLoaderNetworkReplyProxy(QQmlDataLoader *l);
+
+public slots:
+ void finished();
+ void downloadProgress(qint64, qint64);
+
+private:
+ QQmlDataLoader *l;
+};
+
+class QQmlDataLoaderThread : public QQmlThread
+{
+ typedef QQmlDataLoaderThread This;
+
+public:
+ QQmlDataLoaderThread(QQmlDataLoader *loader);
+ QNetworkAccessManager *networkAccessManager() const;
+ QQmlDataLoaderNetworkReplyProxy *networkReplyProxy() const;
+
+ void load(QQmlDataBlob *b);
+ void loadAsync(QQmlDataBlob *b);
+ void loadWithStaticData(QQmlDataBlob *b, const QByteArray &);
+ void loadWithStaticDataAsync(QQmlDataBlob *b, const QByteArray &);
+ void callCompleted(QQmlDataBlob *b);
+ void callDownloadProgressChanged(QQmlDataBlob *b, qreal p);
+ void initializeEngine(QQmlExtensionInterface *, const char *);
+
+protected:
+ virtual void shutdownThread();
+
+private:
+ void loadThread(QQmlDataBlob *b);
+ void loadWithStaticDataThread(QQmlDataBlob *b, const QByteArray &);
+ void callCompletedMain(QQmlDataBlob *b);
+ void callDownloadProgressChangedMain(QQmlDataBlob *b, qreal p);
+ void initializeEngineMain(QQmlExtensionInterface *iface, const char *uri);
+
+ QQmlDataLoader *m_loader;
+ mutable QNetworkAccessManager *m_networkAccessManager;
+ mutable QQmlDataLoaderNetworkReplyProxy *m_networkReplyProxy;
+};
+
+
+QQmlDataLoaderNetworkReplyProxy::QQmlDataLoaderNetworkReplyProxy(QQmlDataLoader *l)
+: l(l)
+{
+}
+
+void QQmlDataLoaderNetworkReplyProxy::finished()
+{
+ Q_ASSERT(sender());
+ Q_ASSERT(qobject_cast<QNetworkReply *>(sender()));
+ QNetworkReply *reply = static_cast<QNetworkReply *>(sender());
+ l->networkReplyFinished(reply);
+}
+
+void QQmlDataLoaderNetworkReplyProxy::downloadProgress(qint64 bytesReceived, qint64 bytesTotal)
+{
+ Q_ASSERT(sender());
+ Q_ASSERT(qobject_cast<QNetworkReply *>(sender()));
+ QNetworkReply *reply = static_cast<QNetworkReply *>(sender());
+ l->networkReplyProgress(reply, bytesReceived, bytesTotal);
+}
+
+/*
+Returns the set of QML files in path (qmldir, *.qml, *.js). The caller
+is responsible for deleting the returned data.
+Returns 0 if the directory does not exist.
+*/
+#if defined (Q_OS_UNIX) && !defined(Q_OS_DARWIN)
+static QStringHash<bool> *qmlFilesInDirectory(const QString &path)
+{
+ QByteArray name(QFile::encodeName(path));
+ DIR *dd = opendir(name);
+ if (!dd)
+ return 0;
+
+ struct dirent *result;
+ union {
+ struct dirent d;
+ char b[offsetof (struct dirent, d_name) + NAME_MAX + 1];
+ } u;
+
+ QStringHash<bool> *files = new QStringHash<bool>;
+ while (readdir_r(dd, &u.d, &result) == 0 && result != 0) {
+ if (!strcmp(u.d.d_name, "qmldir")) {
+ files->insert(QLatin1String("qmldir"), true);
+ continue;
+ }
+ int len = strlen(u.d.d_name);
+ if (len < 4)
+ continue;
+ if (!strcmp(u.d.d_name+len-4, ".qml") || !strcmp(u.d.d_name+len-3, ".js"))
+ files->insert(QFile::decodeName(u.d.d_name), true);
+#if defined(Q_OS_DARWIN)
+ else if ((len > 6 && !strcmp(u.d.d_name+len-6, ".dylib")) || !strcmp(u.d.d_name+len-3, ".so")
+ || (len > 7 && !strcmp(u.d.d_name+len-7, ".bundle")))
+ files->insert(QFile::decodeName(u.d.d_name), true);
+#else // Unix
+ else if (!strcmp(u.d.d_name+len-3, ".so") || !strcmp(u.d.d_name+len-3, ".sl"))
+ files->insert(QFile::decodeName(u.d.d_name), true);
+#endif
+ }
+
+ closedir(dd);
+ return files;
+}
+#else
+static QStringHash<bool> *qmlFilesInDirectory(const QString &path)
+{
+ QDirIterator dir(path, QDir::Files);
+ if (!dir.hasNext())
+ return 0;
+ QStringHash<bool> *files = new QStringHash<bool>;
+ while (dir.hasNext()) {
+ dir.next();
+ QString fileName = dir.fileName();
+ if (fileName == QLatin1String("qmldir")
+ || fileName.endsWith(QLatin1String(".qml"))
+ || fileName.endsWith(QLatin1String(".js"))
+#if defined(Q_OS_WIN32) || defined(Q_OS_WINCE)
+ || fileName.endsWith(QLatin1String(".dll"))
+#elif defined(Q_OS_DARWIN)
+ || fileName.endsWith(QLatin1String(".dylib"))
+ || fileName.endsWith(QLatin1String(".so"))
+ || fileName.endsWith(QLatin1String(".bundle"))
+#else // Unix
+ || fileName.endsWith(QLatin1String(".so"))
+ || fileName.endsWith(QLatin1String(".sl"))
+#endif
+ ) {
+#if defined(Q_OS_WIN32) || defined(Q_OS_WINCE) || defined(Q_OS_DARWIN)
+ fileName = fileName.toLower();
+#endif
+ files->insert(fileName, true);
+ }
+ }
+ return files;
+}
+#endif
+
+
+/*!
+\class QQmlDataBlob
+\brief The QQmlDataBlob encapsulates a data request that can be issued to a QQmlDataLoader.
+\internal
+
+QQmlDataBlob's are loaded by a QQmlDataLoader. The user creates the QQmlDataBlob
+and then calls QQmlDataLoader::load() or QQmlDataLoader::loadWithStaticData() to load it.
+The QQmlDataLoader invokes callbacks on the QQmlDataBlob as data becomes available.
+*/
+
+/*!
+\enum QQmlDataBlob::Status
+
+This enum describes the status of the data blob.
+
+\list
+\o Null The blob has not yet been loaded by a QQmlDataLoader
+\o Loading The blob is loading network data. The QQmlDataBlob::setData() callback has not yet been
+invoked or has not yet returned.
+\o WaitingForDependencies The blob is waiting for dependencies to be done before continueing. This status
+only occurs after the QQmlDataBlob::setData() callback has been made, and when the blob has outstanding
+dependencies.
+\o Complete The blob's data has been loaded and all dependencies are done.
+\o Error An error has been set on this blob.
+\endlist
+*/
+
+/*!
+\enum QQmlDataBlob::Type
+
+This enum describes the type of the data blob.
+
+\list
+\o QmlFile This is a QQmlTypeData
+\o JavaScriptFile This is a QQmlScriptData
+\o QmldirFile This is a QQmlQmldirData
+\endlist
+*/
+
+/*!
+Create a new QQmlDataBlob for \a url and of the provided \a type.
+*/
+QQmlDataBlob::QQmlDataBlob(const QUrl &url, Type type)
+: m_type(type), m_url(url), m_finalUrl(url), m_manager(0), m_redirectCount(0),
+ m_inCallback(false), m_isDone(false)
+{
+}
+
+/*! \internal */
+QQmlDataBlob::~QQmlDataBlob()
+{
+ Q_ASSERT(m_waitingOnMe.isEmpty());
+
+ cancelAllWaitingFor();
+}
+
+/*!
+Returns the type provided to the constructor.
+*/
+QQmlDataBlob::Type QQmlDataBlob::type() const
+{
+ return m_type;
+}
+
+/*!
+Returns the blob's status.
+*/
+QQmlDataBlob::Status QQmlDataBlob::status() const
+{
+ return m_data.status();
+}
+
+/*!
+Returns true if the status is Null.
+*/
+bool QQmlDataBlob::isNull() const
+{
+ return status() == Null;
+}
+
+/*!
+Returns true if the status is Loading.
+*/
+bool QQmlDataBlob::isLoading() const
+{
+ return status() == Loading;
+}
+
+/*!
+Returns true if the status is WaitingForDependencies.
+*/
+bool QQmlDataBlob::isWaiting() const
+{
+ return status() == WaitingForDependencies;
+}
+
+/*!
+Returns true if the status is Complete.
+*/
+bool QQmlDataBlob::isComplete() const
+{
+ return status() == Complete;
+}
+
+/*!
+Returns true if the status is Error.
+*/
+bool QQmlDataBlob::isError() const
+{
+ return status() == Error;
+}
+
+/*!
+Returns true if the status is Complete or Error.
+*/
+bool QQmlDataBlob::isCompleteOrError() const
+{
+ Status s = status();
+ return s == Error || s == Complete;
+}
+
+/*!
+Returns the data download progress from 0 to 1.
+*/
+qreal QQmlDataBlob::progress() const
+{
+ quint8 p = m_data.progress();
+ if (p == 0xFF) return 1.;
+ else return qreal(p) / qreal(0xFF);
+}
+
+/*!
+Returns the blob url passed to the constructor. If a network redirect
+happens while fetching the data, this url remains the same.
+
+\sa finalUrl()
+*/
+QUrl QQmlDataBlob::url() const
+{
+ return m_url;
+}
+
+/*!
+Returns the final url of the data. Initially this is the same as
+url(), but if a network redirect happens while fetching the data, this url
+is updated to reflect the new location.
+
+May only be called from the load thread, or after the blob isCompleteOrError().
+*/
+QUrl QQmlDataBlob::finalUrl() const
+{
+ Q_ASSERT(isCompleteOrError() || (m_manager && m_manager->m_thread->isThisThread()));
+ return m_finalUrl;
+}
+
+/*!
+Returns the finalUrl() as a string.
+*/
+QString QQmlDataBlob::finalUrlString() const
+{
+ Q_ASSERT(isCompleteOrError() || (m_manager && m_manager->m_thread->isThisThread()));
+ if (m_finalUrlString.isEmpty())
+ m_finalUrlString = m_finalUrl.toString();
+
+ return m_finalUrlString;
+}
+
+/*!
+Return the errors on this blob.
+
+May only be called from the load thread, or after the blob isCompleteOrError().
+*/
+QList<QQmlError> QQmlDataBlob::errors() const
+{
+ Q_ASSERT(isCompleteOrError() || (m_manager && m_manager->m_thread->isThisThread()));
+ return m_errors;
+}
+
+/*!
+Mark this blob as having \a errors.
+
+All outstanding dependencies will be cancelled. Requests to add new dependencies
+will be ignored. Entry into the Error state is irreversable.
+
+The setError() method may only be called from within a QQmlDataBlob callback.
+*/
+void QQmlDataBlob::setError(const QQmlError &errors)
+{
+ ASSERT_CALLBACK();
+
+ QList<QQmlError> l;
+ l << errors;
+ setError(l);
+}
+
+/*!
+\overload
+*/
+void QQmlDataBlob::setError(const QList<QQmlError> &errors)
+{
+ ASSERT_CALLBACK();
+
+ Q_ASSERT(status() != Error);
+ Q_ASSERT(m_errors.isEmpty());
+
+ m_errors = errors; // Must be set before the m_data fence
+ m_data.setStatus(Error);
+
+ cancelAllWaitingFor();
+
+ if (!m_inCallback)
+ tryDone();
+}
+
+/*!
+Wait for \a blob to become complete or to error. If \a blob is already
+complete or in error, or this blob is already complete, this has no effect.
+
+The setError() method may only be called from within a QQmlDataBlob callback.
+*/
+void QQmlDataBlob::addDependency(QQmlDataBlob *blob)
+{
+ ASSERT_CALLBACK();
+
+ Q_ASSERT(status() != Null);
+
+ if (!blob ||
+ blob->status() == Error || blob->status() == Complete ||
+ status() == Error || status() == Complete || m_isDone ||
+ m_waitingFor.contains(blob))
+ return;
+
+ blob->addref();
+
+ m_data.setStatus(WaitingForDependencies);
+
+ m_waitingFor.append(blob);
+ blob->m_waitingOnMe.append(this);
+}
+
+/*!
+\fn void QQmlDataBlob::dataReceived(const QByteArray &data)
+
+Invoked when data for the blob is received. Implementors should use this callback
+to determine a blob's dependencies. Within this callback you may call setError()
+or addDependency().
+*/
+
+/*!
+Invoked once data has either been received or a network error occurred, and all
+dependencies are complete.
+
+You can set an error in this method, but you cannot add new dependencies. Implementors
+should use this callback to finalize processing of data.
+
+The default implementation does nothing.
+
+XXX Rename processData() or some such to avoid confusion between done() (processing thread)
+and completed() (main thread)
+*/
+void QQmlDataBlob::done()
+{
+}
+
+/*!
+Invoked if there is a network error while fetching this blob.
+
+The default implementation sets an appropriate QQmlError.
+*/
+void QQmlDataBlob::networkError(QNetworkReply::NetworkError networkError)
+{
+ Q_UNUSED(networkError);
+
+ QQmlError error;
+ error.setUrl(m_finalUrl);
+
+ const char *errorString = 0;
+ switch (networkError) {
+ default:
+ errorString = "Network error";
+ break;
+ case QNetworkReply::ConnectionRefusedError:
+ errorString = "Connection refused";
+ break;
+ case QNetworkReply::RemoteHostClosedError:
+ errorString = "Remote host closed the connection";
+ break;
+ case QNetworkReply::HostNotFoundError:
+ errorString = "Host not found";
+ break;
+ case QNetworkReply::TimeoutError:
+ errorString = "Timeout";
+ break;
+ case QNetworkReply::ProxyConnectionRefusedError:
+ case QNetworkReply::ProxyConnectionClosedError:
+ case QNetworkReply::ProxyNotFoundError:
+ case QNetworkReply::ProxyTimeoutError:
+ case QNetworkReply::ProxyAuthenticationRequiredError:
+ case QNetworkReply::UnknownProxyError:
+ errorString = "Proxy error";
+ break;
+ case QNetworkReply::ContentAccessDenied:
+ errorString = "Access denied";
+ break;
+ case QNetworkReply::ContentNotFoundError:
+ errorString = "File not found";
+ break;
+ case QNetworkReply::AuthenticationRequiredError:
+ errorString = "Authentication required";
+ break;
+ };
+
+ error.setDescription(QLatin1String(errorString));
+
+ setError(error);
+}
+
+/*!
+Called if \a blob, which was previously waited for, has an error.
+
+The default implementation does nothing.
+*/
+void QQmlDataBlob::dependencyError(QQmlDataBlob *blob)
+{
+ Q_UNUSED(blob);
+}
+
+/*!
+Called if \a blob, which was previously waited for, has completed.
+
+The default implementation does nothing.
+*/
+void QQmlDataBlob::dependencyComplete(QQmlDataBlob *blob)
+{
+ Q_UNUSED(blob);
+}
+
+/*!
+Called when all blobs waited for have completed. This occurs regardless of
+whether they are in error, or complete state.
+
+The default implementation does nothing.
+*/
+void QQmlDataBlob::allDependenciesDone()
+{
+}
+
+/*!
+Called when the download progress of this blob changes. \a progress goes
+from 0 to 1.
+
+This callback is only invoked if an asynchronous load for this blob is
+made. An asynchronous load is one in which the Asynchronous mode is
+specified explicitly, or one that is implicitly delayed due to a network
+operation.
+
+The default implementation does nothing.
+*/
+void QQmlDataBlob::downloadProgressChanged(qreal progress)
+{
+ Q_UNUSED(progress);
+}
+
+/*!
+Invoked on the main thread sometime after done() was called on the load thread.
+
+You cannot modify the blobs state at all in this callback and cannot depend on the
+order or timeliness of these callbacks. Implementors should use this callback to notify
+dependencies on the main thread that the blob is done and not a lot else.
+
+This callback is only invoked if an asynchronous load for this blob is
+made. An asynchronous load is one in which the Asynchronous mode is
+specified explicitly, or one that is implicitly delayed due to a network
+operation.
+
+The default implementation does nothing.
+*/
+void QQmlDataBlob::completed()
+{
+}
+
+
+void QQmlDataBlob::tryDone()
+{
+ if (status() != Loading && m_waitingFor.isEmpty() && !m_isDone) {
+ m_isDone = true;
+ addref();
+
+#ifdef DATABLOB_DEBUG
+ qWarning("QQmlDataBlob::done() %s", qPrintable(url().toString()));
+#endif
+ done();
+
+ if (status() != Error)
+ m_data.setStatus(Complete);
+
+ notifyAllWaitingOnMe();
+
+ // Locking is not required here, as anyone expecting callbacks must
+ // already be protected against the blob being completed (as set above);
+ if (m_data.isAsync()) {
+#ifdef DATABLOB_DEBUG
+ qWarning("QQmlDataBlob: Dispatching completed");
+#endif
+ m_manager->m_thread->callCompleted(this);
+ }
+
+ release();
+ }
+}
+
+void QQmlDataBlob::cancelAllWaitingFor()
+{
+ while (m_waitingFor.count()) {
+ QQmlDataBlob *blob = m_waitingFor.takeLast();
+
+ Q_ASSERT(blob->m_waitingOnMe.contains(this));
+
+ blob->m_waitingOnMe.removeOne(this);
+
+ blob->release();
+ }
+}
+
+void QQmlDataBlob::notifyAllWaitingOnMe()
+{
+ while (m_waitingOnMe.count()) {
+ QQmlDataBlob *blob = m_waitingOnMe.takeLast();
+
+ Q_ASSERT(blob->m_waitingFor.contains(this));
+
+ blob->notifyComplete(this);
+ }
+}
+
+void QQmlDataBlob::notifyComplete(QQmlDataBlob *blob)
+{
+ Q_ASSERT(m_waitingFor.contains(blob));
+ Q_ASSERT(blob->status() == Error || blob->status() == Complete);
+
+ m_inCallback = true;
+
+ if (blob->status() == Error) {
+ dependencyError(blob);
+ } else if (blob->status() == Complete) {
+ dependencyComplete(blob);
+ }
+
+ m_waitingFor.removeOne(blob);
+ blob->release();
+
+ if (!isError() && m_waitingFor.isEmpty())
+ allDependenciesDone();
+
+ m_inCallback = false;
+
+ tryDone();
+}
+
+#define TD_STATUS_MASK 0x0000FFFF
+#define TD_STATUS_SHIFT 0
+#define TD_PROGRESS_MASK 0x00FF0000
+#define TD_PROGRESS_SHIFT 16
+#define TD_ASYNC_MASK 0x80000000
+
+QQmlDataBlob::ThreadData::ThreadData()
+: _p(0)
+{
+}
+
+QQmlDataBlob::Status QQmlDataBlob::ThreadData::status() const
+{
+ return QQmlDataBlob::Status((_p.load() & TD_STATUS_MASK) >> TD_STATUS_SHIFT);
+}
+
+void QQmlDataBlob::ThreadData::setStatus(QQmlDataBlob::Status status)
+{
+ while (true) {
+ int d = _p.load();
+ int nd = (d & ~TD_STATUS_MASK) | ((status << TD_STATUS_SHIFT) & TD_STATUS_MASK);
+ if (d == nd || _p.testAndSetOrdered(d, nd)) return;
+ }
+}
+
+bool QQmlDataBlob::ThreadData::isAsync() const
+{
+ return _p.load() & TD_ASYNC_MASK;
+}
+
+void QQmlDataBlob::ThreadData::setIsAsync(bool v)
+{
+ while (true) {
+ int d = _p.load();
+ int nd = (d & ~TD_ASYNC_MASK) | (v?TD_ASYNC_MASK:0);
+ if (d == nd || _p.testAndSetOrdered(d, nd)) return;
+ }
+}
+
+quint8 QQmlDataBlob::ThreadData::progress() const
+{
+ return quint8((_p.load() & TD_PROGRESS_MASK) >> TD_PROGRESS_SHIFT);
+}
+
+void QQmlDataBlob::ThreadData::setProgress(quint8 v)
+{
+ while (true) {
+ int d = _p.load();
+ int nd = (d & ~TD_PROGRESS_MASK) | ((v << TD_PROGRESS_SHIFT) & TD_PROGRESS_MASK);
+ if (d == nd || _p.testAndSetOrdered(d, nd)) return;
+ }
+}
+
+QQmlDataLoaderThread::QQmlDataLoaderThread(QQmlDataLoader *loader)
+: m_loader(loader), m_networkAccessManager(0), m_networkReplyProxy(0)
+{
+}
+
+QNetworkAccessManager *QQmlDataLoaderThread::networkAccessManager() const
+{
+ Q_ASSERT(isThisThread());
+ if (!m_networkAccessManager) {
+ m_networkAccessManager = QQmlEnginePrivate::get(m_loader->engine())->createNetworkAccessManager(0);
+ m_networkReplyProxy = new QQmlDataLoaderNetworkReplyProxy(m_loader);
+ }
+
+ return m_networkAccessManager;
+}
+
+QQmlDataLoaderNetworkReplyProxy *QQmlDataLoaderThread::networkReplyProxy() const
+{
+ Q_ASSERT(isThisThread());
+ Q_ASSERT(m_networkReplyProxy); // Must call networkAccessManager() first
+ return m_networkReplyProxy;
+}
+
+void QQmlDataLoaderThread::load(QQmlDataBlob *b)
+{
+ b->addref();
+ callMethodInThread(&This::loadThread, b);
+}
+
+void QQmlDataLoaderThread::loadAsync(QQmlDataBlob *b)
+{
+ b->addref();
+ postMethodToThread(&This::loadThread, b);
+}
+
+void QQmlDataLoaderThread::loadWithStaticData(QQmlDataBlob *b, const QByteArray &d)
+{
+ b->addref();
+ callMethodInThread(&This::loadWithStaticDataThread, b, d);
+}
+
+void QQmlDataLoaderThread::loadWithStaticDataAsync(QQmlDataBlob *b, const QByteArray &d)
+{
+ b->addref();
+ postMethodToThread(&This::loadWithStaticDataThread, b, d);
+}
+
+void QQmlDataLoaderThread::callCompleted(QQmlDataBlob *b)
+{
+ b->addref();
+ postMethodToMain(&This::callCompletedMain, b);
+}
+
+void QQmlDataLoaderThread::callDownloadProgressChanged(QQmlDataBlob *b, qreal p)
+{
+ b->addref();
+ postMethodToMain(&This::callDownloadProgressChangedMain, b, p);
+}
+
+void QQmlDataLoaderThread::initializeEngine(QQmlExtensionInterface *iface,
+ const char *uri)
+{
+ callMethodInMain(&This::initializeEngineMain, iface, uri);
+}
+
+void QQmlDataLoaderThread::shutdownThread()
+{
+ delete m_networkAccessManager;
+ m_networkAccessManager = 0;
+ delete m_networkReplyProxy;
+ m_networkReplyProxy = 0;
+}
+
+void QQmlDataLoaderThread::loadThread(QQmlDataBlob *b)
+{
+ m_loader->loadThread(b);
+ b->release();
+}
+
+void QQmlDataLoaderThread::loadWithStaticDataThread(QQmlDataBlob *b, const QByteArray &d)
+{
+ m_loader->loadWithStaticDataThread(b, d);
+ b->release();
+}
+
+void QQmlDataLoaderThread::callCompletedMain(QQmlDataBlob *b)
+{
+#ifdef DATABLOB_DEBUG
+ qWarning("QQmlDataLoaderThread: %s completed() callback", qPrintable(b->url().toString()));
+#endif
+ b->completed();
+ b->release();
+}
+
+void QQmlDataLoaderThread::callDownloadProgressChangedMain(QQmlDataBlob *b, qreal p)
+{
+#ifdef DATABLOB_DEBUG
+ qWarning("QQmlDataLoaderThread: %s downloadProgressChanged(%f) callback",
+ qPrintable(b->url().toString()), p);
+#endif
+ b->downloadProgressChanged(p);
+ b->release();
+}
+
+void QQmlDataLoaderThread::initializeEngineMain(QQmlExtensionInterface *iface,
+ const char *uri)
+{
+ Q_ASSERT(m_loader->engine()->thread() == QThread::currentThread());
+ iface->initializeEngine(m_loader->engine(), uri);
+}
+
+/*!
+\class QQmlDataLoader
+\brief The QQmlDataLoader class abstracts loading files and their dependencies over the network.
+\internal
+
+The QQmlDataLoader class is provided for the exclusive use of the QQmlTypeLoader class.
+
+Clients create QQmlDataBlob instances and submit them to the QQmlDataLoader class
+through the QQmlDataLoader::load() or QQmlDataLoader::loadWithStaticData() methods.
+The loader then fetches the data over the network or from the local file system in an efficient way.
+QQmlDataBlob is an abstract class, so should always be specialized.
+
+Once data is received, the QQmlDataBlob::dataReceived() method is invoked on the blob. The
+derived class should use this callback to process the received data. Processing of the data can
+result in an error being set (QQmlDataBlob::setError()), or one or more dependencies being
+created (QQmlDataBlob::addDependency()). Dependencies are other QQmlDataBlob's that
+are required before processing can fully complete.
+
+To complete processing, the QQmlDataBlob::done() callback is invoked. done() is called when
+one of these three preconditions are met.
+
+\list 1
+\o The QQmlDataBlob has no dependencies.
+\o The QQmlDataBlob has an error set.
+\o All the QQmlDataBlob's dependencies are themselves "done()".
+\endlist
+
+Thus QQmlDataBlob::done() will always eventually be called, even if the blob has an error set.
+*/
+
+/*!
+Create a new QQmlDataLoader for \a engine.
+*/
+QQmlDataLoader::QQmlDataLoader(QQmlEngine *engine)
+: m_engine(engine), m_thread(new QQmlDataLoaderThread(this))
+{
+}
+
+/*! \internal */
+QQmlDataLoader::~QQmlDataLoader()
+{
+ for (NetworkReplies::Iterator iter = m_networkReplies.begin(); iter != m_networkReplies.end(); ++iter)
+ (*iter)->release();
+
+ m_thread->shutdown();
+ delete m_thread;
+}
+
+void QQmlDataLoader::lock()
+{
+ m_thread->lock();
+}
+
+void QQmlDataLoader::unlock()
+{
+ m_thread->unlock();
+}
+
+/*!
+Load the provided \a blob from the network or filesystem.
+
+The loader must be locked.
+*/
+void QQmlDataLoader::load(QQmlDataBlob *blob, Mode mode)
+{
+#ifdef DATABLOB_DEBUG
+ qWarning("QQmlDataLoader::load(%s): %s thread", qPrintable(blob->m_url.toString()),
+ m_thread->isThisThread()?"Compile":"Engine");
+#endif
+
+ Q_ASSERT(blob->status() == QQmlDataBlob::Null);
+ Q_ASSERT(blob->m_manager == 0);
+
+ blob->m_data.setStatus(QQmlDataBlob::Loading);
+ blob->m_manager = this;
+
+ if (m_thread->isThisThread()) {
+ unlock();
+ loadThread(blob);
+ lock();
+ } else if (mode == PreferSynchronous) {
+ unlock();
+ m_thread->load(blob);
+ lock();
+ if (!blob->isCompleteOrError())
+ blob->m_data.setIsAsync(true);
+ } else {
+ Q_ASSERT(mode == Asynchronous);
+ blob->m_data.setIsAsync(true);
+ unlock();
+ m_thread->loadAsync(blob);
+ lock();
+ }
+}
+
+/*!
+Load the provided \a blob with \a data. The blob's URL is not used by the data loader in this case.
+
+The loader must be locked.
+*/
+void QQmlDataLoader::loadWithStaticData(QQmlDataBlob *blob, const QByteArray &data, Mode mode)
+{
+#ifdef DATABLOB_DEBUG
+ qWarning("QQmlDataLoader::loadWithStaticData(%s, data): %s thread", qPrintable(blob->m_url.toString()),
+ m_thread->isThisThread()?"Compile":"Engine");
+#endif
+
+ Q_ASSERT(blob->status() == QQmlDataBlob::Null);
+ Q_ASSERT(blob->m_manager == 0);
+
+ blob->m_data.setStatus(QQmlDataBlob::Loading);
+ blob->m_manager = this;
+
+ if (m_thread->isThisThread()) {
+ unlock();
+ loadWithStaticDataThread(blob, data);
+ lock();
+ } else if (mode == PreferSynchronous) {
+ unlock();
+ m_thread->loadWithStaticData(blob, data);
+ lock();
+ if (!blob->isCompleteOrError())
+ blob->m_data.setIsAsync(true);
+ } else {
+ Q_ASSERT(mode == Asynchronous);
+ blob->m_data.setIsAsync(true);
+ unlock();
+ m_thread->loadWithStaticDataAsync(blob, data);
+ lock();
+ }
+}
+
+void QQmlDataLoader::loadWithStaticDataThread(QQmlDataBlob *blob, const QByteArray &data)
+{
+ ASSERT_LOADTHREAD();
+
+ setData(blob, data);
+}
+
+void QQmlDataLoader::loadThread(QQmlDataBlob *blob)
+{
+ ASSERT_LOADTHREAD();
+
+ if (blob->m_url.isEmpty()) {
+ QQmlError error;
+ error.setDescription(QLatin1String("Invalid null URL"));
+ blob->setError(error);
+ return;
+ }
+
+ QString lf = QQmlEnginePrivate::urlToLocalFileOrQrc(blob->m_url);
+
+ if (!lf.isEmpty()) {
+ if (!QQml_isFileCaseCorrect(lf)) {
+ QQmlError error;
+ error.setUrl(blob->m_url);
+ error.setDescription(QLatin1String("File name case mismatch"));
+ blob->setError(error);
+ return;
+ }
+ QFile file(lf);
+ if (file.open(QFile::ReadOnly)) {
+ QByteArray data = file.readAll();
+
+ blob->m_data.setProgress(0xFF);
+ if (blob->m_data.isAsync())
+ m_thread->callDownloadProgressChanged(blob, 1.);
+
+ setData(blob, data);
+ } else {
+ blob->networkError(QNetworkReply::ContentNotFoundError);
+ }
+
+ } else {
+
+ QNetworkReply *reply = m_thread->networkAccessManager()->get(QNetworkRequest(blob->m_url));
+ QObject *nrp = m_thread->networkReplyProxy();
+ QObject::connect(reply, SIGNAL(downloadProgress(qint64,qint64)),
+ nrp, SLOT(downloadProgress(qint64,qint64)));
+ QObject::connect(reply, SIGNAL(finished()),
+ nrp, SLOT(finished()));
+ m_networkReplies.insert(reply, blob);
+
+ blob->addref();
+ }
+}
+
+#define DATALOADER_MAXIMUM_REDIRECT_RECURSION 16
+
+void QQmlDataLoader::networkReplyFinished(QNetworkReply *reply)
+{
+ Q_ASSERT(m_thread->isThisThread());
+
+ reply->deleteLater();
+
+ QQmlDataBlob *blob = m_networkReplies.take(reply);
+
+ Q_ASSERT(blob);
+
+ blob->m_redirectCount++;
+
+ if (blob->m_redirectCount < DATALOADER_MAXIMUM_REDIRECT_RECURSION) {
+ QVariant redirect = reply->attribute(QNetworkRequest::RedirectionTargetAttribute);
+ if (redirect.isValid()) {
+ QUrl url = reply->url().resolved(redirect.toUrl());
+ blob->m_finalUrl = url;
+
+ QNetworkReply *reply = m_thread->networkAccessManager()->get(QNetworkRequest(url));
+ QObject *nrp = m_thread->networkReplyProxy();
+ QObject::connect(reply, SIGNAL(finished()), nrp, SLOT(finished()));
+ m_networkReplies.insert(reply, blob);
+ return;
+ }
+ }
+
+ if (reply->error()) {
+ blob->networkError(reply->error());
+ } else {
+ QByteArray data = reply->readAll();
+ setData(blob, data);
+ }
+
+ blob->release();
+}
+
+void QQmlDataLoader::networkReplyProgress(QNetworkReply *reply,
+ qint64 bytesReceived, qint64 bytesTotal)
+{
+ Q_ASSERT(m_thread->isThisThread());
+
+ QQmlDataBlob *blob = m_networkReplies.value(reply);
+
+ Q_ASSERT(blob);
+
+ if (bytesTotal != 0) {
+ quint8 progress = 0xFF * (qreal(bytesReceived) / qreal(bytesTotal));
+ blob->m_data.setProgress(progress);
+ if (blob->m_data.isAsync())
+ m_thread->callDownloadProgressChanged(blob, blob->m_data.progress());
+ }
+}
+
+/*!
+Return the QQmlEngine associated with this loader
+*/
+QQmlEngine *QQmlDataLoader::engine() const
+{
+ return m_engine;
+}
+
+/*!
+Call the initializeEngine() method on \a iface. Used by QQmlImportDatabase to ensure it
+gets called in the correct thread.
+*/
+void QQmlDataLoader::initializeEngine(QQmlExtensionInterface *iface,
+ const char *uri)
+{
+ Q_ASSERT(m_thread->isThisThread() || engine()->thread() == QThread::currentThread());
+
+ if (m_thread->isThisThread()) {
+ m_thread->initializeEngine(iface, uri);
+ } else {
+ Q_ASSERT(engine()->thread() == QThread::currentThread());
+ iface->initializeEngine(engine(), uri);
+ }
+}
+
+
+void QQmlDataLoader::setData(QQmlDataBlob *blob, const QByteArray &data)
+{
+ blob->m_inCallback = true;
+
+ blob->dataReceived(data);
+
+ if (!blob->isError() && !blob->isWaiting())
+ blob->allDependenciesDone();
+
+ if (blob->status() != QQmlDataBlob::Error)
+ blob->m_data.setStatus(QQmlDataBlob::WaitingForDependencies);
+
+ blob->m_inCallback = false;
+
+ blob->tryDone();
+}
+
+/*!
+Constructs a new type loader that uses the given \a engine.
+*/
+QQmlTypeLoader::QQmlTypeLoader(QQmlEngine *engine)
+: QQmlDataLoader(engine)
+{
+}
+
+/*!
+Destroys the type loader, first clearing the cache of any information about
+loaded files.
+*/
+QQmlTypeLoader::~QQmlTypeLoader()
+{
+ clearCache();
+}
+
+/*!
+\enum QQmlTypeLoader::Option
+
+This enum defines the options that control the way type data is handled.
+
+\value None The default value, indicating that no other options
+ are enabled.
+\value PreserveParser The parser used to handle the type data is preserved
+ after the data has been parsed.
+*/
+
+/*!
+Returns a QQmlTypeData for the specified \a url. The QQmlTypeData may be cached.
+*/
+QQmlTypeData *QQmlTypeLoader::get(const QUrl &url)
+{
+ Q_ASSERT(!url.isRelative() &&
+ (QQmlEnginePrivate::urlToLocalFileOrQrc(url).isEmpty() ||
+ !QDir::isRelativePath(QQmlEnginePrivate::urlToLocalFileOrQrc(url))));
+
+ lock();
+
+ QQmlTypeData *typeData = m_typeCache.value(url);
+
+ if (!typeData) {
+ typeData = new QQmlTypeData(url, None, this);
+ m_typeCache.insert(url, typeData);
+ QQmlDataLoader::load(typeData);
+ }
+
+ typeData->addref();
+
+ unlock();
+
+ return typeData;
+}
+
+/*!
+Returns a QQmlTypeData for the given \a data with the provided base \a url. The
+QQmlTypeData will not be cached.
+
+The specified \a options control how the loader handles type data.
+*/
+QQmlTypeData *QQmlTypeLoader::get(const QByteArray &data, const QUrl &url, Options options)
+{
+ lock();
+
+ QQmlTypeData *typeData = new QQmlTypeData(url, options, this);
+ QQmlDataLoader::loadWithStaticData(typeData, data);
+
+ unlock();
+
+ return typeData;
+}
+
+/*!
+Return a QQmlScriptBlob for \a url. The QQmlScriptData may be cached.
+*/
+QQmlScriptBlob *QQmlTypeLoader::getScript(const QUrl &url)
+{
+ Q_ASSERT(!url.isRelative() &&
+ (QQmlEnginePrivate::urlToLocalFileOrQrc(url).isEmpty() ||
+ !QDir::isRelativePath(QQmlEnginePrivate::urlToLocalFileOrQrc(url))));
+
+ lock();
+
+ QQmlScriptBlob *scriptBlob = m_scriptCache.value(url);
+
+ if (!scriptBlob) {
+ scriptBlob = new QQmlScriptBlob(url, this);
+ m_scriptCache.insert(url, scriptBlob);
+ QQmlDataLoader::load(scriptBlob);
+ }
+
+ scriptBlob->addref();
+
+ unlock();
+
+ return scriptBlob;
+}
+
+/*!
+Returns a QQmlQmldirData for \a url. The QQmlQmldirData may be cached.
+*/
+QQmlQmldirData *QQmlTypeLoader::getQmldir(const QUrl &url)
+{
+ Q_ASSERT(!url.isRelative() &&
+ (QQmlEnginePrivate::urlToLocalFileOrQrc(url).isEmpty() ||
+ !QDir::isRelativePath(QQmlEnginePrivate::urlToLocalFileOrQrc(url))));
+
+ lock();
+
+ QQmlQmldirData *qmldirData = m_qmldirCache.value(url);
+
+ if (!qmldirData) {
+ qmldirData = new QQmlQmldirData(url);
+ m_qmldirCache.insert(url, qmldirData);
+ QQmlDataLoader::load(qmldirData);
+ }
+
+ qmldirData->addref();
+
+ unlock();
+
+ return qmldirData;
+}
+
+/*!
+Returns the absolute filename of path via a directory cache for files named
+"qmldir", "*.qml", "*.js", and plugins.
+Returns a empty string if the path does not exist.
+*/
+QString QQmlTypeLoader::absoluteFilePath(const QString &path)
+{
+ if (path.isEmpty())
+ return QString();
+ if (path.at(0) == QLatin1Char(':')) {
+ // qrc resource
+ QFileInfo fileInfo(path);
+ return fileInfo.isFile() ? fileInfo.absoluteFilePath() : QString();
+ }
+#if defined(Q_OS_WIN32) || defined(Q_OS_WINCE) || defined(Q_OS_DARWIN)
+ QString lowPath = path.toLower();
+ int lastSlash = lowPath.lastIndexOf(QLatin1Char('/'));
+ QString dirPath = lowPath.left(lastSlash);
+#else
+ int lastSlash = path.lastIndexOf(QLatin1Char('/'));
+ QStringRef dirPath(&path, 0, lastSlash);
+#endif
+
+ StringSet **fileSet = m_importDirCache.value(QHashedStringRef(dirPath.constData(), dirPath.length()));
+ if (!fileSet) {
+#if defined(Q_OS_WIN32) || defined(Q_OS_WINCE) || defined(Q_OS_DARWIN)
+ QHashedString dirPathString(dirPath);
+#else
+ QHashedString dirPathString(dirPath.toString());
+#endif
+ StringSet *files = qmlFilesInDirectory(dirPathString);
+ m_importDirCache.insert(dirPathString, files);
+ fileSet = m_importDirCache.value(dirPathString);
+ }
+ if (!(*fileSet))
+ return QString();
+
+#if defined(Q_OS_WIN32) || defined(Q_OS_WINCE) || defined(Q_OS_DARWIN)
+ QString absoluteFilePath = (*fileSet)->contains(QHashedStringRef(lowPath.constData()+lastSlash+1, lowPath.length()-lastSlash-1)) ? path : QString();
+#else
+ QString absoluteFilePath = (*fileSet)->contains(QHashedStringRef(path.constData()+lastSlash+1, path.length()-lastSlash-1)) ? path : QString();
+#endif
+ if (absoluteFilePath.length() > 2 && absoluteFilePath.at(0) != QLatin1Char('/') && absoluteFilePath.at(1) != QLatin1Char(':'))
+ absoluteFilePath = QFileInfo(absoluteFilePath).absoluteFilePath();
+
+ return absoluteFilePath;
+}
+
+/*!
+Returns true if the path is a directory via a directory cache. Cache is
+shared with absoluteFilePath().
+*/
+bool QQmlTypeLoader::directoryExists(const QString &path)
+{
+ if (path.isEmpty())
+ return false;
+ if (path.at(0) == QLatin1Char(':')) {
+ // qrc resource
+ QFileInfo fileInfo(path);
+ return fileInfo.exists() && fileInfo.isDir();
+ }
+
+ int length = path.length();
+ if (path.endsWith(QLatin1Char('/')))
+ --length;
+#if defined(Q_OS_WIN32) || defined(Q_OS_WINCE) || defined(Q_OS_DARWIN)
+ QString dirPath = path.left(length).toLower();
+#else
+ QStringRef dirPath(&path, 0, length);
+#endif
+
+ StringSet **fileSet = m_importDirCache.value(QHashedStringRef(dirPath.constData(), dirPath.length()));
+ if (!fileSet) {
+#if defined(Q_OS_WIN32) || defined(Q_OS_WINCE) || defined(Q_OS_DARWIN)
+ QHashedString dirPathString(dirPath);
+#else
+ QHashedString dirPathString(dirPath.toString());
+#endif
+ StringSet *files = qmlFilesInDirectory(dirPathString);
+ m_importDirCache.insert(dirPathString, files);
+ fileSet = m_importDirCache.value(dirPathString);
+ }
+
+ return (*fileSet);
+}
+
+
+/*!
+Return a QQmlDirParser for absoluteFilePath. The QQmlDirParser may be cached.
+*/
+const QQmlDirParser *QQmlTypeLoader::qmlDirParser(const QString &absoluteFilePath)
+{
+ QQmlDirParser *qmldirParser;
+ QQmlDirParser **val = m_importQmlDirCache.value(absoluteFilePath);
+ if (!val) {
+ qmldirParser = new QQmlDirParser;
+ qmldirParser->setFileSource(absoluteFilePath);
+ qmldirParser->setUrl(QUrl::fromLocalFile(absoluteFilePath));
+ qmldirParser->parse();
+ m_importQmlDirCache.insert(absoluteFilePath, qmldirParser);
+ } else {
+ qmldirParser = *val;
+ }
+
+ return qmldirParser;
+}
+
+
+/*!
+Clears cached information about loaded files, including any type data, scripts
+and qmldir information.
+*/
+void QQmlTypeLoader::clearCache()
+{
+ for (TypeCache::Iterator iter = m_typeCache.begin(); iter != m_typeCache.end(); ++iter)
+ (*iter)->release();
+ for (ScriptCache::Iterator iter = m_scriptCache.begin(); iter != m_scriptCache.end(); ++iter)
+ (*iter)->release();
+ for (QmldirCache::Iterator iter = m_qmldirCache.begin(); iter != m_qmldirCache.end(); ++iter)
+ (*iter)->release();
+ qDeleteAll(m_importDirCache);
+ qDeleteAll(m_importQmlDirCache);
+
+ m_typeCache.clear();
+ m_scriptCache.clear();
+ m_qmldirCache.clear();
+ m_importDirCache.clear();
+ m_importQmlDirCache.clear();
+}
+
+
+QQmlTypeData::QQmlTypeData(const QUrl &url, QQmlTypeLoader::Options options,
+ QQmlTypeLoader *manager)
+: QQmlDataBlob(url, QmlFile), m_options(options), m_imports(manager), m_typesResolved(false),
+ m_compiledData(0), m_typeLoader(manager)
+{
+}
+
+QQmlTypeData::~QQmlTypeData()
+{
+ for (int ii = 0; ii < m_scripts.count(); ++ii)
+ m_scripts.at(ii).script->release();
+ for (int ii = 0; ii < m_qmldirs.count(); ++ii)
+ m_qmldirs.at(ii)->release();
+ for (int ii = 0; ii < m_types.count(); ++ii)
+ if (m_types.at(ii).typeData) m_types.at(ii).typeData->release();
+ if (m_compiledData)
+ m_compiledData->release();
+}
+
+QQmlTypeLoader *QQmlTypeData::typeLoader() const
+{
+ return m_typeLoader;
+}
+
+const QQmlImports &QQmlTypeData::imports() const
+{
+ return m_imports;
+}
+
+const QQmlScript::Parser &QQmlTypeData::parser() const
+{
+ return scriptParser;
+}
+
+const QList<QQmlTypeData::TypeReference> &QQmlTypeData::resolvedTypes() const
+{
+ return m_types;
+}
+
+const QList<QQmlTypeData::ScriptReference> &QQmlTypeData::resolvedScripts() const
+{
+ return m_scripts;
+}
+
+const QSet<QString> &QQmlTypeData::namespaces() const
+{
+ return m_namespaces;
+}
+
+QQmlCompiledData *QQmlTypeData::compiledData() const
+{
+ if (m_compiledData)
+ m_compiledData->addref();
+
+ return m_compiledData;
+}
+
+void QQmlTypeData::registerCallback(TypeDataCallback *callback)
+{
+ Q_ASSERT(!m_callbacks.contains(callback));
+ m_callbacks.append(callback);
+}
+
+void QQmlTypeData::unregisterCallback(TypeDataCallback *callback)
+{
+ Q_ASSERT(m_callbacks.contains(callback));
+ m_callbacks.removeOne(callback);
+ Q_ASSERT(!m_callbacks.contains(callback));
+}
+
+void QQmlTypeData::done()
+{
+ // Check all script dependencies for errors
+ for (int ii = 0; !isError() && ii < m_scripts.count(); ++ii) {
+ const ScriptReference &script = m_scripts.at(ii);
+ Q_ASSERT(script.script->isCompleteOrError());
+ if (script.script->isError()) {
+ QList<QQmlError> errors = script.script->errors();
+ QQmlError error;
+ error.setUrl(finalUrl());
+ error.setLine(script.location.line);
+ error.setColumn(script.location.column);
+ error.setDescription(QQmlTypeLoader::tr("Script %1 unavailable").arg(script.script->url().toString()));
+ errors.prepend(error);
+ setError(errors);
+ }
+ }
+
+ // Check all type dependencies for errors
+ for (int ii = 0; !isError() && ii < m_types.count(); ++ii) {
+ const TypeReference &type = m_types.at(ii);
+ Q_ASSERT(!type.typeData || type.typeData->isCompleteOrError());
+ if (type.typeData && type.typeData->isError()) {
+ QString typeName = scriptParser.referencedTypes().at(ii)->name;
+
+ QList<QQmlError> errors = type.typeData->errors();
+ QQmlError error;
+ error.setUrl(finalUrl());
+ error.setLine(type.location.line);
+ error.setColumn(type.location.column);
+ error.setDescription(QQmlTypeLoader::tr("Type %1 unavailable").arg(typeName));
+ errors.prepend(error);
+ setError(errors);
+ }
+ }
+
+ // Compile component
+ if (!isError())
+ compile();
+
+ if (!(m_options & QQmlTypeLoader::PreserveParser))
+ scriptParser.clear();
+}
+
+void QQmlTypeData::completed()
+{
+ // Notify callbacks
+ while (!m_callbacks.isEmpty()) {
+ TypeDataCallback *callback = m_callbacks.takeFirst();
+ callback->typeDataReady(this);
+ }
+}
+
+void QQmlTypeData::dataReceived(const QByteArray &data)
+{
+ if (!scriptParser.parse(data, finalUrl(), finalUrlString())) {
+ setError(scriptParser.errors());
+ return;
+ }
+
+ m_imports.setBaseUrl(finalUrl(), finalUrlString());
+
+ foreach (const QQmlScript::Import &import, scriptParser.imports()) {
+ if (import.type == QQmlScript::Import::File && import.qualifier.isEmpty()) {
+ QUrl importUrl = finalUrl().resolved(QUrl(import.uri + QLatin1String("/qmldir")));
+ if (QQmlEnginePrivate::urlToLocalFileOrQrc(importUrl).isEmpty()) {
+ QQmlQmldirData *data = typeLoader()->getQmldir(importUrl);
+ addDependency(data);
+ m_qmldirs << data;
+ }
+ } else if (import.type == QQmlScript::Import::Script) {
+ QUrl scriptUrl = finalUrl().resolved(QUrl(import.uri));
+ QQmlScriptBlob *blob = typeLoader()->getScript(scriptUrl);
+ addDependency(blob);
+
+ ScriptReference ref;
+ ref.location = import.location.start;
+ ref.qualifier = import.qualifier;
+ ref.script = blob;
+ m_scripts << ref;
+
+ }
+ }
+
+ if (!finalUrl().scheme().isEmpty()) {
+ QUrl importUrl = finalUrl().resolved(QUrl(QLatin1String("qmldir")));
+ if (QQmlEnginePrivate::urlToLocalFileOrQrc(importUrl).isEmpty()) {
+ QQmlQmldirData *data = typeLoader()->getQmldir(importUrl);
+ addDependency(data);
+ m_qmldirs << data;
+ }
+ }
+}
+
+void QQmlTypeData::allDependenciesDone()
+{
+ if (!m_typesResolved) {
+ resolveTypes();
+ m_typesResolved = true;
+ }
+}
+
+void QQmlTypeData::downloadProgressChanged(qreal p)
+{
+ for (int ii = 0; ii < m_callbacks.count(); ++ii) {
+ TypeDataCallback *callback = m_callbacks.at(ii);
+ callback->typeDataProgress(this, p);
+ }
+}
+
+void QQmlTypeData::compile()
+{
+ Q_ASSERT(m_compiledData == 0);
+ QQmlProfilerService::startRange(QQmlProfilerService::Compiling);
+
+ m_compiledData = new QQmlCompiledData(typeLoader()->engine());
+ m_compiledData->url = finalUrl();
+ m_compiledData->name = finalUrlString();
+ QQmlProfilerService::rangeLocation(QQmlProfilerService::Compiling, QUrl(m_compiledData->name),1,1);
+ QQmlProfilerService::rangeData(QQmlProfilerService::Compiling, m_compiledData->name);
+
+ QQmlCompiler compiler(&scriptParser._pool);
+ if (!compiler.compile(typeLoader()->engine(), this, m_compiledData)) {
+ setError(compiler.errors());
+ m_compiledData->release();
+ m_compiledData = 0;
+ }
+ QQmlProfilerService::endRange(QQmlProfilerService::Compiling);
+}
+
+void QQmlTypeData::resolveTypes()
+{
+ QQmlEnginePrivate *ep = QQmlEnginePrivate::get(m_typeLoader->engine());
+ QQmlImportDatabase *importDatabase = &ep->importDatabase;
+
+ // For local urls, add an implicit import "." as first (most overridden) lookup.
+ // This will also trigger the loading of the qmldir and the import of any native
+ // types from available plugins.
+ QList<QQmlError> errors;
+ if (QQmlQmldirData *qmldir = qmldirForUrl(finalUrl().resolved(QUrl(QLatin1String("./qmldir"))))) {
+ m_imports.addImport(importDatabase, QLatin1String("."),
+ QString(), -1, -1, QQmlScript::Import::File,
+ qmldir->dirComponents(), &errors);
+ } else {
+ m_imports.addImport(importDatabase, QLatin1String("."),
+ QString(), -1, -1, QQmlScript::Import::File,
+ QQmlDirComponents(), &errors);
+ }
+
+ // remove any errors which are due to the implicit import which aren't real errors.
+ // for example, if the implicitly included qmldir file doesn't exist, that is not an error.
+ QList<QQmlError> realErrors;
+ for (int i = 0; i < errors.size(); ++i) {
+ if (errors.at(i).description() != QQmlImportDatabase::tr("import \".\" has no qmldir and no namespace")
+ && errors.at(i).description() != QQmlImportDatabase::tr("\".\": no such directory")) {
+ realErrors.prepend(errors.at(i)); // this is a real error.
+ }
+ }
+
+ // report any real errors which occurred during plugin loading or qmldir parsing.
+ if (!realErrors.isEmpty()) {
+ setError(realErrors);
+ return;
+ }
+
+ foreach (const QQmlScript::Import &import, scriptParser.imports()) {
+ QQmlDirComponents qmldircomponentsnetwork;
+ if (import.type == QQmlScript::Import::Script)
+ continue;
+
+ if (import.type == QQmlScript::Import::File && import.qualifier.isEmpty()) {
+ QUrl qmldirUrl = finalUrl().resolved(QUrl(import.uri + QLatin1String("/qmldir")));
+ if (QQmlQmldirData *qmldir = qmldirForUrl(qmldirUrl))
+ qmldircomponentsnetwork = qmldir->dirComponents();
+ }
+
+ int vmaj = -1;
+ int vmin = -1;
+ import.extractVersion(&vmaj, &vmin);
+
+ QList<QQmlError> errors;
+ if (!m_imports.addImport(importDatabase, import.uri, import.qualifier,
+ vmaj, vmin, import.type, qmldircomponentsnetwork, &errors)) {
+ QQmlError error;
+ if (errors.size()) {
+ error = errors.takeFirst();
+ } else {
+ // this should not be possible!
+ // Description should come from error provided by addImport() function.
+ error.setDescription(QQmlTypeLoader::tr("Unreported error adding script import to import database"));
+ }
+ error.setUrl(m_imports.baseUrl());
+ error.setLine(import.location.start.line);
+ error.setColumn(import.location.start.column);
+ errors.prepend(error); // put it back on the list after filling out information.
+
+ setError(errors);
+ return;
+ }
+ }
+
+ // Add any imported scripts to our resolved set
+ foreach (const QQmlImports::ScriptReference &script, m_imports.resolvedScripts())
+ {
+ QQmlScriptBlob *blob = typeLoader()->getScript(script.location);
+ addDependency(blob);
+
+ ScriptReference ref;
+ //ref.location = ...
+ ref.qualifier = script.nameSpace;
+ if (!script.qualifier.isEmpty())
+ {
+ ref.qualifier.prepend(script.qualifier + QLatin1Char('.'));
+
+ // Add a reference to the enclosing namespace
+ m_namespaces.insert(script.qualifier);
+ }
+
+ ref.script = blob;
+ m_scripts << ref;
+ }
+
+ foreach (QQmlScript::TypeReference *parserRef, scriptParser.referencedTypes()) {
+ TypeReference ref;
+
+ QString url;
+ int majorVersion;
+ int minorVersion;
+ QQmlImportedNamespace *typeNamespace = 0;
+ QList<QQmlError> errors;
+
+ if (!m_imports.resolveType(parserRef->name, &ref.type, &url, &majorVersion, &minorVersion,
+ &typeNamespace, &errors) || typeNamespace) {
+ // Known to not be a type:
+ // - known to be a namespace (Namespace {})
+ // - type with unknown namespace (UnknownNamespace.SomeType {})
+ QQmlError error;
+ QString userTypeName = parserRef->name;
+ userTypeName.replace(QLatin1Char('/'),QLatin1Char('.'));
+ if (typeNamespace) {
+ error.setDescription(QQmlTypeLoader::tr("Namespace %1 cannot be used as a type").arg(userTypeName));
+ } else {
+ if (errors.size()) {
+ error = errors.takeFirst();
+ } else {
+ // this should not be possible!
+ // Description should come from error provided by addImport() function.
+ error.setDescription(QQmlTypeLoader::tr("Unreported error adding script import to import database"));
+ }
+ error.setUrl(m_imports.baseUrl());
+ error.setDescription(QQmlTypeLoader::tr("%1 %2").arg(userTypeName).arg(error.description()));
+ }
+
+ if (!parserRef->refObjects.isEmpty()) {
+ QQmlScript::Object *obj = parserRef->refObjects.first();
+ error.setLine(obj->location.start.line);
+ error.setColumn(obj->location.start.column);
+ }
+
+ errors.prepend(error);
+ setError(errors);
+ return;
+ }
+
+ if (ref.type) {
+ ref.majorVersion = majorVersion;
+ ref.minorVersion = minorVersion;
+ } else {
+ ref.typeData = typeLoader()->get(QUrl(url));
+ addDependency(ref.typeData);
+ }
+
+ if (parserRef->refObjects.count())
+ ref.location = parserRef->refObjects.first()->location.start;
+
+ m_types << ref;
+ }
+}
+
+QQmlQmldirData *QQmlTypeData::qmldirForUrl(const QUrl &url)
+{
+ for (int ii = 0; ii < m_qmldirs.count(); ++ii) {
+ if (m_qmldirs.at(ii)->url() == url)
+ return m_qmldirs.at(ii);
+ }
+ return 0;
+}
+
+QQmlScriptData::QQmlScriptData()
+: importCache(0), pragmas(QQmlScript::Object::ScriptBlock::None), m_loaded(false)
+{
+}
+
+QQmlScriptData::~QQmlScriptData()
+{
+}
+
+void QQmlScriptData::clear()
+{
+ if (importCache) {
+ importCache->release();
+ importCache = 0;
+ }
+
+ for (int ii = 0; ii < scripts.count(); ++ii)
+ scripts.at(ii)->release();
+ scripts.clear();
+
+ qPersistentDispose(m_program);
+ qPersistentDispose(m_value);
+
+ // An addref() was made when the QQmlCleanup was added to the engine.
+ release();
+}
+
+QQmlScriptBlob::QQmlScriptBlob(const QUrl &url, QQmlTypeLoader *loader)
+: QQmlDataBlob(url, JavaScriptFile), m_pragmas(QQmlScript::Object::ScriptBlock::None),
+ m_imports(loader), m_scriptData(0), m_typeLoader(loader)
+{
+}
+
+QQmlScriptBlob::~QQmlScriptBlob()
+{
+ if (m_scriptData) {
+ m_scriptData->release();
+ m_scriptData = 0;
+ }
+}
+
+QQmlScript::Object::ScriptBlock::Pragmas QQmlScriptBlob::pragmas() const
+{
+ return m_pragmas;
+}
+
+QQmlTypeLoader *QQmlScriptBlob::typeLoader() const
+{
+ return m_typeLoader;
+}
+
+const QQmlImports &QQmlScriptBlob::imports() const
+{
+ return m_imports;
+}
+
+QQmlScriptData *QQmlScriptBlob::scriptData() const
+{
+ return m_scriptData;
+}
+
+void QQmlScriptBlob::dataReceived(const QByteArray &data)
+{
+ QQmlEnginePrivate *ep = QQmlEnginePrivate::get(m_typeLoader->engine());
+ QQmlImportDatabase *importDatabase = &ep->importDatabase;
+
+ m_source = QString::fromUtf8(data);
+
+ QQmlScript::Parser::JavaScriptMetaData metadata =
+ QQmlScript::Parser::extractMetaData(m_source);
+
+ m_imports.setBaseUrl(finalUrl(), finalUrlString());
+
+ m_pragmas = metadata.pragmas;
+
+ foreach (const QQmlScript::Import &import, metadata.imports) {
+ Q_ASSERT(import.type != QQmlScript::Import::File);
+
+ if (import.type == QQmlScript::Import::Script) {
+ QUrl scriptUrl = finalUrl().resolved(QUrl(import.uri));
+ QQmlScriptBlob *blob = typeLoader()->getScript(scriptUrl);
+ addDependency(blob);
+
+ ScriptReference ref;
+ ref.location = import.location.start;
+ ref.qualifier = import.qualifier;
+ ref.script = blob;
+ m_scripts << ref;
+ } else {
+ Q_ASSERT(import.type == QQmlScript::Import::Library);
+ int vmaj = -1;
+ int vmin = -1;
+ import.extractVersion(&vmaj, &vmin);
+
+ QList<QQmlError> errors;
+ if (!m_imports.addImport(importDatabase, import.uri, import.qualifier, vmaj, vmin,
+ import.type, QQmlDirComponents(), &errors)) {
+ QQmlError error = errors.takeFirst();
+ // description should be set by addImport().
+ error.setUrl(m_imports.baseUrl());
+ error.setLine(import.location.start.line);
+ error.setColumn(import.location.start.column);
+ errors.prepend(error);
+
+ setError(errors);
+ return;
+ }
+ }
+ }
+}
+
+void QQmlScriptBlob::done()
+{
+ // Check all script dependencies for errors
+ for (int ii = 0; !isError() && ii < m_scripts.count(); ++ii) {
+ const ScriptReference &script = m_scripts.at(ii);
+ Q_ASSERT(script.script->isCompleteOrError());
+ if (script.script->isError()) {
+ QList<QQmlError> errors = script.script->errors();
+ QQmlError error;
+ error.setUrl(finalUrl());
+ error.setLine(script.location.line);
+ error.setColumn(script.location.column);
+ error.setDescription(typeLoader()->tr("Script %1 unavailable").arg(script.script->url().toString()));
+ errors.prepend(error);
+ setError(errors);
+ }
+ }
+
+ if (isError())
+ return;
+
+ QQmlEngine *engine = typeLoader()->engine();
+ m_scriptData = new QQmlScriptData();
+ m_scriptData->url = finalUrl();
+ m_scriptData->urlString = finalUrlString();
+ m_scriptData->importCache = new QQmlTypeNameCache();
+
+ for (int ii = 0; !isError() && ii < m_scripts.count(); ++ii) {
+ const ScriptReference &script = m_scripts.at(ii);
+
+ m_scriptData->scripts.append(script.script);
+ m_scriptData->importCache->add(script.qualifier, ii);
+ }
+
+ m_imports.populateCache(m_scriptData->importCache, engine);
+
+ m_scriptData->pragmas = m_pragmas;
+ m_scriptData->m_programSource = m_source.toUtf8();
+ m_source.clear();
+}
+
+QQmlQmldirData::QQmlQmldirData(const QUrl &url)
+: QQmlDataBlob(url, QmldirFile)
+{
+}
+
+const QQmlDirComponents &QQmlQmldirData::dirComponents() const
+{
+ return m_components;
+}
+
+void QQmlQmldirData::dataReceived(const QByteArray &data)
+{
+ QQmlDirParser parser;
+ parser.setSource(QString::fromUtf8(data));
+ parser.parse();
+ m_components = parser.components();
+}
+
+QT_END_NAMESPACE
+
+#include "qqmltypeloader.moc"
diff --git a/src/qml/qml/qqmltypeloader_p.h b/src/qml/qml/qqmltypeloader_p.h
new file mode 100644
index 0000000000..0dd7adecac
--- /dev/null
+++ b/src/qml/qml/qqmltypeloader_p.h
@@ -0,0 +1,435 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLTYPELOADER_P_H
+#define QQMLTYPELOADER_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qobject.h>
+#include <QtCore/qatomic.h>
+#include <QtNetwork/qnetworkreply.h>
+#include <QtQml/qqmlerror.h>
+#include <QtQml/qqmlengine.h>
+
+#include <private/qv8_p.h>
+#include <private/qhashedstring_p.h>
+#include <private/qqmlscript_p.h>
+#include <private/qqmlimport_p.h>
+#include <private/qqmlcleanup_p.h>
+#include <private/qqmldirparser_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQmlScriptData;
+class QQmlScriptBlob;
+class QQmlQmldirData;
+class QQmlTypeLoader;
+class QQmlCompiledData;
+class QQmlComponentPrivate;
+class QQmlTypeData;
+class QQmlDataLoader;
+class QQmlExtensionInterface;
+
+// Exported for QtQuick1
+class Q_QML_PRIVATE_EXPORT QQmlDataBlob : public QQmlRefCount
+{
+public:
+ enum Status {
+ Null, // Prior to QQmlDataLoader::load()
+ Loading, // Prior to data being received and dataReceived() being called
+ WaitingForDependencies, // While there are outstanding addDependency()s
+ Complete, // Finished
+ Error // Error
+ };
+
+ enum Type {
+ QmlFile,
+ JavaScriptFile,
+ QmldirFile
+ };
+
+ QQmlDataBlob(const QUrl &, Type);
+ virtual ~QQmlDataBlob();
+
+ Type type() const;
+
+ Status status() const;
+ bool isNull() const;
+ bool isLoading() const;
+ bool isWaiting() const;
+ bool isComplete() const;
+ bool isError() const;
+ bool isCompleteOrError() const;
+
+ qreal progress() const;
+
+ QUrl url() const;
+ QUrl finalUrl() const;
+ QString finalUrlString() const;
+
+ QList<QQmlError> errors() const;
+
+protected:
+ // Can be called from within callbacks
+ void setError(const QQmlError &);
+ void setError(const QList<QQmlError> &errors);
+ void addDependency(QQmlDataBlob *);
+
+ // Callbacks made in load thread
+ virtual void dataReceived(const QByteArray &) = 0;
+ virtual void done();
+ virtual void networkError(QNetworkReply::NetworkError);
+ virtual void dependencyError(QQmlDataBlob *);
+ virtual void dependencyComplete(QQmlDataBlob *);
+ virtual void allDependenciesDone();
+
+ // Callbacks made in main thread
+ virtual void downloadProgressChanged(qreal);
+ virtual void completed();
+private:
+ friend class QQmlDataLoader;
+ friend class QQmlDataLoaderThread;
+
+ void tryDone();
+ void cancelAllWaitingFor();
+ void notifyAllWaitingOnMe();
+ void notifyComplete(QQmlDataBlob *);
+
+ struct ThreadData {
+ inline ThreadData();
+ inline QQmlDataBlob::Status status() const;
+ inline void setStatus(QQmlDataBlob::Status);
+ inline bool isAsync() const;
+ inline void setIsAsync(bool);
+ inline quint8 progress() const;
+ inline void setProgress(quint8);
+
+ private:
+ QAtomicInt _p;
+ };
+ ThreadData m_data;
+
+ // m_errors should *always* be written before the status is set to Error.
+ // We use the status change as a memory fence around m_errors so that locking
+ // isn't required. Once the status is set to Error (or Complete), m_errors
+ // cannot be changed.
+ QList<QQmlError> m_errors;
+
+ Type m_type;
+
+ QUrl m_url;
+ QUrl m_finalUrl;
+ mutable QString m_finalUrlString;
+
+ // List of QQmlDataBlob's that are waiting for me to complete.
+ QList<QQmlDataBlob *> m_waitingOnMe;
+
+ // List of QQmlDataBlob's that I am waiting for to complete.
+ QList<QQmlDataBlob *> m_waitingFor;
+
+ // Manager that is currently fetching data for me
+ QQmlDataLoader *m_manager;
+ int m_redirectCount:30;
+ bool m_inCallback:1;
+ bool m_isDone:1;
+};
+
+class QQmlDataLoaderThread;
+// Exported for QtQuick1
+class Q_QML_PRIVATE_EXPORT QQmlDataLoader
+{
+public:
+ QQmlDataLoader(QQmlEngine *);
+ ~QQmlDataLoader();
+
+ void lock();
+ void unlock();
+
+ bool isConcurrent() const { return true; }
+
+ enum Mode { PreferSynchronous, Asynchronous };
+
+ void load(QQmlDataBlob *, Mode = PreferSynchronous);
+ void loadWithStaticData(QQmlDataBlob *, const QByteArray &, Mode = PreferSynchronous);
+
+ QQmlEngine *engine() const;
+ void initializeEngine(QQmlExtensionInterface *, const char *);
+
+private:
+ friend class QQmlDataBlob;
+ friend class QQmlDataLoaderThread;
+ friend class QQmlDataLoaderNetworkReplyProxy;
+
+ void loadThread(QQmlDataBlob *);
+ void loadWithStaticDataThread(QQmlDataBlob *, const QByteArray &);
+ void networkReplyFinished(QNetworkReply *);
+ void networkReplyProgress(QNetworkReply *, qint64, qint64);
+
+ typedef QHash<QNetworkReply *, QQmlDataBlob *> NetworkReplies;
+
+ void setData(QQmlDataBlob *, const QByteArray &);
+
+ QQmlEngine *m_engine;
+ QQmlDataLoaderThread *m_thread;
+ NetworkReplies m_networkReplies;
+};
+
+// Exported for QtQuick1
+class Q_QML_PRIVATE_EXPORT QQmlTypeLoader : public QQmlDataLoader
+{
+ Q_DECLARE_TR_FUNCTIONS(QQmlTypeLoader)
+public:
+ QQmlTypeLoader(QQmlEngine *);
+ ~QQmlTypeLoader();
+
+ enum Option {
+ None,
+ PreserveParser
+ };
+ Q_DECLARE_FLAGS(Options, Option)
+
+ QQmlTypeData *get(const QUrl &url);
+ QQmlTypeData *get(const QByteArray &, const QUrl &url, Options = None);
+ void clearCache();
+
+ QQmlScriptBlob *getScript(const QUrl &);
+ QQmlQmldirData *getQmldir(const QUrl &);
+
+ QString absoluteFilePath(const QString &path);
+ bool directoryExists(const QString &path);
+ const QQmlDirParser *qmlDirParser(const QString &absoluteFilePath);
+private:
+ typedef QHash<QUrl, QQmlTypeData *> TypeCache;
+ typedef QHash<QUrl, QQmlScriptBlob *> ScriptCache;
+ typedef QHash<QUrl, QQmlQmldirData *> QmldirCache;
+ typedef QStringHash<bool> StringSet;
+ typedef QStringHash<StringSet*> ImportDirCache;
+ typedef QStringHash<QQmlDirParser*> ImportQmlDirCache;
+
+ TypeCache m_typeCache;
+ ScriptCache m_scriptCache;
+ QmldirCache m_qmldirCache;
+ ImportDirCache m_importDirCache;
+ ImportQmlDirCache m_importQmlDirCache;
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QQmlTypeLoader::Options)
+
+class Q_AUTOTEST_EXPORT QQmlTypeData : public QQmlDataBlob
+{
+public:
+ struct TypeReference
+ {
+ TypeReference() : type(0), majorVersion(0), minorVersion(0), typeData(0) {}
+
+ QQmlScript::Location location;
+ QQmlType *type;
+ int majorVersion;
+ int minorVersion;
+ QQmlTypeData *typeData;
+ };
+
+ struct ScriptReference
+ {
+ ScriptReference() : script(0) {}
+
+ QQmlScript::Location location;
+ QString qualifier;
+ QQmlScriptBlob *script;
+ };
+
+ QQmlTypeData(const QUrl &, QQmlTypeLoader::Options, QQmlTypeLoader *);
+ ~QQmlTypeData();
+
+ QQmlTypeLoader *typeLoader() const;
+
+ const QQmlImports &imports() const;
+ const QQmlScript::Parser &parser() const;
+
+ const QList<TypeReference> &resolvedTypes() const;
+ const QList<ScriptReference> &resolvedScripts() const;
+ const QSet<QString> &namespaces() const;
+
+ QQmlCompiledData *compiledData() const;
+
+ // Used by QQmlComponent to get notifications
+ struct TypeDataCallback {
+ ~TypeDataCallback() {}
+ virtual void typeDataProgress(QQmlTypeData *, qreal) {}
+ virtual void typeDataReady(QQmlTypeData *) {}
+ };
+ void registerCallback(TypeDataCallback *);
+ void unregisterCallback(TypeDataCallback *);
+
+protected:
+ virtual void done();
+ virtual void completed();
+ virtual void dataReceived(const QByteArray &);
+ virtual void allDependenciesDone();
+ virtual void downloadProgressChanged(qreal);
+
+private:
+ void resolveTypes();
+ void compile();
+
+ QQmlTypeLoader::Options m_options;
+
+ QQmlQmldirData *qmldirForUrl(const QUrl &);
+
+ QQmlScript::Parser scriptParser;
+ QQmlImports m_imports;
+
+ QList<ScriptReference> m_scripts;
+ QList<QQmlQmldirData *> m_qmldirs;
+
+ QSet<QString> m_namespaces;
+
+ QList<TypeReference> m_types;
+ bool m_typesResolved:1;
+
+ QQmlCompiledData *m_compiledData;
+
+ QList<TypeDataCallback *> m_callbacks;
+
+ QQmlTypeLoader *m_typeLoader;
+};
+
+// QQmlScriptData instances are created, uninitialized, by the loader in the
+// load thread. The first time they are used by the VME, they are initialized which
+// creates their v8 objects and they are referenced and added to the engine's cleanup
+// list. During QQmlCleanup::clear() all v8 resources are destroyed, and the
+// reference that was created is released but final deletion only occurs once all the
+// references as released. This is all intended to ensure that the v8 resources are
+// only created and destroyed in the main thread :)
+class Q_AUTOTEST_EXPORT QQmlScriptData : public QQmlCleanup,
+ public QQmlRefCount
+{
+public:
+ QQmlScriptData();
+ ~QQmlScriptData();
+
+ QUrl url;
+ QString urlString;
+ QQmlTypeNameCache *importCache;
+ QList<QQmlScriptBlob *> scripts;
+ QQmlScript::Object::ScriptBlock::Pragmas pragmas;
+
+ bool isInitialized() const { return hasEngine(); }
+ void initialize(QQmlEngine *);
+
+protected:
+ virtual void clear(); // From QQmlCleanup
+
+private:
+ friend class QQmlVME;
+ friend class QQmlScriptBlob;
+
+ bool m_loaded;
+ QByteArray m_programSource;
+ v8::Persistent<v8::Script> m_program;
+ v8::Persistent<v8::Object> m_value;
+};
+
+class Q_AUTOTEST_EXPORT QQmlScriptBlob : public QQmlDataBlob
+{
+public:
+ QQmlScriptBlob(const QUrl &, QQmlTypeLoader *);
+ ~QQmlScriptBlob();
+
+ struct ScriptReference
+ {
+ ScriptReference() : script(0) {}
+
+ QQmlScript::Location location;
+ QString qualifier;
+ QQmlScriptBlob *script;
+ };
+
+ QQmlScript::Object::ScriptBlock::Pragmas pragmas() const;
+
+ QQmlTypeLoader *typeLoader() const;
+ const QQmlImports &imports() const;
+
+ QQmlScriptData *scriptData() const;
+
+protected:
+ virtual void dataReceived(const QByteArray &);
+ virtual void done();
+
+private:
+ QQmlScript::Object::ScriptBlock::Pragmas m_pragmas;
+ QString m_source;
+
+ QQmlImports m_imports;
+ QList<ScriptReference> m_scripts;
+ QQmlScriptData *m_scriptData;
+
+ QQmlTypeLoader *m_typeLoader;
+};
+
+class Q_AUTOTEST_EXPORT QQmlQmldirData : public QQmlDataBlob
+{
+public:
+ QQmlQmldirData(const QUrl &);
+
+ const QQmlDirComponents &dirComponents() const;
+
+protected:
+ virtual void dataReceived(const QByteArray &);
+
+private:
+ QQmlDirComponents m_components;
+
+};
+
+QT_END_NAMESPACE
+
+#endif // QQMLTYPELOADER_P_H
diff --git a/src/qml/qml/qqmltypenamecache.cpp b/src/qml/qml/qqmltypenamecache.cpp
new file mode 100644
index 0000000000..f9d3e7704c
--- /dev/null
+++ b/src/qml/qml/qqmltypenamecache.cpp
@@ -0,0 +1,127 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qqmltypenamecache_p.h"
+
+#include "qqmlengine_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QQmlTypeNameCache::QQmlTypeNameCache()
+{
+}
+
+QQmlTypeNameCache::~QQmlTypeNameCache()
+{
+}
+
+void QQmlTypeNameCache::add(const QHashedString &name, int importedScriptIndex, const QHashedString &nameSpace)
+{
+ Import import;
+ import.scriptIndex = importedScriptIndex;
+
+ if (nameSpace.length() != 0) {
+ Import *i = m_namedImports.value(nameSpace);
+ Q_ASSERT(i != 0);
+ m_namespacedImports[i].insert(name, import);
+ return;
+ }
+
+ if (m_namedImports.contains(name))
+ return;
+
+ m_namedImports.insert(name, import);
+}
+
+QQmlTypeNameCache::Result QQmlTypeNameCache::query(const QHashedStringRef &name)
+{
+ Result result = query(m_namedImports, name);
+
+ if (!result.isValid())
+ result = typeSearch(m_anonymousImports, name);
+
+ return result;
+}
+
+QQmlTypeNameCache::Result QQmlTypeNameCache::query(const QHashedStringRef &name,
+ const void *importNamespace)
+{
+ Q_ASSERT(importNamespace);
+ const Import *i = static_cast<const Import *>(importNamespace);
+ Q_ASSERT(i->scriptIndex == -1);
+
+ return typeSearch(i->modules, name);
+}
+
+QQmlTypeNameCache::Result QQmlTypeNameCache::query(const QHashedV8String &name)
+{
+ Result result = query(m_namedImports, name);
+
+ if (!result.isValid())
+ result = typeSearch(m_anonymousImports, name);
+
+ return result;
+}
+
+QQmlTypeNameCache::Result QQmlTypeNameCache::query(const QHashedV8String &name, const void *importNamespace)
+{
+ Q_ASSERT(importNamespace);
+ const Import *i = static_cast<const Import *>(importNamespace);
+ Q_ASSERT(i->scriptIndex == -1);
+
+ QMap<const Import *, QStringHash<Import> >::const_iterator it = m_namespacedImports.find(i);
+ if (it != m_namespacedImports.constEnd())
+ return query(*it, name);
+
+ return typeSearch(i->modules, name);
+}
+
+QQmlMetaType::ModuleApiInstance *QQmlTypeNameCache::moduleApi(const void *importNamespace)
+{
+ Q_ASSERT(importNamespace);
+ const Import *i = static_cast<const Import *>(importNamespace);
+ Q_ASSERT(i->scriptIndex == -1);
+
+ return i->moduleApi;
+}
+
+QT_END_NAMESPACE
+
diff --git a/src/qml/qml/qqmltypenamecache_p.h b/src/qml/qml/qqmltypenamecache_p.h
new file mode 100644
index 0000000000..a9268db37a
--- /dev/null
+++ b/src/qml/qml/qqmltypenamecache_p.h
@@ -0,0 +1,187 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLTYPENAMECACHE_P_H
+#define QQMLTYPENAMECACHE_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qqmlrefcount_p.h>
+#include "qqmlcleanup_p.h"
+#include "qqmlmetatype_p.h"
+
+#include <private/qhashedstring_p.h>
+
+#include <QtCore/qvector.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQmlType;
+class QQmlEngine;
+class QQmlTypeNameCache : public QQmlRefCount
+{
+public:
+ QQmlTypeNameCache();
+ virtual ~QQmlTypeNameCache();
+
+ inline bool isEmpty() const;
+
+ void add(const QHashedString &name, int sciptIndex = -1, const QHashedString &nameSpace = QHashedString());
+
+ struct Result {
+ inline Result();
+ inline Result(const void *importNamespace);
+ inline Result(QQmlType *type);
+ inline Result(int scriptIndex);
+ inline Result(const Result &);
+
+ inline bool isValid() const;
+
+ QQmlType *type;
+ const void *importNamespace;
+ int scriptIndex;
+ };
+ Result query(const QHashedStringRef &);
+ Result query(const QHashedStringRef &, const void *importNamespace);
+ Result query(const QHashedV8String &);
+ Result query(const QHashedV8String &, const void *importNamespace);
+ QQmlMetaType::ModuleApiInstance *moduleApi(const void *importNamespace);
+
+private:
+ friend class QQmlImports;
+
+ struct Import {
+ inline Import();
+ // Imported module
+ QQmlMetaType::ModuleApiInstance *moduleApi;
+ QVector<QQmlTypeModuleVersion> modules;
+
+ // Or, imported script
+ int scriptIndex;
+ };
+
+ template<typename Key>
+ Result query(const QStringHash<Import> &imports, Key key)
+ {
+ Import *i = imports.value(key);
+ if (i) {
+ if (i->scriptIndex != -1) {
+ return Result(i->scriptIndex);
+ } else {
+ return Result(static_cast<const void *>(i));
+ }
+ }
+
+ return Result();
+ }
+
+ template<typename Key>
+ Result typeSearch(const QVector<QQmlTypeModuleVersion> &modules, Key key)
+ {
+ QVector<QQmlTypeModuleVersion>::const_iterator end = modules.constEnd();
+ for (QVector<QQmlTypeModuleVersion>::const_iterator it = modules.constBegin(); it != end; ++it) {
+ if (QQmlType *type = it->type(key))
+ return Result(type);
+ }
+
+ return Result();
+ }
+
+ QStringHash<Import> m_namedImports;
+ QMap<const Import *, QStringHash<Import> > m_namespacedImports;
+ QVector<QQmlTypeModuleVersion> m_anonymousImports;
+
+ QQmlEngine *engine;
+};
+
+QQmlTypeNameCache::Result::Result()
+: type(0), importNamespace(0), scriptIndex(-1)
+{
+}
+
+QQmlTypeNameCache::Result::Result(const void *importNamespace)
+: type(0), importNamespace(importNamespace), scriptIndex(-1)
+{
+}
+
+QQmlTypeNameCache::Result::Result(QQmlType *type)
+: type(type), importNamespace(0), scriptIndex(-1)
+{
+}
+
+QQmlTypeNameCache::Result::Result(int scriptIndex)
+: type(0), importNamespace(0), scriptIndex(scriptIndex)
+{
+}
+
+QQmlTypeNameCache::Result::Result(const Result &o)
+: type(o.type), importNamespace(o.importNamespace), scriptIndex(o.scriptIndex)
+{
+}
+
+bool QQmlTypeNameCache::Result::isValid() const
+{
+ return type || importNamespace || scriptIndex != -1;
+}
+
+QQmlTypeNameCache::Import::Import()
+: moduleApi(0), scriptIndex(-1)
+{
+}
+
+bool QQmlTypeNameCache::isEmpty() const
+{
+ return m_namedImports.isEmpty() && m_anonymousImports.isEmpty();
+}
+
+QT_END_NAMESPACE
+
+#endif // QQMLTYPENAMECACHE_P_H
+
diff --git a/src/qml/qml/qqmltypenotavailable.cpp b/src/qml/qml/qqmltypenotavailable.cpp
new file mode 100644
index 0000000000..6eb891af71
--- /dev/null
+++ b/src/qml/qml/qqmltypenotavailable.cpp
@@ -0,0 +1,53 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qqmltypenotavailable_p.h"
+
+QT_BEGIN_NAMESPACE
+
+int qmlRegisterTypeNotAvailable(const char *uri, int versionMajor, int versionMinor, const char *qmlName, const QString& message)
+{
+ return qmlRegisterUncreatableType<QQmlTypeNotAvailable>(uri,versionMajor,versionMinor,qmlName,message);
+}
+
+QQmlTypeNotAvailable::QQmlTypeNotAvailable() { }
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmltypenotavailable_p.h b/src/qml/qml/qqmltypenotavailable_p.h
new file mode 100644
index 0000000000..d0618a0686
--- /dev/null
+++ b/src/qml/qml/qqmltypenotavailable_p.h
@@ -0,0 +1,64 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLTYPENOTAVAILABLE_H
+#define QQMLTYPENOTAVAILABLE_H
+
+#include <qqml.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+
+class QQmlTypeNotAvailable : public QObject {
+ Q_OBJECT
+public:
+ QQmlTypeNotAvailable();
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQmlTypeNotAvailable)
+
+QT_END_HEADER
+
+#endif // QQMLTYPENOTAVAILABLE_H
diff --git a/src/qml/qml/qqmlvaluetype.cpp b/src/qml/qml/qqmlvaluetype.cpp
new file mode 100644
index 0000000000..4ade00f9b4
--- /dev/null
+++ b/src/qml/qml/qqmlvaluetype.cpp
@@ -0,0 +1,868 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qqmlvaluetype_p.h"
+
+#include "qqmlmetatype_p.h"
+#include <private/qfont_p.h>
+
+#include <QtCore/qdebug.h>
+
+QT_BEGIN_NAMESPACE
+
+template<typename T>
+int qmlRegisterValueTypeEnums(const char *uri, int versionMajor, int versionMinor, const char *qmlName)
+{
+ QByteArray name(T::staticMetaObject.className());
+
+ QByteArray pointerName(name + '*');
+
+ QQmlPrivate::RegisterType type = {
+ 0,
+
+ qRegisterMetaType<T *>(pointerName.constData()), 0, 0, 0,
+
+ QString(),
+
+ uri, versionMajor, versionMinor, qmlName, &T::staticMetaObject,
+
+ 0, 0,
+
+ 0, 0, 0,
+
+ 0, 0,
+
+ 0,
+ 0
+ };
+
+ return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type);
+}
+
+QQmlValueTypeFactory::QQmlValueTypeFactory()
+{
+ // ### Optimize
+ for (unsigned int ii = 0; ii < (QVariant::UserType - 1); ++ii)
+ valueTypes[ii] = valueType(ii);
+}
+
+QQmlValueTypeFactory::~QQmlValueTypeFactory()
+{
+ for (unsigned int ii = 0; ii < (QVariant::UserType - 1); ++ii)
+ delete valueTypes[ii];
+}
+
+bool QQmlValueTypeFactory::isValueType(int idx)
+{
+ if ((uint)idx < QVariant::UserType
+ && idx != QVariant::StringList
+ && idx != QMetaType::QObjectStar
+ && idx != QMetaType::QWidgetStar
+ && idx != QMetaType::VoidStar
+ && idx != QMetaType::QVariant) {
+ return true;
+ }
+ return false;
+}
+
+void QQmlValueTypeFactory::registerBaseTypes(const char *uri, int versionMajor, int versionMinor)
+{
+ qmlRegisterValueTypeEnums<QQmlEasingValueType>(uri, versionMajor, versionMinor, "Easing");
+ qmlRegisterValueTypeEnums<QQmlFontValueType>(uri, versionMajor, versionMinor, "Font");
+}
+
+void QQmlValueTypeFactory::registerValueTypes()
+{
+ registerBaseTypes("QtQuick", 2, 0);
+}
+
+QQmlValueType *QQmlValueTypeFactory::valueType(int t)
+{
+ QQmlValueType *rv = 0;
+
+ switch (t) {
+ case QVariant::Point:
+ rv = new QQmlPointValueType;
+ break;
+ case QVariant::PointF:
+ rv = new QQmlPointFValueType;
+ break;
+ case QVariant::Size:
+ rv = new QQmlSizeValueType;
+ break;
+ case QVariant::SizeF:
+ rv = new QQmlSizeFValueType;
+ break;
+ case QVariant::Rect:
+ rv = new QQmlRectValueType;
+ break;
+ case QVariant::RectF:
+ rv = new QQmlRectFValueType;
+ break;
+ case QVariant::Vector2D:
+ rv = new QQmlVector2DValueType;
+ break;
+ case QVariant::Vector3D:
+ rv = new QQmlVector3DValueType;
+ break;
+ case QVariant::Vector4D:
+ rv = new QQmlVector4DValueType;
+ break;
+ case QVariant::Quaternion:
+ rv = new QQmlQuaternionValueType;
+ break;
+ case QVariant::Matrix4x4:
+ rv = new QQmlMatrix4x4ValueType;
+ break;
+ case QVariant::EasingCurve:
+ rv = new QQmlEasingValueType;
+ break;
+ case QVariant::Font:
+ rv = new QQmlFontValueType;
+ break;
+ case QVariant::Color:
+ rv = new QQmlColorValueType;
+ break;
+ default:
+ break;
+ }
+
+ Q_ASSERT(!rv || rv->metaObject()->propertyCount() < 32);
+ return rv;
+}
+
+QQmlValueType::QQmlValueType(QObject *parent)
+: QObject(parent)
+{
+}
+
+#define QML_VALUETYPE_READWRITE(name, cpptype, var) \
+ QQml ## name ## ValueType::QQml ## name ## ValueType(QObject *parent) \
+ : QQmlValueType(parent) \
+ { \
+ } \
+ void QQml ## name ## ValueType::read(QObject *obj, int idx) \
+ { \
+ void *a[] = { &var, 0 }; \
+ QMetaObject::metacall(obj, QMetaObject::ReadProperty, idx, a); \
+ onLoad(); \
+ } \
+ void QQml ## name ## ValueType::write(QObject *obj, int idx, \
+ QQmlPropertyPrivate::WriteFlags flags) \
+ { \
+ int status = -1; \
+ void *a[] = { &var, 0, &status, &flags }; \
+ QMetaObject::metacall(obj, QMetaObject::WriteProperty, idx, a); \
+ } \
+ bool QQml ## name ## ValueType::isEqual(const QVariant &value) const \
+ { \
+ return QVariant(var) == value; \
+ } \
+ QVariant QQml ## name ## ValueType::value() \
+ { \
+ return QVariant(var); \
+ } \
+ void QQml ## name ## ValueType::setValue(const QVariant &value) \
+ { \
+ var = qvariant_cast<cpptype>(value); \
+ onLoad(); \
+ }
+
+QML_VALUETYPE_READWRITE(PointF, QPointF, point);
+QML_VALUETYPE_READWRITE(Point, QPoint, point);
+QML_VALUETYPE_READWRITE(SizeF, QSizeF, size);
+QML_VALUETYPE_READWRITE(Size, QSize, size);
+QML_VALUETYPE_READWRITE(RectF, QRectF, rect);
+QML_VALUETYPE_READWRITE(Rect, QRect, rect);
+QML_VALUETYPE_READWRITE(Vector2D, QVector2D, vector);
+QML_VALUETYPE_READWRITE(Vector3D, QVector3D, vector);
+QML_VALUETYPE_READWRITE(Vector4D, QVector4D, vector);
+QML_VALUETYPE_READWRITE(Quaternion, QQuaternion, quaternion);
+QML_VALUETYPE_READWRITE(Matrix4x4, QMatrix4x4, matrix);
+QML_VALUETYPE_READWRITE(Easing, QEasingCurve, easing);
+QML_VALUETYPE_READWRITE(Font, QFont, font);
+QML_VALUETYPE_READWRITE(Color, QColor, color);
+
+QString QQmlPointFValueType::toString() const
+{
+ return QString(QLatin1String("QPointF(%1, %2)")).arg(point.x()).arg(point.y());
+}
+
+qreal QQmlPointFValueType::x() const
+{
+ return point.x();
+}
+
+qreal QQmlPointFValueType::y() const
+{
+ return point.y();
+}
+
+void QQmlPointFValueType::setX(qreal x)
+{
+ point.setX(x);
+}
+
+void QQmlPointFValueType::setY(qreal y)
+{
+ point.setY(y);
+}
+
+QString QQmlPointValueType::toString() const
+{
+ return QString(QLatin1String("QPoint(%1, %2)")).arg(point.x()).arg(point.y());
+}
+
+int QQmlPointValueType::x() const
+{
+ return point.x();
+}
+
+int QQmlPointValueType::y() const
+{
+ return point.y();
+}
+
+void QQmlPointValueType::setX(int x)
+{
+ point.setX(x);
+}
+
+void QQmlPointValueType::setY(int y)
+{
+ point.setY(y);
+}
+
+QString QQmlSizeFValueType::toString() const
+{
+ return QString(QLatin1String("QSizeF(%1, %2)")).arg(size.width()).arg(size.height());
+}
+
+qreal QQmlSizeFValueType::width() const
+{
+ return size.width();
+}
+
+qreal QQmlSizeFValueType::height() const
+{
+ return size.height();
+}
+
+void QQmlSizeFValueType::setWidth(qreal w)
+{
+ size.setWidth(w);
+}
+
+void QQmlSizeFValueType::setHeight(qreal h)
+{
+ size.setHeight(h);
+}
+
+QString QQmlSizeValueType::toString() const
+{
+ return QString(QLatin1String("QSize(%1, %2)")).arg(size.width()).arg(size.height());
+}
+
+int QQmlSizeValueType::width() const
+{
+ return size.width();
+}
+
+int QQmlSizeValueType::height() const
+{
+ return size.height();
+}
+
+void QQmlSizeValueType::setWidth(int w)
+{
+ size.setWidth(w);
+}
+
+void QQmlSizeValueType::setHeight(int h)
+{
+ size.setHeight(h);
+}
+
+QString QQmlRectFValueType::toString() const
+{
+ return QString(QLatin1String("QRectF(%1, %2, %3, %4)")).arg(rect.x()).arg(rect.y()).arg(rect.width()).arg(rect.height());
+}
+
+qreal QQmlRectFValueType::x() const
+{
+ return rect.x();
+}
+
+qreal QQmlRectFValueType::y() const
+{
+ return rect.y();
+}
+
+void QQmlRectFValueType::setX(qreal x)
+{
+ rect.moveLeft(x);
+}
+
+void QQmlRectFValueType::setY(qreal y)
+{
+ rect.moveTop(y);
+}
+
+qreal QQmlRectFValueType::width() const
+{
+ return rect.width();
+}
+
+qreal QQmlRectFValueType::height() const
+{
+ return rect.height();
+}
+
+void QQmlRectFValueType::setWidth(qreal w)
+{
+ rect.setWidth(w);
+}
+
+void QQmlRectFValueType::setHeight(qreal h)
+{
+ rect.setHeight(h);
+}
+
+QString QQmlRectValueType::toString() const
+{
+ return QString(QLatin1String("QRect(%1, %2, %3, %4)")).arg(rect.x()).arg(rect.y()).arg(rect.width()).arg(rect.height());
+}
+
+int QQmlRectValueType::x() const
+{
+ return rect.x();
+}
+
+int QQmlRectValueType::y() const
+{
+ return rect.y();
+}
+
+void QQmlRectValueType::setX(int x)
+{
+ rect.moveLeft(x);
+}
+
+void QQmlRectValueType::setY(int y)
+{
+ rect.moveTop(y);
+}
+
+int QQmlRectValueType::width() const
+{
+ return rect.width();
+}
+
+int QQmlRectValueType::height() const
+{
+ return rect.height();
+}
+
+void QQmlRectValueType::setWidth(int w)
+{
+ rect.setWidth(w);
+}
+
+void QQmlRectValueType::setHeight(int h)
+{
+ rect.setHeight(h);
+}
+
+QString QQmlVector2DValueType::toString() const
+{
+ return QString(QLatin1String("QVector2D(%1, %2)")).arg(vector.x()).arg(vector.y());
+}
+
+qreal QQmlVector2DValueType::x() const
+{
+ return vector.x();
+}
+
+qreal QQmlVector2DValueType::y() const
+{
+ return vector.y();
+}
+
+void QQmlVector2DValueType::setX(qreal x)
+{
+ vector.setX(x);
+}
+
+void QQmlVector2DValueType::setY(qreal y)
+{
+ vector.setY(y);
+}
+
+QString QQmlVector3DValueType::toString() const
+{
+ return QString(QLatin1String("QVector3D(%1, %2, %3)")).arg(vector.x()).arg(vector.y()).arg(vector.z());
+}
+
+qreal QQmlVector3DValueType::x() const
+{
+ return vector.x();
+}
+
+qreal QQmlVector3DValueType::y() const
+{
+ return vector.y();
+}
+
+qreal QQmlVector3DValueType::z() const
+{
+ return vector.z();
+}
+
+void QQmlVector3DValueType::setX(qreal x)
+{
+ vector.setX(x);
+}
+
+void QQmlVector3DValueType::setY(qreal y)
+{
+ vector.setY(y);
+}
+
+void QQmlVector3DValueType::setZ(qreal z)
+{
+ vector.setZ(z);
+}
+
+QString QQmlVector4DValueType::toString() const
+{
+ return QString(QLatin1String("QVector4D(%1, %2, %3, %4)")).arg(vector.x()).arg(vector.y()).arg(vector.z()).arg(vector.w());
+}
+
+qreal QQmlVector4DValueType::x() const
+{
+ return vector.x();
+}
+
+qreal QQmlVector4DValueType::y() const
+{
+ return vector.y();
+}
+
+qreal QQmlVector4DValueType::z() const
+{
+ return vector.z();
+}
+
+qreal QQmlVector4DValueType::w() const
+{
+ return vector.w();
+}
+
+void QQmlVector4DValueType::setX(qreal x)
+{
+ vector.setX(x);
+}
+
+void QQmlVector4DValueType::setY(qreal y)
+{
+ vector.setY(y);
+}
+
+void QQmlVector4DValueType::setZ(qreal z)
+{
+ vector.setZ(z);
+}
+
+void QQmlVector4DValueType::setW(qreal w)
+{
+ vector.setW(w);
+}
+
+QString QQmlQuaternionValueType::toString() const
+{
+ return QString(QLatin1String("QQuaternion(%1, %2, %3, %4)")).arg(quaternion.scalar()).arg(quaternion.x()).arg(quaternion.y()).arg(quaternion.z());
+}
+
+qreal QQmlQuaternionValueType::scalar() const
+{
+ return quaternion.scalar();
+}
+
+qreal QQmlQuaternionValueType::x() const
+{
+ return quaternion.x();
+}
+
+qreal QQmlQuaternionValueType::y() const
+{
+ return quaternion.y();
+}
+
+qreal QQmlQuaternionValueType::z() const
+{
+ return quaternion.z();
+}
+
+void QQmlQuaternionValueType::setScalar(qreal scalar)
+{
+ quaternion.setScalar(scalar);
+}
+
+void QQmlQuaternionValueType::setX(qreal x)
+{
+ quaternion.setX(x);
+}
+
+void QQmlQuaternionValueType::setY(qreal y)
+{
+ quaternion.setY(y);
+}
+
+void QQmlQuaternionValueType::setZ(qreal z)
+{
+ quaternion.setZ(z);
+}
+
+QString QQmlMatrix4x4ValueType::toString() const
+{
+ return QString(QLatin1String("QMatrix4x4(%1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16)"))
+ .arg(matrix(0, 0)).arg(matrix(0, 1)).arg(matrix(0, 2)).arg(matrix(0, 3))
+ .arg(matrix(1, 0)).arg(matrix(1, 1)).arg(matrix(1, 2)).arg(matrix(1, 3))
+ .arg(matrix(2, 0)).arg(matrix(2, 1)).arg(matrix(2, 2)).arg(matrix(2, 3))
+ .arg(matrix(3, 0)).arg(matrix(3, 1)).arg(matrix(3, 2)).arg(matrix(3, 3));
+}
+
+QString QQmlEasingValueType::toString() const
+{
+ return QString(QLatin1String("QEasingCurve(%1, %2, %3, %4)")).arg(easing.type()).arg(easing.amplitude()).arg(easing.overshoot()).arg(easing.period());
+}
+
+QQmlEasingValueType::Type QQmlEasingValueType::type() const
+{
+ return (QQmlEasingValueType::Type)easing.type();
+}
+
+qreal QQmlEasingValueType::amplitude() const
+{
+ return easing.amplitude();
+}
+
+qreal QQmlEasingValueType::overshoot() const
+{
+ return easing.overshoot();
+}
+
+qreal QQmlEasingValueType::period() const
+{
+ return easing.period();
+}
+
+void QQmlEasingValueType::setType(QQmlEasingValueType::Type type)
+{
+ easing.setType((QEasingCurve::Type)type);
+}
+
+void QQmlEasingValueType::setAmplitude(qreal amplitude)
+{
+ easing.setAmplitude(amplitude);
+}
+
+void QQmlEasingValueType::setOvershoot(qreal overshoot)
+{
+ easing.setOvershoot(overshoot);
+}
+
+void QQmlEasingValueType::setPeriod(qreal period)
+{
+ easing.setPeriod(period);
+}
+
+void QQmlEasingValueType::setBezierCurve(const QVariantList &customCurveVariant)
+{
+ if (customCurveVariant.isEmpty())
+ return;
+
+ QVariantList variantList = customCurveVariant;
+ if ((variantList.count() % 6) == 0) {
+ bool allRealsOk = true;
+ QList<qreal> reals;
+ for (int i = 0; i < variantList.count(); i++) {
+ bool ok;
+ const qreal real = variantList.at(i).toReal(&ok);
+ reals.append(real);
+ if (!ok)
+ allRealsOk = false;
+ }
+ if (allRealsOk) {
+ QEasingCurve newEasingCurve(QEasingCurve::BezierSpline);
+ for (int i = 0; i < reals.count() / 6; i++) {
+ const qreal c1x = reals.at(i * 6);
+ const qreal c1y = reals.at(i * 6 + 1);
+ const qreal c2x = reals.at(i * 6 + 2);
+ const qreal c2y = reals.at(i * 6 + 3);
+ const qreal c3x = reals.at(i * 6 + 4);
+ const qreal c3y = reals.at(i * 6 + 5);
+
+ const QPointF c1(c1x, c1y);
+ const QPointF c2(c2x, c2y);
+ const QPointF c3(c3x, c3y);
+
+ newEasingCurve.addCubicBezierSegment(c1, c2, c3);
+ easing = newEasingCurve;
+ }
+ }
+ }
+}
+
+QVariantList QQmlEasingValueType::bezierCurve() const
+{
+ QVariantList rv;
+ QList<QPointF> points = easing.cubicBezierSpline();
+ for (int ii = 0; ii < points.count(); ++ii)
+ rv << QVariant(points.at(ii).x()) << QVariant(points.at(ii).y());
+ return rv;
+}
+
+void QQmlFontValueType::onLoad()
+{
+ pixelSizeSet = false;
+ pointSizeSet = false;
+}
+
+QString QQmlFontValueType::toString() const
+{
+ return QString(QLatin1String("QFont(%1)")).arg(font.toString());
+}
+
+QString QQmlFontValueType::family() const
+{
+ return font.family();
+}
+
+void QQmlFontValueType::setFamily(const QString &family)
+{
+ font.setFamily(family);
+}
+
+bool QQmlFontValueType::bold() const
+{
+ return font.bold();
+}
+
+void QQmlFontValueType::setBold(bool b)
+{
+ font.setBold(b);
+}
+
+QQmlFontValueType::FontWeight QQmlFontValueType::weight() const
+{
+ return (QQmlFontValueType::FontWeight)font.weight();
+}
+
+void QQmlFontValueType::setWeight(QQmlFontValueType::FontWeight w)
+{
+ font.setWeight((QFont::Weight)w);
+}
+
+bool QQmlFontValueType::italic() const
+{
+ return font.italic();
+}
+
+void QQmlFontValueType::setItalic(bool b)
+{
+ font.setItalic(b);
+}
+
+bool QQmlFontValueType::underline() const
+{
+ return font.underline();
+}
+
+void QQmlFontValueType::setUnderline(bool b)
+{
+ font.setUnderline(b);
+}
+
+bool QQmlFontValueType::overline() const
+{
+ return font.overline();
+}
+
+void QQmlFontValueType::setOverline(bool b)
+{
+ font.setOverline(b);
+}
+
+bool QQmlFontValueType::strikeout() const
+{
+ return font.strikeOut();
+}
+
+void QQmlFontValueType::setStrikeout(bool b)
+{
+ font.setStrikeOut(b);
+}
+
+qreal QQmlFontValueType::pointSize() const
+{
+ if (font.pointSizeF() == -1) {
+ if (dpi.isNull)
+ dpi = qt_defaultDpi();
+ return font.pixelSize() * qreal(72.) / qreal(dpi);
+ }
+ return font.pointSizeF();
+}
+
+void QQmlFontValueType::setPointSize(qreal size)
+{
+ if (pixelSizeSet) {
+ qWarning() << "Both point size and pixel size set. Using pixel size.";
+ return;
+ }
+
+ if (size >= 0.0) {
+ pointSizeSet = true;
+ font.setPointSizeF(size);
+ } else {
+ pointSizeSet = false;
+ }
+}
+
+int QQmlFontValueType::pixelSize() const
+{
+ if (font.pixelSize() == -1) {
+ if (dpi.isNull)
+ dpi = qt_defaultDpi();
+ return (font.pointSizeF() * dpi) / qreal(72.);
+ }
+ return font.pixelSize();
+}
+
+void QQmlFontValueType::setPixelSize(int size)
+{
+ if (size >0) {
+ if (pointSizeSet)
+ qWarning() << "Both point size and pixel size set. Using pixel size.";
+ font.setPixelSize(size);
+ pixelSizeSet = true;
+ } else {
+ pixelSizeSet = false;
+ }
+}
+
+QQmlFontValueType::Capitalization QQmlFontValueType::capitalization() const
+{
+ return (QQmlFontValueType::Capitalization)font.capitalization();
+}
+
+void QQmlFontValueType::setCapitalization(QQmlFontValueType::Capitalization c)
+{
+ font.setCapitalization((QFont::Capitalization)c);
+}
+
+qreal QQmlFontValueType::letterSpacing() const
+{
+ return font.letterSpacing();
+}
+
+void QQmlFontValueType::setLetterSpacing(qreal size)
+{
+ font.setLetterSpacing(QFont::AbsoluteSpacing, size);
+}
+
+qreal QQmlFontValueType::wordSpacing() const
+{
+ return font.wordSpacing();
+}
+
+void QQmlFontValueType::setWordSpacing(qreal size)
+{
+ font.setWordSpacing(size);
+}
+
+QString QQmlColorValueType::toString() const
+{
+ // special case - to maintain behaviour with QtQuick 1.0, we just output normal toString() value.
+ return QVariant(color).toString();
+}
+
+qreal QQmlColorValueType::r() const
+{
+ return color.redF();
+}
+
+qreal QQmlColorValueType::g() const
+{
+ return color.greenF();
+}
+
+qreal QQmlColorValueType::b() const
+{
+ return color.blueF();
+}
+
+qreal QQmlColorValueType::a() const
+{
+ return color.alphaF();
+}
+
+void QQmlColorValueType::setR(qreal r)
+{
+ color.setRedF(r);
+}
+
+void QQmlColorValueType::setG(qreal g)
+{
+ color.setGreenF(g);
+}
+
+void QQmlColorValueType::setB(qreal b)
+{
+ color.setBlueF(b);
+}
+
+void QQmlColorValueType::setA(qreal a)
+{
+ color.setAlphaF(a);
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlvaluetype_p.h b/src/qml/qml/qqmlvaluetype_p.h
new file mode 100644
index 0000000000..71817c2a2d
--- /dev/null
+++ b/src/qml/qml/qqmlvaluetype_p.h
@@ -0,0 +1,635 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLVALUETYPE_P_H
+#define QQMLVALUETYPE_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 "qqmlproperty.h"
+#include "qqmlproperty_p.h"
+#include "qqmlnullablevalue_p_p.h"
+
+#include <QtCore/qobject.h>
+#include <QtCore/qrect.h>
+#include <QtCore/qeasingcurve.h>
+#include <QtCore/qvariant.h>
+#include <QtGui/qvector2d.h>
+#include <QtGui/qvector3d.h>
+#include <QtGui/qvector4d.h>
+#include <QtGui/qmatrix4x4.h>
+#include <QtGui/qquaternion.h>
+#include <QtGui/qfont.h>
+#include <QtGui/qcolor.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q_QML_PRIVATE_EXPORT QQmlValueType : public QObject
+{
+ Q_OBJECT
+public:
+ QQmlValueType(QObject *parent = 0);
+ virtual void read(QObject *, int) = 0;
+ virtual void write(QObject *, int, QQmlPropertyPrivate::WriteFlags flags) = 0;
+ virtual QVariant value() = 0;
+ virtual void setValue(const QVariant &) = 0;
+
+ virtual QString toString() const = 0;
+ virtual bool isEqual(const QVariant &value) const = 0;
+
+ inline void onLoad();
+};
+
+class Q_QML_PRIVATE_EXPORT QQmlValueTypeFactory
+{
+public:
+ QQmlValueTypeFactory();
+ ~QQmlValueTypeFactory();
+ static bool isValueType(int);
+ static QQmlValueType *valueType(int);
+
+ static void registerBaseTypes(const char *uri, int versionMajor, int versionMinor);
+ static void registerValueTypes();
+
+ QQmlValueType *operator[](int idx) const {
+ if (idx >= (int)QVariant::UserType) return 0;
+ else return valueTypes[idx];
+ }
+
+private:
+ QQmlValueType *valueTypes[QVariant::UserType - 1];
+};
+
+// Exported for QtQuick1
+class Q_QML_PRIVATE_EXPORT QQmlPointFValueType : public QQmlValueType
+{
+ Q_PROPERTY(qreal x READ x WRITE setX)
+ Q_PROPERTY(qreal y READ y WRITE setY)
+ Q_OBJECT
+public:
+ QQmlPointFValueType(QObject *parent = 0);
+
+ virtual void read(QObject *, int);
+ virtual void write(QObject *, int, QQmlPropertyPrivate::WriteFlags);
+ virtual QVariant value();
+ virtual void setValue(const QVariant &value);
+ virtual QString toString() const;
+ virtual bool isEqual(const QVariant &value) const;
+
+ qreal x() const;
+ qreal y() const;
+ void setX(qreal);
+ void setY(qreal);
+
+private:
+ QPointF point;
+};
+
+// Exported for QtQuick1
+class Q_QML_PRIVATE_EXPORT QQmlPointValueType : public QQmlValueType
+{
+ Q_PROPERTY(int x READ x WRITE setX)
+ Q_PROPERTY(int y READ y WRITE setY)
+ Q_OBJECT
+public:
+ QQmlPointValueType(QObject *parent = 0);
+
+ virtual void read(QObject *, int);
+ virtual void write(QObject *, int, QQmlPropertyPrivate::WriteFlags);
+ virtual QVariant value();
+ virtual void setValue(const QVariant &value);
+ virtual QString toString() const;
+ virtual bool isEqual(const QVariant &value) const;
+
+ int x() const;
+ int y() const;
+ void setX(int);
+ void setY(int);
+
+private:
+ QPoint point;
+};
+
+// Exported for QtQuick1
+class Q_QML_PRIVATE_EXPORT QQmlSizeFValueType : public QQmlValueType
+{
+ Q_PROPERTY(qreal width READ width WRITE setWidth)
+ Q_PROPERTY(qreal height READ height WRITE setHeight)
+ Q_OBJECT
+public:
+ QQmlSizeFValueType(QObject *parent = 0);
+
+ virtual void read(QObject *, int);
+ virtual void write(QObject *, int, QQmlPropertyPrivate::WriteFlags);
+ virtual QVariant value();
+ virtual void setValue(const QVariant &value);
+ virtual QString toString() const;
+ virtual bool isEqual(const QVariant &value) const;
+
+ qreal width() const;
+ qreal height() const;
+ void setWidth(qreal);
+ void setHeight(qreal);
+
+private:
+ QSizeF size;
+};
+
+// Exported for QtQuick1
+class Q_QML_PRIVATE_EXPORT QQmlSizeValueType : public QQmlValueType
+{
+ Q_PROPERTY(int width READ width WRITE setWidth)
+ Q_PROPERTY(int height READ height WRITE setHeight)
+ Q_OBJECT
+public:
+ QQmlSizeValueType(QObject *parent = 0);
+
+ virtual void read(QObject *, int);
+ virtual void write(QObject *, int, QQmlPropertyPrivate::WriteFlags);
+ virtual QVariant value();
+ virtual void setValue(const QVariant &value);
+ virtual QString toString() const;
+ virtual bool isEqual(const QVariant &value) const;
+
+ int width() const;
+ int height() const;
+ void setWidth(int);
+ void setHeight(int);
+
+private:
+ QSize size;
+};
+
+// Exported for QtQuick1
+class Q_QML_PRIVATE_EXPORT QQmlRectFValueType : public QQmlValueType
+{
+ Q_PROPERTY(qreal x READ x WRITE setX)
+ Q_PROPERTY(qreal y READ y WRITE setY)
+ Q_PROPERTY(qreal width READ width WRITE setWidth)
+ Q_PROPERTY(qreal height READ height WRITE setHeight)
+ Q_OBJECT
+public:
+ QQmlRectFValueType(QObject *parent = 0);
+
+ virtual void read(QObject *, int);
+ virtual void write(QObject *, int, QQmlPropertyPrivate::WriteFlags);
+ virtual QVariant value();
+ virtual void setValue(const QVariant &value);
+ virtual QString toString() const;
+ virtual bool isEqual(const QVariant &value) const;
+
+ qreal x() const;
+ qreal y() const;
+ void setX(qreal);
+ void setY(qreal);
+
+ qreal width() const;
+ qreal height() const;
+ void setWidth(qreal);
+ void setHeight(qreal);
+
+private:
+ QRectF rect;
+};
+
+// Exported for QtQuick1
+class Q_QML_PRIVATE_EXPORT QQmlRectValueType : public QQmlValueType
+{
+ Q_PROPERTY(int x READ x WRITE setX)
+ Q_PROPERTY(int y READ y WRITE setY)
+ Q_PROPERTY(int width READ width WRITE setWidth)
+ Q_PROPERTY(int height READ height WRITE setHeight)
+ Q_OBJECT
+public:
+ QQmlRectValueType(QObject *parent = 0);
+
+ virtual void read(QObject *, int);
+ virtual void write(QObject *, int, QQmlPropertyPrivate::WriteFlags);
+ virtual QVariant value();
+ virtual void setValue(const QVariant &value);
+ virtual QString toString() const;
+ virtual bool isEqual(const QVariant &value) const;
+
+ int x() const;
+ int y() const;
+ void setX(int);
+ void setY(int);
+
+ int width() const;
+ int height() const;
+ void setWidth(int);
+ void setHeight(int);
+
+private:
+ QRect rect;
+};
+
+class Q_QML_PRIVATE_EXPORT QQmlVector2DValueType : public QQmlValueType
+{
+ Q_PROPERTY(qreal x READ x WRITE setX)
+ Q_PROPERTY(qreal y READ y WRITE setY)
+ Q_OBJECT
+public:
+ QQmlVector2DValueType(QObject *parent = 0);
+
+ virtual void read(QObject *, int);
+ virtual void write(QObject *, int, QQmlPropertyPrivate::WriteFlags);
+ virtual QVariant value();
+ virtual void setValue(const QVariant &value);
+ virtual QString toString() const;
+ virtual bool isEqual(const QVariant &value) const;
+
+ qreal x() const;
+ qreal y() const;
+ void setX(qreal);
+ void setY(qreal);
+
+private:
+ QVector2D vector;
+};
+
+class Q_QML_PRIVATE_EXPORT QQmlVector3DValueType : public QQmlValueType
+{
+ Q_PROPERTY(qreal x READ x WRITE setX)
+ Q_PROPERTY(qreal y READ y WRITE setY)
+ Q_PROPERTY(qreal z READ z WRITE setZ)
+ Q_OBJECT
+public:
+ QQmlVector3DValueType(QObject *parent = 0);
+
+ virtual void read(QObject *, int);
+ virtual void write(QObject *, int, QQmlPropertyPrivate::WriteFlags);
+ virtual QVariant value();
+ virtual void setValue(const QVariant &value);
+ virtual QString toString() const;
+ virtual bool isEqual(const QVariant &value) const;
+
+ qreal x() const;
+ qreal y() const;
+ qreal z() const;
+ void setX(qreal);
+ void setY(qreal);
+ void setZ(qreal);
+
+private:
+ QVector3D vector;
+};
+
+class Q_QML_PRIVATE_EXPORT QQmlVector4DValueType : public QQmlValueType
+{
+ Q_PROPERTY(qreal x READ x WRITE setX)
+ Q_PROPERTY(qreal y READ y WRITE setY)
+ Q_PROPERTY(qreal z READ z WRITE setZ)
+ Q_PROPERTY(qreal w READ w WRITE setW)
+ Q_OBJECT
+public:
+ QQmlVector4DValueType(QObject *parent = 0);
+
+ virtual void read(QObject *, int);
+ virtual void write(QObject *, int, QQmlPropertyPrivate::WriteFlags);
+ virtual QVariant value();
+ virtual void setValue(const QVariant &value);
+ virtual QString toString() const;
+ virtual bool isEqual(const QVariant &value) const;
+
+ qreal x() const;
+ qreal y() const;
+ qreal z() const;
+ qreal w() const;
+ void setX(qreal);
+ void setY(qreal);
+ void setZ(qreal);
+ void setW(qreal);
+
+private:
+ QVector4D vector;
+};
+
+class Q_QML_PRIVATE_EXPORT QQmlQuaternionValueType : public QQmlValueType
+{
+ Q_PROPERTY(qreal scalar READ scalar WRITE setScalar)
+ Q_PROPERTY(qreal x READ x WRITE setX)
+ Q_PROPERTY(qreal y READ y WRITE setY)
+ Q_PROPERTY(qreal z READ z WRITE setZ)
+ Q_OBJECT
+public:
+ QQmlQuaternionValueType(QObject *parent = 0);
+
+ virtual void read(QObject *, int);
+ virtual void write(QObject *, int, QQmlPropertyPrivate::WriteFlags);
+ virtual QVariant value();
+ virtual void setValue(const QVariant &value);
+ virtual QString toString() const;
+ virtual bool isEqual(const QVariant &value) const;
+
+ qreal scalar() const;
+ qreal x() const;
+ qreal y() const;
+ qreal z() const;
+ void setScalar(qreal);
+ void setX(qreal);
+ void setY(qreal);
+ void setZ(qreal);
+
+private:
+ QQuaternion quaternion;
+};
+
+class Q_QML_PRIVATE_EXPORT QQmlMatrix4x4ValueType : public QQmlValueType
+{
+ Q_PROPERTY(qreal m11 READ m11 WRITE setM11)
+ Q_PROPERTY(qreal m12 READ m12 WRITE setM12)
+ Q_PROPERTY(qreal m13 READ m13 WRITE setM13)
+ Q_PROPERTY(qreal m14 READ m14 WRITE setM14)
+ Q_PROPERTY(qreal m21 READ m21 WRITE setM21)
+ Q_PROPERTY(qreal m22 READ m22 WRITE setM22)
+ Q_PROPERTY(qreal m23 READ m23 WRITE setM23)
+ Q_PROPERTY(qreal m24 READ m24 WRITE setM24)
+ Q_PROPERTY(qreal m31 READ m31 WRITE setM31)
+ Q_PROPERTY(qreal m32 READ m32 WRITE setM32)
+ Q_PROPERTY(qreal m33 READ m33 WRITE setM33)
+ Q_PROPERTY(qreal m34 READ m34 WRITE setM34)
+ Q_PROPERTY(qreal m41 READ m41 WRITE setM41)
+ Q_PROPERTY(qreal m42 READ m42 WRITE setM42)
+ Q_PROPERTY(qreal m43 READ m43 WRITE setM43)
+ Q_PROPERTY(qreal m44 READ m44 WRITE setM44)
+ Q_OBJECT
+public:
+ QQmlMatrix4x4ValueType(QObject *parent = 0);
+
+ virtual void read(QObject *, int);
+ virtual void write(QObject *, int, QQmlPropertyPrivate::WriteFlags);
+ virtual QVariant value();
+ virtual void setValue(const QVariant &value);
+ virtual QString toString() const;
+ virtual bool isEqual(const QVariant &value) const;
+
+ qreal m11() const { return matrix(0, 0); }
+ qreal m12() const { return matrix(0, 1); }
+ qreal m13() const { return matrix(0, 2); }
+ qreal m14() const { return matrix(0, 3); }
+ qreal m21() const { return matrix(1, 0); }
+ qreal m22() const { return matrix(1, 1); }
+ qreal m23() const { return matrix(1, 2); }
+ qreal m24() const { return matrix(1, 3); }
+ qreal m31() const { return matrix(2, 0); }
+ qreal m32() const { return matrix(2, 1); }
+ qreal m33() const { return matrix(2, 2); }
+ qreal m34() const { return matrix(2, 3); }
+ qreal m41() const { return matrix(3, 0); }
+ qreal m42() const { return matrix(3, 1); }
+ qreal m43() const { return matrix(3, 2); }
+ qreal m44() const { return matrix(3, 3); }
+
+ void setM11(qreal value) { matrix(0, 0) = value; }
+ void setM12(qreal value) { matrix(0, 1) = value; }
+ void setM13(qreal value) { matrix(0, 2) = value; }
+ void setM14(qreal value) { matrix(0, 3) = value; }
+ void setM21(qreal value) { matrix(1, 0) = value; }
+ void setM22(qreal value) { matrix(1, 1) = value; }
+ void setM23(qreal value) { matrix(1, 2) = value; }
+ void setM24(qreal value) { matrix(1, 3) = value; }
+ void setM31(qreal value) { matrix(2, 0) = value; }
+ void setM32(qreal value) { matrix(2, 1) = value; }
+ void setM33(qreal value) { matrix(2, 2) = value; }
+ void setM34(qreal value) { matrix(2, 3) = value; }
+ void setM41(qreal value) { matrix(3, 0) = value; }
+ void setM42(qreal value) { matrix(3, 1) = value; }
+ void setM43(qreal value) { matrix(3, 2) = value; }
+ void setM44(qreal value) { matrix(3, 3) = value; }
+
+private:
+ QMatrix4x4 matrix;
+};
+
+class Q_QML_PRIVATE_EXPORT QQmlEasingValueType : public QQmlValueType
+{
+ Q_OBJECT
+ Q_ENUMS(Type)
+
+ Q_PROPERTY(QQmlEasingValueType::Type type READ type WRITE setType)
+ Q_PROPERTY(qreal amplitude READ amplitude WRITE setAmplitude)
+ Q_PROPERTY(qreal overshoot READ overshoot WRITE setOvershoot)
+ Q_PROPERTY(qreal period READ period WRITE setPeriod)
+ Q_PROPERTY(QVariantList bezierCurve READ bezierCurve WRITE setBezierCurve)
+public:
+ enum Type {
+ Linear = QEasingCurve::Linear,
+ InQuad = QEasingCurve::InQuad, OutQuad = QEasingCurve::OutQuad,
+ InOutQuad = QEasingCurve::InOutQuad, OutInQuad = QEasingCurve::OutInQuad,
+ InCubic = QEasingCurve::InCubic, OutCubic = QEasingCurve::OutCubic,
+ InOutCubic = QEasingCurve::InOutCubic, OutInCubic = QEasingCurve::OutInCubic,
+ InQuart = QEasingCurve::InQuart, OutQuart = QEasingCurve::OutQuart,
+ InOutQuart = QEasingCurve::InOutQuart, OutInQuart = QEasingCurve::OutInQuart,
+ InQuint = QEasingCurve::InQuint, OutQuint = QEasingCurve::OutQuint,
+ InOutQuint = QEasingCurve::InOutQuint, OutInQuint = QEasingCurve::OutInQuint,
+ InSine = QEasingCurve::InSine, OutSine = QEasingCurve::OutSine,
+ InOutSine = QEasingCurve::InOutSine, OutInSine = QEasingCurve::OutInSine,
+ InExpo = QEasingCurve::InExpo, OutExpo = QEasingCurve::OutExpo,
+ InOutExpo = QEasingCurve::InOutExpo, OutInExpo = QEasingCurve::OutInExpo,
+ InCirc = QEasingCurve::InCirc, OutCirc = QEasingCurve::OutCirc,
+ InOutCirc = QEasingCurve::InOutCirc, OutInCirc = QEasingCurve::OutInCirc,
+ InElastic = QEasingCurve::InElastic, OutElastic = QEasingCurve::OutElastic,
+ InOutElastic = QEasingCurve::InOutElastic, OutInElastic = QEasingCurve::OutInElastic,
+ InBack = QEasingCurve::InBack, OutBack = QEasingCurve::OutBack,
+ InOutBack = QEasingCurve::InOutBack, OutInBack = QEasingCurve::OutInBack,
+ InBounce = QEasingCurve::InBounce, OutBounce = QEasingCurve::OutBounce,
+ InOutBounce = QEasingCurve::InOutBounce, OutInBounce = QEasingCurve::OutInBounce,
+ InCurve = QEasingCurve::InCurve, OutCurve = QEasingCurve::OutCurve,
+ SineCurve = QEasingCurve::SineCurve, CosineCurve = QEasingCurve::CosineCurve,
+ Bezier = QEasingCurve::BezierSpline
+ };
+
+ QQmlEasingValueType(QObject *parent = 0);
+
+ virtual void read(QObject *, int);
+ virtual void write(QObject *, int, QQmlPropertyPrivate::WriteFlags);
+ virtual QVariant value();
+ virtual void setValue(const QVariant &value);
+ virtual QString toString() const;
+ virtual bool isEqual(const QVariant &value) const;
+
+ Type type() const;
+ qreal amplitude() const;
+ qreal overshoot() const;
+ qreal period() const;
+ void setType(Type);
+ void setAmplitude(qreal);
+ void setOvershoot(qreal);
+ void setPeriod(qreal);
+ void setBezierCurve(const QVariantList &);
+ QVariantList bezierCurve() const;
+
+
+private:
+ QEasingCurve easing;
+};
+
+class Q_QML_PRIVATE_EXPORT QQmlFontValueType : public QQmlValueType
+{
+ Q_OBJECT
+ Q_ENUMS(FontWeight)
+ Q_ENUMS(Capitalization)
+
+ Q_PROPERTY(QString family READ family WRITE setFamily)
+ Q_PROPERTY(bool bold READ bold WRITE setBold)
+ Q_PROPERTY(FontWeight weight READ weight WRITE setWeight)
+ Q_PROPERTY(bool italic READ italic WRITE setItalic)
+ Q_PROPERTY(bool underline READ underline WRITE setUnderline)
+ Q_PROPERTY(bool overline READ overline WRITE setOverline)
+ Q_PROPERTY(bool strikeout READ strikeout WRITE setStrikeout)
+ Q_PROPERTY(qreal pointSize READ pointSize WRITE setPointSize)
+ Q_PROPERTY(int pixelSize READ pixelSize WRITE setPixelSize)
+ Q_PROPERTY(Capitalization capitalization READ capitalization WRITE setCapitalization)
+ Q_PROPERTY(qreal letterSpacing READ letterSpacing WRITE setLetterSpacing)
+ Q_PROPERTY(qreal wordSpacing READ wordSpacing WRITE setWordSpacing)
+
+public:
+ enum FontWeight { Light = QFont::Light,
+ Normal = QFont::Normal,
+ DemiBold = QFont::DemiBold,
+ Bold = QFont::Bold,
+ Black = QFont::Black };
+ enum Capitalization { MixedCase = QFont::MixedCase,
+ AllUppercase = QFont::AllUppercase,
+ AllLowercase = QFont::AllLowercase,
+ SmallCaps = QFont::SmallCaps,
+ Capitalize = QFont::Capitalize };
+
+ QQmlFontValueType(QObject *parent = 0);
+
+ virtual void read(QObject *, int);
+ virtual void write(QObject *, int, QQmlPropertyPrivate::WriteFlags);
+ virtual QVariant value();
+ virtual void setValue(const QVariant &value);
+ virtual QString toString() const;
+ virtual bool isEqual(const QVariant &value) const;
+
+ QString family() const;
+ void setFamily(const QString &);
+
+ bool bold() const;
+ void setBold(bool b);
+
+ FontWeight weight() const;
+ void setWeight(FontWeight);
+
+ bool italic() const;
+ void setItalic(bool b);
+
+ bool underline() const;
+ void setUnderline(bool b);
+
+ bool overline() const;
+ void setOverline(bool b);
+
+ bool strikeout() const;
+ void setStrikeout(bool b);
+
+ qreal pointSize() const;
+ void setPointSize(qreal size);
+
+ int pixelSize() const;
+ void setPixelSize(int size);
+
+ Capitalization capitalization() const;
+ void setCapitalization(Capitalization);
+
+ qreal letterSpacing() const;
+ void setLetterSpacing(qreal spacing);
+
+ qreal wordSpacing() const;
+ void setWordSpacing(qreal spacing);
+
+ void onLoad();
+private:
+ QFont font;
+ bool pixelSizeSet;
+ bool pointSizeSet;
+ mutable QQmlNullableValue<int> dpi;
+};
+
+class Q_QML_PRIVATE_EXPORT QQmlColorValueType : public QQmlValueType
+{
+ Q_PROPERTY(qreal r READ r WRITE setR)
+ Q_PROPERTY(qreal g READ g WRITE setG)
+ Q_PROPERTY(qreal b READ b WRITE setB)
+ Q_PROPERTY(qreal a READ a WRITE setA)
+ Q_OBJECT
+public:
+ QQmlColorValueType(QObject *parent = 0);
+
+ virtual void read(QObject *, int);
+ virtual void write(QObject *, int, QQmlPropertyPrivate::WriteFlags);
+ virtual QVariant value();
+ virtual void setValue(const QVariant &value);
+ virtual QString toString() const;
+ virtual bool isEqual(const QVariant &value) const;
+
+ qreal r() const;
+ qreal g() const;
+ qreal b() const;
+ qreal a() const;
+ void setR(qreal);
+ void setG(qreal);
+ void setB(qreal);
+ void setA(qreal);
+
+private:
+ QColor color;
+};
+
+void QQmlValueType::onLoad()
+{
+}
+
+QT_END_NAMESPACE
+
+#endif // QQMLVALUETYPE_P_H
diff --git a/src/qml/qml/qqmlvme.cpp b/src/qml/qml/qqmlvme.cpp
new file mode 100644
index 0000000000..2b66e00bad
--- /dev/null
+++ b/src/qml/qml/qqmlvme.cpp
@@ -0,0 +1,1370 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qqmlvme_p.h"
+
+#include "qqmlcompiler_p.h"
+#include "qqmlboundsignal_p.h"
+#include "qqmlstringconverters_p.h"
+#include <private/qmetaobjectbuilder_p.h>
+#include <private/qfastmetabuilder_p.h>
+#include "qqmldata_p.h"
+#include "qqml.h"
+#include "qqmlcustomparser_p.h"
+#include "qqmlengine.h"
+#include "qqmlcontext.h"
+#include "qqmlcomponent.h"
+#include "qqmlcomponentattached_p.h"
+#include "qqmlbinding_p.h"
+#include "qqmlengine_p.h"
+#include "qqmlcomponent_p.h"
+#include "qqmlvmemetaobject_p.h"
+#include "qqmlbinding_p_p.h"
+#include "qqmlcontext_p.h"
+#include <private/qv4bindings_p.h>
+#include <private/qv8bindings_p.h>
+#include "qqmlglobal_p.h"
+#include <private/qfinitestack_p.h>
+#include "qqmlscriptstring.h"
+#include "qqmlscriptstring_p.h"
+#include "qqmlpropertyvalueinterceptor_p.h"
+
+#include <QStack>
+#include <QColor>
+#include <QPointF>
+#include <QSizeF>
+#include <QRectF>
+#include <QtCore/qdebug.h>
+#include <QtCore/qvarlengtharray.h>
+#include <QtCore/qcoreapplication.h>
+#include <QtCore/qdatetime.h>
+#include <QtCore/qvarlengtharray.h>
+#include <QtQml/qjsvalue.h>
+
+QT_BEGIN_NAMESPACE
+
+using namespace QQmlVMETypes;
+
+#define VME_EXCEPTION(desc, line) \
+ { \
+ QQmlError error; \
+ error.setDescription(desc.trimmed()); \
+ error.setLine(line); \
+ error.setUrl(COMP->url); \
+ *errors << error; \
+ goto exceptionExit; \
+ }
+
+void QQmlVME::init(QQmlContextData *ctxt, QQmlCompiledData *comp, int start,
+ QQmlContextData *creation)
+{
+ Q_ASSERT(ctxt);
+ Q_ASSERT(comp);
+
+ if (start == -1) {
+ start = 0;
+ } else {
+ creationContext = creation;
+ }
+
+ State initState;
+ initState.context = ctxt;
+ initState.compiledData = comp;
+ initState.instructionStream = comp->bytecode.constData() + start;
+ states.push(initState);
+
+ typedef QQmlInstruction I;
+ I *i = (I *)initState.instructionStream;
+
+ Q_ASSERT(comp->instructionType(i) == I::Init);
+
+ objects.allocate(i->init.objectStackSize);
+ lists.allocate(i->init.listStackSize);
+ bindValues.allocate(i->init.bindingsSize);
+ parserStatus.allocate(i->init.parserStatusSize);
+
+#ifdef QML_ENABLE_TRACE
+ parserStatusData.allocate(i->init.parserStatusSize);
+ rootComponent = comp;
+#endif
+
+ rootContext = 0;
+ engine = ctxt->engine;
+}
+
+bool QQmlVME::initDeferred(QObject *object)
+{
+ QQmlData *data = QQmlData::get(object);
+
+ if (!data || !data->context || !data->deferredComponent)
+ return false;
+
+ QQmlContextData *ctxt = data->context;
+ QQmlCompiledData *comp = data->deferredComponent;
+ int start = data->deferredIdx;
+
+ State initState;
+ initState.flags = State::Deferred;
+ initState.context = ctxt;
+ initState.compiledData = comp;
+ initState.instructionStream = comp->bytecode.constData() + start;
+ states.push(initState);
+
+ typedef QQmlInstruction I;
+ I *i = (I *)initState.instructionStream;
+
+ Q_ASSERT(comp->instructionType(i) == I::DeferInit);
+
+ objects.allocate(i->deferInit.objectStackSize);
+ lists.allocate(i->deferInit.listStackSize);
+ bindValues.allocate(i->deferInit.bindingsSize);
+ parserStatus.allocate(i->deferInit.parserStatusSize);
+
+ objects.push(object);
+
+#ifdef QML_ENABLE_TRACE
+ parserStatusData.allocate(i->deferInit.parserStatusSize);
+ rootComponent = comp;
+#endif
+
+ rootContext = 0;
+ engine = ctxt->engine;
+
+ return true;
+}
+
+namespace {
+struct ActiveVMERestorer
+{
+ ActiveVMERestorer(QQmlVME *me, QQmlEnginePrivate *ep)
+ : ep(ep), oldVME(ep->activeVME) { ep->activeVME = me; }
+ ~ActiveVMERestorer() { ep->activeVME = oldVME; }
+
+ QQmlEnginePrivate *ep;
+ QQmlVME *oldVME;
+};
+}
+
+QObject *QQmlVME::execute(QList<QQmlError> *errors, const Interrupt &interrupt)
+{
+ Q_ASSERT(states.count() >= 1);
+
+#ifdef QML_ENABLE_TRACE
+ QQmlTrace trace("VME Execute");
+ trace.addDetail("URL", rootComponent->url);
+#endif
+
+ QQmlEnginePrivate *ep = QQmlEnginePrivate::get(states.at(0).context->engine);
+
+ ActiveVMERestorer restore(this, ep);
+
+ QObject *rv = run(errors, interrupt);
+
+ return rv;
+}
+
+inline bool fastHasBinding(QObject *o, int index)
+{
+ QQmlData *ddata = static_cast<QQmlData *>(QObjectPrivate::get(o)->declarativeData);
+
+ return ddata && (ddata->bindingBitsSize > index) &&
+ (ddata->bindingBits[index / 32] & (1 << (index % 32)));
+}
+
+static void removeBindingOnProperty(QObject *o, int index)
+{
+ QQmlAbstractBinding *binding = QQmlPropertyPrivate::setBinding(o, index, -1, 0);
+ if (binding) binding->destroy();
+}
+
+static QVariant variantFromString(const QString &string)
+{
+ return QQmlStringConverters::variantFromString(string);
+}
+
+// XXX we probably need some form of "work count" here to prevent us checking this
+// for every instruction.
+#define QML_BEGIN_INSTR_COMMON(I) { \
+ const QQmlInstructionMeta<(int)QQmlInstruction::I>::DataType &instr = QQmlInstructionMeta<(int)QQmlInstruction::I>::data(*genericInstr); \
+ INSTRUCTIONSTREAM += QQmlInstructionMeta<(int)QQmlInstruction::I>::Size; \
+ Q_UNUSED(instr);
+
+#ifdef QML_THREADED_VME_INTERPRETER
+# define QML_BEGIN_INSTR(I) op_##I: \
+ QML_BEGIN_INSTR_COMMON(I)
+
+# define QML_NEXT_INSTR(I) { \
+ if (watcher.hasRecursed()) return 0; \
+ genericInstr = reinterpret_cast<const QQmlInstruction *>(INSTRUCTIONSTREAM); \
+ goto *genericInstr->common.code; \
+ }
+
+# define QML_END_INSTR(I) } \
+ if (watcher.hasRecursed()) return 0; \
+ genericInstr = reinterpret_cast<const QQmlInstruction *>(INSTRUCTIONSTREAM); \
+ if (interrupt.shouldInterrupt()) return 0; \
+ goto *genericInstr->common.code;
+
+#else
+# define QML_BEGIN_INSTR(I) \
+ case QQmlInstruction::I: \
+ QML_BEGIN_INSTR_COMMON(I)
+
+# define QML_NEXT_INSTR(I) { \
+ if (watcher.hasRecursed()) return 0; \
+ break; \
+ }
+
+# define QML_END_INSTR(I) \
+ if (watcher.hasRecursed() || interrupt.shouldInterrupt()) return 0; \
+ } break;
+#endif
+
+#define QML_STORE_VALUE(name, cpptype, value) \
+ QML_BEGIN_INSTR(name) \
+ cpptype v = value; \
+ void *a[] = { (void *)&v, 0, &status, &flags }; \
+ QObject *target = objects.top(); \
+ CLEAN_PROPERTY(target, instr.propertyIndex); \
+ QMetaObject::metacall(target, QMetaObject::WriteProperty, instr.propertyIndex, a); \
+ QML_END_INSTR(name)
+
+#define QML_STORE_LIST(name, cpptype, value) \
+ QML_BEGIN_INSTR(name) \
+ cpptype v; \
+ v.append(value); \
+ void *a[] = { (void *)&v, 0, &status, &flags }; \
+ QObject *target = objects.top(); \
+ CLEAN_PROPERTY(target, instr.propertyIndex); \
+ QMetaObject::metacall(target, QMetaObject::WriteProperty, instr.propertyIndex, a); \
+ QML_END_INSTR(name)
+
+#define QML_STORE_VAR(name, value) \
+ QML_BEGIN_INSTR(name) \
+ v8::Handle<v8::Value> v8value = value; \
+ QObject *target = objects.top(); \
+ CLEAN_PROPERTY(target, instr.propertyIndex); \
+ QMetaObject *mo = const_cast<QMetaObject *>(target->metaObject()); \
+ QQmlVMEMetaObject *vmemo = static_cast<QQmlVMEMetaObject *>(mo); \
+ vmemo->setVMEProperty(instr.propertyIndex, v8value); \
+ QML_END_INSTR(name)
+
+#define QML_STORE_POINTER(name, value) \
+ QML_BEGIN_INSTR(name) \
+ void *a[] = { (void *)value, 0, &status, &flags }; \
+ QObject *target = objects.top(); \
+ CLEAN_PROPERTY(target, instr.propertyIndex); \
+ QMetaObject::metacall(target, QMetaObject::WriteProperty, instr.propertyIndex, a); \
+ QML_END_INSTR(name)
+
+#define CLEAN_PROPERTY(o, index) \
+ if (fastHasBinding(o, index)) \
+ removeBindingOnProperty(o, index)
+
+QObject *QQmlVME::run(QList<QQmlError> *errors,
+ const Interrupt &interrupt
+#ifdef QML_THREADED_VME_INTERPRETER
+ , void ***storeJumpTable
+#endif
+ )
+{
+#ifdef QML_THREADED_VME_INTERPRETER
+ if (storeJumpTable) {
+#define QML_INSTR_ADDR(I, FMT) &&op_##I,
+ static void *jumpTable[] = {
+ FOR_EACH_QML_INSTR(QML_INSTR_ADDR)
+ };
+#undef QML_INSTR_ADDR
+ *storeJumpTable = jumpTable;
+ return 0;
+ }
+#endif
+ Q_ASSERT(errors->isEmpty());
+ Q_ASSERT(states.count() >= 1);
+
+ QQmlEngine *engine = states.at(0).context->engine;
+ QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine);
+
+ // Need a v8 handle scope and execution context for StoreVar instructions.
+ v8::HandleScope handleScope;
+ v8::Context::Scope contextScope(ep->v8engine()->context());
+
+ int status = -1; // needed for dbus
+ QQmlPropertyPrivate::WriteFlags flags = QQmlPropertyPrivate::BypassInterceptor |
+ QQmlPropertyPrivate::RemoveBindingOnAliasWrite;
+
+ QRecursionWatcher<QQmlVME, &QQmlVME::recursion> watcher(this);
+
+#define COMP states.top().compiledData
+#define CTXT states.top().context
+#define INSTRUCTIONSTREAM states.top().instructionStream
+#define BINDINGSKIPLIST states.top().bindingSkipList
+
+#define TYPES COMP->types
+#define PRIMITIVES COMP->primitives
+#define DATAS COMP->datas
+#define PROGRAMS COMP->programs
+#define PROPERTYCACHES COMP->propertyCaches
+#define SCRIPTS COMP->scripts
+#define URLS COMP->urls
+
+#ifdef QML_THREADED_VME_INTERPRETER
+ const QQmlInstruction *genericInstr = reinterpret_cast<const QQmlInstruction *>(INSTRUCTIONSTREAM);
+ goto *genericInstr->common.code;
+#else
+ for (;;) {
+ const QQmlInstruction *genericInstr = reinterpret_cast<const QQmlInstruction *>(INSTRUCTIONSTREAM);
+
+ switch (genericInstr->common.instructionType) {
+#endif
+
+ // Store a created object in a property. These all pop from the objects stack.
+ QML_STORE_VALUE(StoreObject, QObject *, objects.pop());
+ QML_STORE_VALUE(StoreVariantObject, QVariant, QVariant::fromValue(objects.pop()));
+ QML_STORE_VAR(StoreVarObject, ep->v8engine()->newQObject(objects.pop()));
+
+ // Store a literal value in a corresponding property
+ QML_STORE_VALUE(StoreFloat, float, instr.value);
+ QML_STORE_VALUE(StoreDouble, double, instr.value);
+ QML_STORE_VALUE(StoreBool, bool, instr.value);
+ QML_STORE_VALUE(StoreInteger, int, instr.value);
+ QML_STORE_VALUE(StoreColor, QColor, QColor::fromRgba(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);
+ QML_STORE_POINTER(StorePoint, (QPoint *)&instr.point);
+ QML_STORE_POINTER(StorePointF, (QPointF *)&instr.point);
+ QML_STORE_POINTER(StoreSize, (QSize *)&instr.size);
+ QML_STORE_POINTER(StoreSizeF, (QSizeF *)&instr.size);
+ QML_STORE_POINTER(StoreRect, (QRect *)&instr.rect);
+ QML_STORE_POINTER(StoreRectF, (QRectF *)&instr.rect);
+ QML_STORE_POINTER(StoreVector3D, (QVector3D *)&instr.vector);
+ QML_STORE_POINTER(StoreVector4D, (QVector4D *)&instr.vector);
+ QML_STORE_POINTER(StoreString, &PRIMITIVES.at(instr.value));
+ QML_STORE_POINTER(StoreByteArray, &DATAS.at(instr.value));
+ QML_STORE_POINTER(StoreUrl, &URLS.at(instr.value));
+ QML_STORE_VALUE(StoreTrString, QString,
+ QCoreApplication::translate(DATAS.at(instr.context).constData(),
+ DATAS.at(instr.text).constData(),
+ DATAS.at(instr.comment).constData(),
+ QCoreApplication::UnicodeUTF8,
+ instr.n));
+ QML_STORE_VALUE(StoreTrIdString, QString, qtTrId(DATAS.at(instr.text).constData(), instr.n));
+
+ // Store a literal value in a QList
+ QML_STORE_LIST(StoreStringList, QStringList, PRIMITIVES.at(instr.value));
+ QML_STORE_LIST(StoreStringQList, QList<QString>, PRIMITIVES.at(instr.value));
+ QML_STORE_LIST(StoreUrlQList, QList<QUrl>, URLS.at(instr.value));
+ QML_STORE_LIST(StoreDoubleQList, QList<double>, instr.value);
+ QML_STORE_LIST(StoreBoolQList, QList<bool>, instr.value);
+ QML_STORE_LIST(StoreIntegerQList, QList<int>, instr.value);
+
+ // Store a literal value in a QVariant property
+ QML_STORE_VALUE(StoreVariant, QVariant, variantFromString(PRIMITIVES.at(instr.value)));
+ QML_STORE_VALUE(StoreVariantInteger, QVariant, QVariant(instr.value));
+ QML_STORE_VALUE(StoreVariantDouble, QVariant, QVariant(instr.value));
+ QML_STORE_VALUE(StoreVariantBool, QVariant, QVariant(instr.value));
+
+ // Store a literal value in a var property.
+ // We deliberately do not use string converters here
+ QML_STORE_VAR(StoreVar, ep->v8engine()->fromVariant(PRIMITIVES.at(instr.value)));
+ QML_STORE_VAR(StoreVarInteger, v8::Integer::New(instr.value));
+ QML_STORE_VAR(StoreVarDouble, v8::Number::New(instr.value));
+ QML_STORE_VAR(StoreVarBool, v8::Boolean::New(instr.value));
+
+
+ QML_BEGIN_INSTR(Init)
+ // Ensure that the compiled data has been initialized
+ if (!COMP->isInitialized()) COMP->initialize(engine);
+
+ QQmlContextData *parentCtxt = CTXT;
+ CTXT = new QQmlContextData;
+ CTXT->isInternal = true;
+ CTXT->url = COMP->url;
+ CTXT->urlString = COMP->name;
+ CTXT->imports = COMP->importCache;
+ CTXT->imports->addref();
+ CTXT->setParent(parentCtxt);
+ if (instr.contextCache != -1)
+ CTXT->setIdPropertyData(COMP->contextCaches.at(instr.contextCache));
+ if (instr.compiledBinding != -1) {
+ const char *v4data = DATAS.at(instr.compiledBinding).constData();
+ CTXT->v4bindings = new QV4Bindings(v4data, CTXT, COMP);
+ }
+ if (states.count() == 1) {
+ rootContext = CTXT;
+ rootContext->activeVMEData = data;
+ }
+ if (states.count() == 1 && !creationContext.isNull()) {
+ // A component that is logically created within another component instance shares the
+ // same instances of script imports. For example:
+ //
+ // import QtQuick 2.0
+ // import "test.js" as Test
+ // ListView {
+ // model: Test.getModel()
+ // delegate: Component {
+ // Text { text: Test.getValue(index); }
+ // }
+ // }
+ //
+ // Has the same "Test" instance. To implement this, we simply copy the v8 handles into
+ // the inner context. We have to create a fresh persistent handle for each to prevent
+ // double dispose. It is possible we could do this more efficiently using some form of
+ // referencing instead.
+ CTXT->importedScripts = creationContext->importedScripts;
+ for (int ii = 0; ii < CTXT->importedScripts.count(); ++ii)
+ CTXT->importedScripts[ii] = qPersistentNew<v8::Object>(CTXT->importedScripts[ii]);
+ }
+ QML_END_INSTR(Init)
+
+ QML_BEGIN_INSTR(DeferInit)
+ QML_END_INSTR(DeferInit)
+
+ QML_BEGIN_INSTR(Done)
+ states.pop();
+
+ if (states.isEmpty())
+ goto normalExit;
+ QML_END_INSTR(Done)
+
+ QML_BEGIN_INSTR(CreateQMLObject)
+ const QQmlCompiledData::TypeReference &type = TYPES.at(instr.type);
+ Q_ASSERT(type.component);
+
+ states.push(State());
+
+ State *cState = &states[states.count() - 2];
+ State *nState = &states[states.count() - 1];
+
+ nState->context = cState->context;
+ nState->compiledData = type.component;
+ nState->instructionStream = type.component->bytecode.constData();
+
+ if (instr.bindingBits != -1) {
+ const QByteArray &bits = cState->compiledData->datas.at(instr.bindingBits);
+ nState->bindingSkipList = QBitField((const quint32*)bits.constData(),
+ bits.size() * 8);
+ }
+ if (instr.isRoot)
+ nState->bindingSkipList = nState->bindingSkipList.united(cState->bindingSkipList);
+
+ // As the state in the state stack changed, execution will continue in the new program.
+ QML_END_INSTR(CreateQMLObject)
+
+ QML_BEGIN_INSTR(CompleteQMLObject)
+ QObject *o = objects.top();
+
+ QQmlData *ddata = QQmlData::get(o);
+ Q_ASSERT(ddata);
+
+ if (instr.isRoot) {
+ if (ddata->context) {
+ Q_ASSERT(ddata->context != CTXT);
+ Q_ASSERT(ddata->outerContext);
+ Q_ASSERT(ddata->outerContext != CTXT);
+ QQmlContextData *c = ddata->context;
+ while (c->linkedContext) c = c->linkedContext;
+ c->linkedContext = CTXT;
+ } else {
+ CTXT->addObject(o);
+ }
+
+ ddata->ownContext = true;
+ } else if (!ddata->context) {
+ CTXT->addObject(o);
+ }
+
+ ddata->setImplicitDestructible();
+ ddata->outerContext = CTXT;
+ ddata->lineNumber = instr.line;
+ ddata->columnNumber = instr.column;
+ QML_END_INSTR(CompleteQMLObject)
+
+ QML_BEGIN_INSTR(CreateCppObject)
+ const QQmlCompiledData::TypeReference &type = TYPES.at(instr.type);
+ Q_ASSERT(type.type);
+
+ QObject *o = 0;
+ void *memory = 0;
+ type.type->create(&o, &memory, sizeof(QQmlData));
+ QQmlData *ddata = new (memory) QQmlData;
+ ddata->ownMemory = false;
+ QObjectPrivate::get(o)->declarativeData = ddata;
+
+ if (type.typePropertyCache && !ddata->propertyCache) {
+ ddata->propertyCache = type.typePropertyCache;
+ ddata->propertyCache->addref();
+ }
+
+ if (!o)
+ VME_EXCEPTION(tr("Unable to create object of type %1").arg(type.className), instr.line);
+
+ if (instr.isRoot) {
+ if (ddata->context) {
+ Q_ASSERT(ddata->context != CTXT);
+ Q_ASSERT(ddata->outerContext);
+ Q_ASSERT(ddata->outerContext != CTXT);
+ QQmlContextData *c = ddata->context;
+ while (c->linkedContext) c = c->linkedContext;
+ c->linkedContext = CTXT;
+ } else {
+ CTXT->addObject(o);
+ }
+
+ ddata->ownContext = true;
+ } else if (!ddata->context) {
+ CTXT->addObject(o);
+ }
+
+ ddata->setImplicitDestructible();
+ ddata->outerContext = CTXT;
+ ddata->lineNumber = instr.line;
+ ddata->columnNumber = instr.column;
+
+ if (instr.data != -1) {
+ QQmlCustomParser *customParser =
+ TYPES.at(instr.type).type->customParser();
+ customParser->setCustomData(o, DATAS.at(instr.data));
+ }
+ if (!objects.isEmpty()) {
+ QObject *parent = objects.top();
+#if 0 // ### refactor
+ if (o->isWidgetType() && parent->isWidgetType())
+ static_cast<QWidget*>(o)->setParent(static_cast<QWidget*>(parent));
+ else
+#endif
+ QQml_setParent_noEvent(o, parent);
+ }
+ objects.push(o);
+ QML_END_INSTR(CreateCppObject)
+
+ QML_BEGIN_INSTR(CreateSimpleObject)
+ QObject *o = (QObject *)operator new(instr.typeSize + sizeof(QQmlData));
+ ::memset(o, 0, instr.typeSize + sizeof(QQmlData));
+ instr.create(o);
+
+ QQmlData *ddata = (QQmlData *)(((const char *)o) + instr.typeSize);
+ const QQmlCompiledData::TypeReference &ref = TYPES.at(instr.type);
+ if (!ddata->propertyCache && ref.typePropertyCache) {
+ ddata->propertyCache = ref.typePropertyCache;
+ ddata->propertyCache->addref();
+ }
+ ddata->lineNumber = instr.line;
+ ddata->columnNumber = instr.column;
+
+ QObjectPrivate::get(o)->declarativeData = ddata;
+ ddata->context = ddata->outerContext = CTXT;
+ ddata->nextContextObject = CTXT->contextObjects;
+ if (ddata->nextContextObject)
+ ddata->nextContextObject->prevContextObject = &ddata->nextContextObject;
+ ddata->prevContextObject = &CTXT->contextObjects;
+ CTXT->contextObjects = ddata;
+
+ QObject *parent = objects.top();
+ QQml_setParent_noEvent(o, parent);
+
+ objects.push(o);
+ QML_END_INSTR(CreateSimpleObject)
+
+ QML_BEGIN_INSTR(SetId)
+ QObject *target = objects.top();
+ CTXT->setIdProperty(instr.index, target);
+ QML_END_INSTR(SetId)
+
+ QML_BEGIN_INSTR(SetDefault)
+ CTXT->contextObject = objects.top();
+ QML_END_INSTR(SetDefault)
+
+ QML_BEGIN_INSTR(CreateComponent)
+ QQmlComponent *qcomp =
+ new QQmlComponent(CTXT->engine, COMP, INSTRUCTIONSTREAM - COMP->bytecode.constData(),
+ objects.isEmpty() ? 0 : objects.top());
+
+ QQmlData *ddata = QQmlData::get(qcomp, true);
+ Q_ASSERT(ddata);
+
+ CTXT->addObject(qcomp);
+
+ if (instr.isRoot)
+ ddata->ownContext = true;
+
+ ddata->setImplicitDestructible();
+ ddata->outerContext = CTXT;
+ ddata->lineNumber = instr.line;
+ ddata->columnNumber = instr.column;
+
+ QQmlComponentPrivate::get(qcomp)->creationContext = CTXT;
+
+ objects.push(qcomp);
+ INSTRUCTIONSTREAM += instr.count;
+ QML_END_INSTR(CreateComponent)
+
+ QML_BEGIN_INSTR(StoreMetaObject)
+ QObject *target = objects.top();
+
+ QMetaObject mo;
+ const QByteArray &metadata = DATAS.at(instr.data);
+ QFastMetaBuilder::fromData(&mo, 0, metadata);
+
+ const QQmlVMEMetaData *data =
+ (const QQmlVMEMetaData *)DATAS.at(instr.aliasData).constData();
+
+ (void)new QQmlVMEMetaObject(target, &mo, data, COMP);
+
+ if (instr.propertyCache != -1) {
+ QQmlData *ddata = QQmlData::get(target, true);
+ if (ddata->propertyCache) ddata->propertyCache->release();
+ ddata->propertyCache = PROPERTYCACHES.at(instr.propertyCache);
+ ddata->propertyCache->addref();
+ }
+ QML_END_INSTR(StoreMetaObject)
+
+ QML_BEGIN_INSTR(AssignCustomType)
+ QObject *target = objects.top();
+ CLEAN_PROPERTY(target, instr.propertyIndex);
+
+ const QString &primitive = PRIMITIVES.at(instr.primitive);
+ int type = instr.type;
+ QQmlMetaType::StringConverter converter = QQmlMetaType::customStringConverter(type);
+ QVariant v = (*converter)(primitive);
+
+ QMetaProperty prop =
+ target->metaObject()->property(instr.propertyIndex);
+ if (v.isNull() || ((int)prop.type() != type && prop.userType() != type))
+ VME_EXCEPTION(tr("Cannot assign value %1 to property %2").arg(primitive).arg(QString::fromUtf8(prop.name())), instr.line);
+
+ void *a[] = { (void *)v.data(), 0, &status, &flags };
+ QMetaObject::metacall(target, QMetaObject::WriteProperty,
+ instr.propertyIndex, a);
+ QML_END_INSTR(AssignCustomType)
+
+ QML_BEGIN_INSTR(AssignSignalObject)
+ // XXX optimize
+
+ QObject *assign = objects.pop();
+ QObject *target = objects.top();
+ int sigIdx = instr.signal;
+ const QString &pr = PRIMITIVES.at(sigIdx);
+
+ QQmlProperty prop(target, pr);
+ if (prop.type() & QQmlProperty::SignalProperty) {
+
+ QMetaMethod method = QQmlMetaType::defaultMethod(assign);
+ if (method.signature() == 0)
+ VME_EXCEPTION(tr("Cannot assign object type %1 with no default method").arg(QString::fromLatin1(assign->metaObject()->className())), instr.line);
+
+ if (!QMetaObject::checkConnectArgs(prop.method().signature(), method.signature()))
+ VME_EXCEPTION(tr("Cannot connect mismatched signal/slot %1 %vs. %2").arg(QString::fromLatin1(method.signature())).arg(QString::fromLatin1(prop.method().signature())), instr.line);
+
+ QQmlPropertyPrivate::connect(target, prop.index(), assign, method.methodIndex());
+
+ } else {
+ VME_EXCEPTION(tr("Cannot assign an object to signal property %1").arg(pr), instr.line);
+ }
+
+
+ QML_END_INSTR(AssignSignalObject)
+
+ QML_BEGIN_INSTR(StoreSignal)
+ QObject *target = objects.top();
+ QObject *context = objects.at(objects.count() - 1 - instr.context);
+
+ QMetaMethod signal = target->metaObject()->method(instr.signalIndex);
+
+ QQmlBoundSignal *bs = new QQmlBoundSignal(target, signal, target);
+ QQmlExpression *expr =
+ new QQmlExpression(CTXT, context, DATAS.at(instr.value), true, COMP->name, instr.line, instr.column, *new QQmlExpressionPrivate);
+ bs->setExpression(expr);
+ QML_END_INSTR(StoreSignal)
+
+ QML_BEGIN_INSTR(StoreImportedScript)
+ CTXT->importedScripts << run(CTXT, SCRIPTS.at(instr.value));
+ QML_END_INSTR(StoreImportedScript)
+
+ QML_BEGIN_INSTR(StoreScriptString)
+ QObject *target = objects.top();
+ QObject *scope = objects.at(objects.count() - 1 - instr.scope);
+ QQmlScriptString ss;
+ ss.setContext(CTXT->asQQmlContext());
+ ss.setScopeObject(scope);
+ ss.setScript(PRIMITIVES.at(instr.value));
+ ss.d.data()->bindingId = instr.bindingId;
+ ss.d.data()->lineNumber = instr.line;
+ ss.d.data()->columnNumber = instr.column;
+
+ void *a[] = { &ss, 0, &status, &flags };
+ QMetaObject::metacall(target, QMetaObject::WriteProperty,
+ instr.propertyIndex, a);
+ QML_END_INSTR(StoreScriptString)
+
+ QML_BEGIN_INSTR(BeginObject)
+ QObject *target = objects.top();
+ QQmlParserStatus *status = reinterpret_cast<QQmlParserStatus *>(reinterpret_cast<char *>(target) + instr.castValue);
+ parserStatus.push(status);
+#ifdef QML_ENABLE_TRACE
+ Q_ASSERT(QObjectPrivate::get(target)->declarativeData);
+ parserStatusData.push(static_cast<QQmlData *>(QObjectPrivate::get(target)->declarativeData));
+#endif
+ status->d = &parserStatus.top();
+
+ status->classBegin();
+ QML_END_INSTR(BeginObject)
+
+ QML_BEGIN_INSTR(InitV8Bindings)
+ CTXT->v8bindings = new QV8Bindings(&PROGRAMS[instr.programIndex], instr.line, CTXT);
+ QML_END_INSTR(InitV8Bindings)
+
+ QML_BEGIN_INSTR(StoreBinding)
+ QObject *target =
+ objects.at(objects.count() - 1 - instr.owner);
+ QObject *context =
+ objects.at(objects.count() - 1 - instr.context);
+
+ if (instr.isRoot && BINDINGSKIPLIST.testBit(instr.property.coreIndex))
+ QML_NEXT_INSTR(StoreBinding);
+
+ QQmlBinding *bind = new QQmlBinding(PRIMITIVES.at(instr.value), true,
+ context, CTXT, COMP->name, instr.line,
+ instr.column);
+ bindValues.push(bind);
+ bind->m_mePtr = &bindValues.top();
+ bind->setTarget(target, instr.property, CTXT);
+
+ typedef QQmlPropertyPrivate QDPP;
+ Q_ASSERT(bind->propertyIndex() == QDPP::bindingIndex(instr.property));
+ Q_ASSERT(bind->object() == target);
+
+ bind->addToObject();
+ QML_END_INSTR(StoreBinding)
+
+ QML_BEGIN_INSTR(StoreBindingOnAlias)
+ QObject *target =
+ objects.at(objects.count() - 1 - instr.owner);
+ QObject *context =
+ objects.at(objects.count() - 1 - instr.context);
+
+ if (instr.isRoot && BINDINGSKIPLIST.testBit(instr.property.coreIndex))
+ QML_NEXT_INSTR(StoreBindingOnAlias);
+
+ QQmlBinding *bind = new QQmlBinding(PRIMITIVES.at(instr.value), true,
+ context, CTXT, COMP->name, instr.line,
+ instr.column);
+ bindValues.push(bind);
+ bind->m_mePtr = &bindValues.top();
+ bind->setTarget(target, instr.property, CTXT);
+
+ QQmlAbstractBinding *old =
+ QQmlPropertyPrivate::setBindingNoEnable(target, instr.property.coreIndex,
+ instr.property.getValueTypeCoreIndex(),
+ bind);
+ if (old) { old->destroy(); }
+ QML_END_INSTR(StoreBindingOnAlias)
+
+ QML_BEGIN_INSTR(StoreV4Binding)
+ QObject *target =
+ objects.at(objects.count() - 1 - instr.owner);
+ QObject *scope =
+ objects.at(objects.count() - 1 - instr.context);
+
+ int property = instr.property;
+ if (instr.isRoot && BINDINGSKIPLIST.testBit(property & 0xFFFF))
+ QML_NEXT_INSTR(StoreV4Binding);
+
+ QQmlAbstractBinding *binding =
+ CTXT->v4bindings->configBinding(instr.value, target, scope, property,
+ instr.line, instr.column);
+ bindValues.push(binding);
+ binding->m_mePtr = &bindValues.top();
+
+ Q_ASSERT(binding->propertyIndex() == property);
+ Q_ASSERT(binding->object() == target);
+
+ binding->addToObject();
+ QML_END_INSTR(StoreV4Binding)
+
+ QML_BEGIN_INSTR(StoreV8Binding)
+ QObject *target =
+ objects.at(objects.count() - 1 - instr.owner);
+ QObject *scope =
+ objects.at(objects.count() - 1 - instr.context);
+
+ if (instr.isRoot && BINDINGSKIPLIST.testBit(instr.property.coreIndex))
+ QML_NEXT_INSTR(StoreV8Binding);
+
+ QQmlAbstractBinding *binding = CTXT->v8bindings->configBinding(target, scope,
+ &instr);
+ if (binding) {
+ bindValues.push(binding);
+ binding->m_mePtr = &bindValues.top();
+
+ typedef QQmlPropertyPrivate QDPP;
+ Q_ASSERT(binding->propertyIndex() == QDPP::bindingIndex(instr.property));
+ Q_ASSERT(binding->object() == target);
+
+ binding->addToObject();
+ }
+ QML_END_INSTR(StoreV8Binding)
+
+ QML_BEGIN_INSTR(StoreValueSource)
+ QObject *obj = objects.pop();
+ QQmlPropertyValueSource *vs = reinterpret_cast<QQmlPropertyValueSource *>(reinterpret_cast<char *>(obj) + instr.castValue);
+ QObject *target = objects.at(objects.count() - 1 - instr.owner);
+
+ obj->setParent(target);
+ vs->setTarget(QQmlPropertyPrivate::restore(target, instr.property, CTXT));
+ QML_END_INSTR(StoreValueSource)
+
+ QML_BEGIN_INSTR(StoreValueInterceptor)
+ QObject *obj = objects.pop();
+ QQmlPropertyValueInterceptor *vi = reinterpret_cast<QQmlPropertyValueInterceptor *>(reinterpret_cast<char *>(obj) + instr.castValue);
+ QObject *target = objects.at(objects.count() - 1 - instr.owner);
+ QQmlProperty prop =
+ QQmlPropertyPrivate::restore(target, instr.property, CTXT);
+ obj->setParent(target);
+ vi->setTarget(prop);
+ QQmlVMEMetaObject *mo = static_cast<QQmlVMEMetaObject *>((QMetaObject*)target->metaObject());
+ mo->registerInterceptor(prop.index(), QQmlPropertyPrivate::valueTypeCoreIndex(prop), vi);
+ QML_END_INSTR(StoreValueInterceptor)
+
+ QML_BEGIN_INSTR(StoreObjectQList)
+ QObject *assign = objects.pop();
+
+ const List &list = lists.top();
+ list.qListProperty.append((QQmlListProperty<void>*)&list.qListProperty, assign);
+ QML_END_INSTR(StoreObjectQList)
+
+ QML_BEGIN_INSTR(AssignObjectList)
+ // This is only used for assigning interfaces
+ QObject *assign = objects.pop();
+ const List &list = lists.top();
+
+ int type = list.type;
+
+ void *ptr = 0;
+
+ const char *iid = QQmlMetaType::interfaceIId(type);
+ if (iid)
+ ptr = assign->qt_metacast(iid);
+ if (!ptr)
+ VME_EXCEPTION(tr("Cannot assign object to list"), instr.line);
+
+
+ list.qListProperty.append((QQmlListProperty<void>*)&list.qListProperty, ptr);
+ QML_END_INSTR(AssignObjectList)
+
+ QML_BEGIN_INSTR(StoreInterface)
+ QObject *assign = objects.pop();
+ QObject *target = objects.top();
+ CLEAN_PROPERTY(target, instr.propertyIndex);
+
+ int coreIdx = instr.propertyIndex;
+ QMetaProperty prop = target->metaObject()->property(coreIdx);
+ int t = prop.userType();
+ const char *iid = QQmlMetaType::interfaceIId(t);
+ bool ok = false;
+ if (iid) {
+ void *ptr = assign->qt_metacast(iid);
+ if (ptr) {
+ void *a[] = { &ptr, 0, &status, &flags };
+ QMetaObject::metacall(target,
+ QMetaObject::WriteProperty,
+ coreIdx, a);
+ ok = true;
+ }
+ }
+
+ if (!ok)
+ VME_EXCEPTION(tr("Cannot assign object to interface property"), instr.line);
+ QML_END_INSTR(StoreInterface)
+
+ QML_BEGIN_INSTR(FetchAttached)
+ QObject *target = objects.top();
+
+ QObject *qmlObject = qmlAttachedPropertiesObjectById(instr.id, target);
+
+ if (!qmlObject)
+ VME_EXCEPTION(tr("Unable to create attached object"), instr.line);
+
+ objects.push(qmlObject);
+ QML_END_INSTR(FetchAttached)
+
+ QML_BEGIN_INSTR(FetchQList)
+ QObject *target = objects.top();
+
+ lists.push(List(instr.type));
+
+ void *a[1];
+ a[0] = (void *)&(lists.top().qListProperty);
+ QMetaObject::metacall(target, QMetaObject::ReadProperty,
+ instr.property, a);
+ QML_END_INSTR(FetchQList)
+
+ QML_BEGIN_INSTR(FetchObject)
+ QObject *target = objects.top();
+
+ QObject *obj = 0;
+ // NOTE: This assumes a cast to QObject does not alter the
+ // object pointer
+ void *a[1];
+ a[0] = &obj;
+ QMetaObject::metacall(target, QMetaObject::ReadProperty,
+ instr.property, a);
+
+ if (!obj)
+ VME_EXCEPTION(tr("Cannot set properties on %1 as it is null").arg(QString::fromUtf8(target->metaObject()->property(instr.property).name())), instr.line);
+
+ objects.push(obj);
+ QML_END_INSTR(FetchObject)
+
+ QML_BEGIN_INSTR(PopQList)
+ lists.pop();
+ QML_END_INSTR(PopQList)
+
+ QML_BEGIN_INSTR(Defer)
+ if (instr.deferCount) {
+ QObject *target = objects.top();
+ QQmlData *data =
+ QQmlData::get(target, true);
+ COMP->addref();
+ data->deferredComponent = COMP;
+ data->deferredIdx = INSTRUCTIONSTREAM - COMP->bytecode.constData();
+ INSTRUCTIONSTREAM += instr.deferCount;
+ }
+ QML_END_INSTR(Defer)
+
+ QML_BEGIN_INSTR(PopFetchedObject)
+ objects.pop();
+ QML_END_INSTR(PopFetchedObject)
+
+ QML_BEGIN_INSTR(FetchValueType)
+ QObject *target = objects.top();
+
+ if (instr.bindingSkipList != 0) {
+ // Possibly need to clear bindings
+ QQmlData *targetData = QQmlData::get(target);
+ if (targetData) {
+ QQmlAbstractBinding *binding =
+ QQmlPropertyPrivate::binding(target, instr.property, -1);
+
+ if (binding && binding->bindingType() != QQmlAbstractBinding::ValueTypeProxy) {
+ QQmlPropertyPrivate::setBinding(target, instr.property, -1, 0);
+ binding->destroy();
+ } else if (binding) {
+ QQmlValueTypeProxyBinding *proxy =
+ static_cast<QQmlValueTypeProxyBinding *>(binding);
+ proxy->removeBindings(instr.bindingSkipList);
+ }
+ }
+ }
+
+ QQmlValueType *valueHandler = ep->valueTypes[instr.type];
+ valueHandler->read(target, instr.property);
+ objects.push(valueHandler);
+ QML_END_INSTR(FetchValueType)
+
+ QML_BEGIN_INSTR(PopValueType)
+ QQmlValueType *valueHandler =
+ static_cast<QQmlValueType *>(objects.pop());
+ QObject *target = objects.top();
+ valueHandler->write(target, instr.property, QQmlPropertyPrivate::BypassInterceptor);
+ QML_END_INSTR(PopValueType)
+
+#ifdef QML_THREADED_VME_INTERPRETER
+ // nothing to do
+#else
+ default:
+ qFatal("QQmlCompiledData: Internal error - unknown instruction %d", genericInstr->common.instructionType);
+ break;
+ }
+ }
+#endif
+
+exceptionExit:
+ Q_ASSERT(!states.isEmpty());
+ Q_ASSERT(!errors->isEmpty());
+
+ reset();
+
+ return 0;
+
+normalExit:
+ Q_ASSERT(objects.count() == 1);
+
+ QObject *rv = objects.top();
+
+ objects.deallocate();
+ lists.deallocate();
+ states.clear();
+
+ return rv;
+}
+
+void QQmlVME::reset()
+{
+ Q_ASSERT(!states.isEmpty() || objects.isEmpty());
+
+ QRecursionWatcher<QQmlVME, &QQmlVME::recursion> watcher(this);
+
+ if (!objects.isEmpty() && !(states.at(0).flags & State::Deferred))
+ delete objects.at(0);
+
+ if (!rootContext.isNull())
+ rootContext->activeVMEData = 0;
+
+ // Remove the QQmlParserStatus and QQmlAbstractBinding back pointers
+ blank(parserStatus);
+ blank(bindValues);
+
+ while (componentAttached) {
+ QQmlComponentAttached *a = componentAttached;
+ a->rem();
+ }
+
+ engine = 0;
+ objects.deallocate();
+ lists.deallocate();
+ bindValues.deallocate();
+ parserStatus.deallocate();
+#ifdef QML_ENABLE_TRACE
+ parserStatusData.deallocate();
+#endif
+ finalizeCallbacks.clear();
+ states.clear();
+ rootContext = 0;
+ creationContext = 0;
+}
+
+// Must be called with a handle scope and context
+void QQmlScriptData::initialize(QQmlEngine *engine)
+{
+ Q_ASSERT(m_program.IsEmpty());
+ Q_ASSERT(engine);
+ Q_ASSERT(!hasEngine());
+
+ QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine);
+ QV8Engine *v8engine = ep->v8engine();
+
+ // If compilation throws an error, a surrounding v8::TryCatch will record it.
+ v8::Local<v8::Script> program = v8engine->qmlModeCompile(m_programSource.constData(),
+ m_programSource.length(), urlString, 1);
+ if (program.IsEmpty())
+ return;
+
+ m_program = qPersistentNew<v8::Script>(program);
+ m_programSource.clear(); // We don't need this anymore
+
+ addToEngine(engine);
+
+ addref();
+}
+
+v8::Persistent<v8::Object> QQmlVME::run(QQmlContextData *parentCtxt, QQmlScriptData *script)
+{
+ if (script->m_loaded)
+ return qPersistentNew<v8::Object>(script->m_value);
+
+ Q_ASSERT(parentCtxt && parentCtxt->engine);
+ QQmlEnginePrivate *ep = QQmlEnginePrivate::get(parentCtxt->engine);
+ QV8Engine *v8engine = ep->v8engine();
+
+ bool shared = script->pragmas & QQmlScript::Object::ScriptBlock::Shared;
+
+ QQmlContextData *effectiveCtxt = parentCtxt;
+ if (shared)
+ effectiveCtxt = 0;
+
+ // Create the script context if required
+ QQmlContextData *ctxt = new QQmlContextData;
+ ctxt->isInternal = true;
+ ctxt->isJSContext = true;
+ if (shared)
+ ctxt->isPragmaLibraryContext = true;
+ else
+ ctxt->isPragmaLibraryContext = parentCtxt->isPragmaLibraryContext;
+ ctxt->url = script->url;
+ ctxt->urlString = script->urlString;
+
+ // For backward compatibility, if there are no imports, we need to use the
+ // imports from the parent context. See QTBUG-17518.
+ if (!script->importCache->isEmpty()) {
+ ctxt->imports = script->importCache;
+ } else if (effectiveCtxt) {
+ ctxt->imports = effectiveCtxt->imports;
+ ctxt->importedScripts = effectiveCtxt->importedScripts;
+ for (int ii = 0; ii < ctxt->importedScripts.count(); ++ii)
+ ctxt->importedScripts[ii] = qPersistentNew<v8::Object>(ctxt->importedScripts[ii]);
+ }
+
+ if (ctxt->imports) {
+ ctxt->imports->addref();
+ }
+
+ if (effectiveCtxt) {
+ ctxt->setParent(effectiveCtxt, true);
+ } else {
+ ctxt->engine = parentCtxt->engine; // Fix for QTBUG-21620
+ }
+
+ for (int ii = 0; ii < script->scripts.count(); ++ii) {
+ ctxt->importedScripts << run(ctxt, script->scripts.at(ii)->scriptData());
+ }
+
+ v8::HandleScope handle_scope;
+ v8::Context::Scope scope(v8engine->context());
+
+ v8::TryCatch try_catch;
+ if (!script->isInitialized())
+ script->initialize(parentCtxt->engine);
+
+ v8::Local<v8::Object> qmlglobal = v8engine->qmlScope(ctxt, 0);
+
+ if (!script->m_program.IsEmpty()) {
+ script->m_program->Run(qmlglobal);
+ } else {
+ // Compilation failed.
+ Q_ASSERT(try_catch.HasCaught());
+ }
+
+ v8::Persistent<v8::Object> rv;
+
+ if (try_catch.HasCaught()) {
+ v8::Local<v8::Message> message = try_catch.Message();
+ if (!message.IsEmpty()) {
+ QQmlError error;
+ QQmlExpressionPrivate::exceptionToError(message, error);
+ ep->warning(error);
+ }
+ }
+
+ rv = qPersistentNew<v8::Object>(qmlglobal);
+ if (shared) {
+ script->m_value = qPersistentNew<v8::Object>(qmlglobal);
+ script->m_loaded = true;
+ }
+
+ return rv;
+}
+
+#ifdef QML_THREADED_VME_INTERPRETER
+void **QQmlVME::instructionJumpTable()
+{
+ static void **jumpTable = 0;
+ if (!jumpTable) {
+ QQmlVME dummy;
+ QQmlVME::Interrupt i;
+ dummy.run(0, i, &jumpTable);
+ }
+ return jumpTable;
+}
+#endif
+
+QQmlContextData *QQmlVME::complete(const Interrupt &interrupt)
+{
+ Q_ASSERT(engine ||
+ (bindValues.isEmpty() &&
+ parserStatus.isEmpty() &&
+ componentAttached == 0 &&
+ rootContext.isNull() &&
+ finalizeCallbacks.isEmpty()));
+
+ if (!engine)
+ return 0;
+
+ QQmlTrace trace("VME Complete");
+#ifdef QML_ENABLE_TRACE
+ trace.addDetail("URL", rootComponent->url);
+#endif
+
+ ActiveVMERestorer restore(this, QQmlEnginePrivate::get(engine));
+ QRecursionWatcher<QQmlVME, &QQmlVME::recursion> watcher(this);
+
+ {
+ QQmlTrace trace("VME Binding Enable");
+ trace.event("begin binding eval");
+ while (!bindValues.isEmpty()) {
+ QQmlAbstractBinding *b = bindValues.pop();
+
+ if(b) {
+ b->m_mePtr = 0;
+ b->setEnabled(true, QQmlPropertyPrivate::BypassInterceptor |
+ QQmlPropertyPrivate::DontRemoveBinding);
+ }
+
+ if (watcher.hasRecursed() || interrupt.shouldInterrupt())
+ return 0;
+ }
+ bindValues.deallocate();
+ }
+
+ {
+ QQmlTrace trace("VME Component Complete");
+ while (!parserStatus.isEmpty()) {
+ QQmlParserStatus *status = parserStatus.pop();
+#ifdef QML_ENABLE_TRACE
+ QQmlData *data = parserStatusData.pop();
+#endif
+
+ if (status && status->d) {
+ status->d = 0;
+#ifdef QML_ENABLE_TRACE
+ QQmlTrace trace("Component complete");
+ trace.addDetail("URL", data->outerContext->url);
+ trace.addDetail("Line", data->lineNumber);
+#endif
+ status->componentComplete();
+ }
+
+ if (watcher.hasRecursed() || interrupt.shouldInterrupt())
+ return 0;
+ }
+ parserStatus.deallocate();
+ }
+
+ {
+ QQmlTrace trace("VME Finalize Callbacks");
+ for (int ii = 0; ii < finalizeCallbacks.count(); ++ii) {
+ QQmlEnginePrivate::FinalizeCallback callback = finalizeCallbacks.at(ii);
+ QObject *obj = callback.first;
+ if (obj) {
+ void *args[] = { 0 };
+ QMetaObject::metacall(obj, QMetaObject::InvokeMetaMethod, callback.second, args);
+ }
+ if (watcher.hasRecursed())
+ return 0;
+ }
+ finalizeCallbacks.clear();
+ }
+
+ {
+ QQmlTrace trace("VME Component.onCompleted Callbacks");
+ while (componentAttached) {
+ QQmlComponentAttached *a = componentAttached;
+ a->rem();
+ QQmlData *d = QQmlData::get(a->parent());
+ Q_ASSERT(d);
+ Q_ASSERT(d->context);
+ a->add(&d->context->componentAttached);
+ emit a->completed();
+
+ if (watcher.hasRecursed() || interrupt.shouldInterrupt())
+ return 0;
+ }
+ }
+
+ QQmlContextData *rv = rootContext;
+
+ reset();
+
+ if (rv) rv->activeVMEData = data;
+
+ return rv;
+}
+
+void QQmlVME::blank(QFiniteStack<QQmlAbstractBinding *> &bs)
+{
+ for (int ii = 0; ii < bs.count(); ++ii) {
+ QQmlAbstractBinding *b = bs.at(ii);
+ if (b) b->m_mePtr = 0;
+ }
+}
+
+void QQmlVME::blank(QFiniteStack<QQmlParserStatus *> &pss)
+{
+ for (int ii = 0; ii < pss.count(); ++ii) {
+ QQmlParserStatus *ps = pss.at(ii);
+ if(ps) ps->d = 0;
+ }
+}
+
+QQmlVMEGuard::QQmlVMEGuard()
+: m_objectCount(0), m_objects(0), m_contextCount(0), m_contexts(0)
+{
+}
+
+QQmlVMEGuard::~QQmlVMEGuard()
+{
+ clear();
+}
+
+void QQmlVMEGuard::guard(QQmlVME *vme)
+{
+ clear();
+
+ m_objectCount = vme->objects.count();
+ m_objects = new QQmlGuard<QObject>[m_objectCount];
+ for (int ii = 0; ii < m_objectCount; ++ii)
+ m_objects[ii] = vme->objects[ii];
+
+ m_contextCount = (vme->rootContext.isNull()?0:1) + vme->states.count();
+ m_contexts = new QQmlGuardedContextData[m_contextCount];
+ for (int ii = 0; ii < vme->states.count(); ++ii)
+ m_contexts[ii] = vme->states.at(ii).context;
+ if (!vme->rootContext.isNull())
+ m_contexts[m_contextCount - 1] = vme->rootContext.contextData();
+}
+
+void QQmlVMEGuard::clear()
+{
+ delete [] m_objects;
+ delete [] m_contexts;
+
+ m_objectCount = 0;
+ m_objects = 0;
+ m_contextCount = 0;
+ m_contexts = 0;
+}
+
+bool QQmlVMEGuard::isOK() const
+{
+ for (int ii = 0; ii < m_objectCount; ++ii)
+ if (m_objects[ii].isNull())
+ return false;
+
+ for (int ii = 0; ii < m_contextCount; ++ii)
+ if (m_contexts[ii].isNull())
+ return false;
+
+ return true;
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlvme_p.h b/src/qml/qml/qqmlvme_p.h
new file mode 100644
index 0000000000..8c8d4d079e
--- /dev/null
+++ b/src/qml/qml/qqmlvme_p.h
@@ -0,0 +1,240 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLVME_P_H
+#define QQMLVME_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 "qqmlerror.h"
+#include <private/qbitfield_p.h>
+#include "qqmlinstruction_p.h"
+#include <private/qrecursionwatcher_p.h>
+
+#include <QtCore/QStack>
+#include <QtCore/QString>
+#include <QtCore/qelapsedtimer.h>
+#include <QtCore/qcoreapplication.h>
+
+#include <private/qv8_p.h>
+#include <private/qqmlengine_p.h>
+#include <private/qfinitestack_p.h>
+
+#include <private/qqmltrace_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QObject;
+class QJSValue;
+class QQmlScriptData;
+class QQmlCompiledData;
+class QQmlCompiledData;
+class QQmlContextData;
+
+namespace QQmlVMETypes {
+ struct List
+ {
+ List() : type(0) {}
+ List(int t) : type(t) {}
+
+ int type;
+ QQmlListProperty<void> qListProperty;
+ };
+}
+Q_DECLARE_TYPEINFO(QQmlVMETypes::List, Q_PRIMITIVE_TYPE | Q_MOVABLE_TYPE);
+
+class QQmlVME
+{
+ Q_DECLARE_TR_FUNCTIONS(QQmlVME)
+public:
+ class Interrupt {
+ public:
+ inline Interrupt();
+ inline Interrupt(bool *runWhile);
+ inline Interrupt(int nsecs);
+
+ inline void reset();
+ inline bool shouldInterrupt() const;
+ private:
+ enum Mode { None, Time, Flag };
+ Mode mode;
+ union {
+ struct {
+ QElapsedTimer timer;
+ int nsecs;
+ };
+ bool *runWhile;
+ };
+ };
+
+ QQmlVME() : data(0), componentAttached(0) {}
+ QQmlVME(void *data) : data(data), componentAttached(0) {}
+
+ void *data;
+ QQmlComponentAttached *componentAttached;
+ QList<QQmlEnginePrivate::FinalizeCallback> finalizeCallbacks;
+
+ void init(QQmlContextData *, QQmlCompiledData *, int start,
+ QQmlContextData * = 0);
+ bool initDeferred(QObject *);
+ void reset();
+
+ QObject *execute(QList<QQmlError> *errors, const Interrupt & = Interrupt());
+ QQmlContextData *complete(const Interrupt & = Interrupt());
+
+private:
+ friend class QQmlVMEGuard;
+
+ QObject *run(QList<QQmlError> *errors, const Interrupt &
+#ifdef QML_THREADED_VME_INTERPRETER
+ , void ***storeJumpTable = 0
+#endif
+ );
+ v8::Persistent<v8::Object> run(QQmlContextData *, QQmlScriptData *);
+
+#ifdef QML_THREADED_VME_INTERPRETER
+ static void **instructionJumpTable();
+ friend class QQmlCompiledData;
+#endif
+
+ QQmlEngine *engine;
+ QRecursionNode recursion;
+
+#ifdef QML_ENABLE_TRACE
+ QQmlCompiledData *rootComponent;
+#endif
+
+ QFiniteStack<QObject *> objects;
+ QFiniteStack<QQmlVMETypes::List> lists;
+
+ QFiniteStack<QQmlAbstractBinding *> bindValues;
+ QFiniteStack<QQmlParserStatus *> parserStatus;
+#ifdef QML_ENABLE_TRACE
+ QFiniteStack<QQmlData *> parserStatusData;
+#endif
+
+ QQmlGuardedContextData rootContext;
+ QQmlGuardedContextData creationContext;
+
+ struct State {
+ enum Flag { Deferred = 0x00000001 };
+
+ State() : flags(0), context(0), compiledData(0), instructionStream(0) {}
+ quint32 flags;
+ QQmlContextData *context;
+ QQmlCompiledData *compiledData;
+ const char *instructionStream;
+ QBitField bindingSkipList;
+ };
+
+ QStack<State> states;
+
+ static void blank(QFiniteStack<QQmlParserStatus *> &);
+ static void blank(QFiniteStack<QQmlAbstractBinding *> &);
+};
+
+// Used to check that a QQmlVME that is interrupted mid-execution
+// is still valid. Checks all the objects and contexts have not been
+// deleted.
+class QQmlVMEGuard
+{
+public:
+ QQmlVMEGuard();
+ ~QQmlVMEGuard();
+
+ void guard(QQmlVME *);
+ void clear();
+
+ bool isOK() const;
+
+private:
+ int m_objectCount;
+ QQmlGuard<QObject> *m_objects;
+ int m_contextCount;
+ QQmlGuardedContextData *m_contexts;
+};
+
+QQmlVME::Interrupt::Interrupt()
+: mode(None)
+{
+}
+
+QQmlVME::Interrupt::Interrupt(bool *runWhile)
+: mode(Flag), runWhile(runWhile)
+{
+}
+
+QQmlVME::Interrupt::Interrupt(int nsecs)
+: mode(Time), nsecs(nsecs)
+{
+}
+
+void QQmlVME::Interrupt::reset()
+{
+ if (mode == Time)
+ timer.start();
+}
+
+bool QQmlVME::Interrupt::shouldInterrupt() const
+{
+ if (mode == None) {
+ return false;
+ } else if (mode == Time) {
+ return timer.nsecsElapsed() > nsecs;
+ } else if (mode == Flag) {
+ return !*runWhile;
+ } else {
+ return false;
+ }
+}
+
+QT_END_NAMESPACE
+
+#endif // QQMLVME_P_H
diff --git a/src/qml/qml/qqmlvmemetaobject.cpp b/src/qml/qml/qqmlvmemetaobject.cpp
new file mode 100644
index 0000000000..7ea89a4a2d
--- /dev/null
+++ b/src/qml/qml/qqmlvmemetaobject.cpp
@@ -0,0 +1,1110 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qqmlvmemetaobject_p.h"
+
+
+#include "qqml.h"
+#include <private/qqmlrefcount_p.h>
+#include "qqmlexpression.h"
+#include "qqmlexpression_p.h"
+#include "qqmlcontext_p.h"
+#include "qqmlbinding_p.h"
+#include "qqmlpropertyvalueinterceptor_p.h"
+
+#include <private/qv8variantresource_p.h>
+
+Q_DECLARE_METATYPE(QJSValue);
+
+QT_BEGIN_NAMESPACE
+
+class QQmlVMEVariant
+{
+public:
+ inline QQmlVMEVariant();
+ inline ~QQmlVMEVariant();
+
+ inline const void *dataPtr() const;
+ inline void *dataPtr();
+ inline int dataType() const;
+
+ inline QObject *asQObject();
+ inline const QVariant &asQVariant();
+ inline int asInt();
+ inline bool asBool();
+ inline double asDouble();
+ inline const QString &asQString();
+ inline const QUrl &asQUrl();
+ inline const QColor &asQColor();
+ inline const QTime &asQTime();
+ inline const QDate &asQDate();
+ inline const QDateTime &asQDateTime();
+ inline const QJSValue &asQJSValue();
+
+ inline void setValue(QObject *);
+ inline void setValue(const QVariant &);
+ inline void setValue(int);
+ inline void setValue(bool);
+ inline void setValue(double);
+ inline void setValue(const QString &);
+ inline void setValue(const QUrl &);
+ inline void setValue(const QColor &);
+ inline void setValue(const QTime &);
+ inline void setValue(const QDate &);
+ inline void setValue(const QDateTime &);
+ inline void setValue(const QJSValue &);
+private:
+ int type;
+ void *data[4]; // Large enough to hold all types
+
+ inline void cleanup();
+};
+
+class QQmlVMEMetaObjectEndpoint : public QQmlNotifierEndpoint
+{
+public:
+ QQmlVMEMetaObjectEndpoint();
+ static void vmecallback(QQmlNotifierEndpoint *);
+ void tryConnect();
+
+ QFlagPointer<QQmlVMEMetaObject> metaObject;
+};
+
+
+QQmlVMEVariant::QQmlVMEVariant()
+: type(QVariant::Invalid)
+{
+}
+
+QQmlVMEVariant::~QQmlVMEVariant()
+{
+ cleanup();
+}
+
+void QQmlVMEVariant::cleanup()
+{
+ if (type == QVariant::Invalid) {
+ } else if (type == QMetaType::Int ||
+ type == QMetaType::Bool ||
+ type == QMetaType::Double) {
+ type = QVariant::Invalid;
+ } else if (type == QMetaType::QObjectStar) {
+ ((QQmlGuard<QObject>*)dataPtr())->~QQmlGuard<QObject>();
+ type = QVariant::Invalid;
+ } else if (type == QMetaType::QString) {
+ ((QString *)dataPtr())->~QString();
+ type = QVariant::Invalid;
+ } else if (type == QMetaType::QUrl) {
+ ((QUrl *)dataPtr())->~QUrl();
+ type = QVariant::Invalid;
+ } else if (type == QMetaType::QColor) {
+ ((QColor *)dataPtr())->~QColor();
+ type = QVariant::Invalid;
+ } else if (type == QMetaType::QTime) {
+ ((QTime *)dataPtr())->~QTime();
+ type = QVariant::Invalid;
+ } else if (type == QMetaType::QDate) {
+ ((QDate *)dataPtr())->~QDate();
+ type = QVariant::Invalid;
+ } else if (type == QMetaType::QDateTime) {
+ ((QDateTime *)dataPtr())->~QDateTime();
+ type = QVariant::Invalid;
+ } else if (type == qMetaTypeId<QVariant>()) {
+ ((QVariant *)dataPtr())->~QVariant();
+ type = QVariant::Invalid;
+ } else if (type == qMetaTypeId<QJSValue>()) {
+ ((QJSValue *)dataPtr())->~QJSValue();
+ type = QVariant::Invalid;
+ }
+
+}
+
+int QQmlVMEVariant::dataType() const
+{
+ return type;
+}
+
+const void *QQmlVMEVariant::dataPtr() const
+{
+ return &data;
+}
+
+void *QQmlVMEVariant::dataPtr()
+{
+ return &data;
+}
+
+QObject *QQmlVMEVariant::asQObject()
+{
+ if (type != QMetaType::QObjectStar)
+ setValue((QObject *)0);
+
+ return *(QQmlGuard<QObject> *)(dataPtr());
+}
+
+const QVariant &QQmlVMEVariant::asQVariant()
+{
+ if (type != QMetaType::QVariant)
+ setValue(QVariant());
+
+ return *(QVariant *)(dataPtr());
+}
+
+int QQmlVMEVariant::asInt()
+{
+ if (type != QMetaType::Int)
+ setValue(int(0));
+
+ return *(int *)(dataPtr());
+}
+
+bool QQmlVMEVariant::asBool()
+{
+ if (type != QMetaType::Bool)
+ setValue(bool(false));
+
+ return *(bool *)(dataPtr());
+}
+
+double QQmlVMEVariant::asDouble()
+{
+ if (type != QMetaType::Double)
+ setValue(double(0));
+
+ return *(double *)(dataPtr());
+}
+
+const QString &QQmlVMEVariant::asQString()
+{
+ if (type != QMetaType::QString)
+ setValue(QString());
+
+ return *(QString *)(dataPtr());
+}
+
+const QUrl &QQmlVMEVariant::asQUrl()
+{
+ if (type != QMetaType::QUrl)
+ setValue(QUrl());
+
+ return *(QUrl *)(dataPtr());
+}
+
+const QColor &QQmlVMEVariant::asQColor()
+{
+ if (type != QMetaType::QColor)
+ setValue(QColor());
+
+ return *(QColor *)(dataPtr());
+}
+
+const QTime &QQmlVMEVariant::asQTime()
+{
+ if (type != QMetaType::QTime)
+ setValue(QTime());
+
+ return *(QTime *)(dataPtr());
+}
+
+const QDate &QQmlVMEVariant::asQDate()
+{
+ if (type != QMetaType::QDate)
+ setValue(QDate());
+
+ return *(QDate *)(dataPtr());
+}
+
+const QDateTime &QQmlVMEVariant::asQDateTime()
+{
+ if (type != QMetaType::QDateTime)
+ setValue(QDateTime());
+
+ return *(QDateTime *)(dataPtr());
+}
+
+const QJSValue &QQmlVMEVariant::asQJSValue()
+{
+ if (type != qMetaTypeId<QJSValue>())
+ setValue(QJSValue());
+
+ return *(QJSValue *)(dataPtr());
+}
+
+void QQmlVMEVariant::setValue(QObject *v)
+{
+ if (type != QMetaType::QObjectStar) {
+ cleanup();
+ type = QMetaType::QObjectStar;
+ new (dataPtr()) QQmlGuard<QObject>();
+ }
+ *(QQmlGuard<QObject>*)(dataPtr()) = v;
+}
+
+void QQmlVMEVariant::setValue(const QVariant &v)
+{
+ if (type != qMetaTypeId<QVariant>()) {
+ cleanup();
+ type = qMetaTypeId<QVariant>();
+ new (dataPtr()) QVariant(v);
+ } else {
+ *(QVariant *)(dataPtr()) = v;
+ }
+}
+
+void QQmlVMEVariant::setValue(int v)
+{
+ if (type != QMetaType::Int) {
+ cleanup();
+ type = QMetaType::Int;
+ }
+ *(int *)(dataPtr()) = v;
+}
+
+void QQmlVMEVariant::setValue(bool v)
+{
+ if (type != QMetaType::Bool) {
+ cleanup();
+ type = QMetaType::Bool;
+ }
+ *(bool *)(dataPtr()) = v;
+}
+
+void QQmlVMEVariant::setValue(double v)
+{
+ if (type != QMetaType::Double) {
+ cleanup();
+ type = QMetaType::Double;
+ }
+ *(double *)(dataPtr()) = v;
+}
+
+void QQmlVMEVariant::setValue(const QString &v)
+{
+ if (type != QMetaType::QString) {
+ cleanup();
+ type = QMetaType::QString;
+ new (dataPtr()) QString(v);
+ } else {
+ *(QString *)(dataPtr()) = v;
+ }
+}
+
+void QQmlVMEVariant::setValue(const QUrl &v)
+{
+ if (type != QMetaType::QUrl) {
+ cleanup();
+ type = QMetaType::QUrl;
+ new (dataPtr()) QUrl(v);
+ } else {
+ *(QUrl *)(dataPtr()) = v;
+ }
+}
+
+void QQmlVMEVariant::setValue(const QColor &v)
+{
+ if (type != QMetaType::QColor) {
+ cleanup();
+ type = QMetaType::QColor;
+ new (dataPtr()) QColor(v);
+ } else {
+ *(QColor *)(dataPtr()) = v;
+ }
+}
+
+void QQmlVMEVariant::setValue(const QTime &v)
+{
+ if (type != QMetaType::QTime) {
+ cleanup();
+ type = QMetaType::QTime;
+ new (dataPtr()) QTime(v);
+ } else {
+ *(QTime *)(dataPtr()) = v;
+ }
+}
+
+void QQmlVMEVariant::setValue(const QDate &v)
+{
+ if (type != QMetaType::QDate) {
+ cleanup();
+ type = QMetaType::QDate;
+ new (dataPtr()) QDate(v);
+ } else {
+ *(QDate *)(dataPtr()) = v;
+ }
+}
+
+void QQmlVMEVariant::setValue(const QDateTime &v)
+{
+ if (type != QMetaType::QDateTime) {
+ cleanup();
+ type = QMetaType::QDateTime;
+ new (dataPtr()) QDateTime(v);
+ } else {
+ *(QDateTime *)(dataPtr()) = v;
+ }
+}
+
+void QQmlVMEVariant::setValue(const QJSValue &v)
+{
+ if (type != qMetaTypeId<QJSValue>()) {
+ cleanup();
+ type = qMetaTypeId<QJSValue>();
+ new (dataPtr()) QJSValue(v);
+ } else {
+ *(QJSValue *)(dataPtr()) = v;
+ }
+}
+
+QQmlVMEMetaObjectEndpoint::QQmlVMEMetaObjectEndpoint()
+{
+ callback = &vmecallback;
+}
+
+void QQmlVMEMetaObjectEndpoint::vmecallback(QQmlNotifierEndpoint *e)
+{
+ QQmlVMEMetaObjectEndpoint *vmee = static_cast<QQmlVMEMetaObjectEndpoint*>(e);
+ vmee->tryConnect();
+}
+
+void QQmlVMEMetaObjectEndpoint::tryConnect()
+{
+ int aliasId = this - metaObject->aliasEndpoints;
+
+ if (metaObject.flag()) {
+ // This is actually notify
+ int sigIdx = metaObject->methodOffset + aliasId + metaObject->metaData->propertyCount;
+ QMetaObject::activate(metaObject->object, sigIdx, 0);
+ } else {
+ QQmlVMEMetaData::AliasData *d = metaObject->metaData->aliasData() + aliasId;
+ if (!d->isObjectAlias()) {
+ QQmlContextData *ctxt = metaObject->ctxt;
+ QObject *target = ctxt->idValues[d->contextIdx].data();
+ if (!target)
+ return;
+
+ QMetaProperty prop = target->metaObject()->property(d->propertyIndex());
+ if (prop.hasNotifySignal())
+ connect(target, prop.notifySignalIndex());
+ }
+
+ metaObject.setFlag();
+ }
+}
+
+QQmlVMEMetaObject::QQmlVMEMetaObject(QObject *obj,
+ const QMetaObject *other,
+ const QQmlVMEMetaData *meta,
+ QQmlCompiledData *cdata)
+: QV8GCCallback::Node(GcPrologueCallback), object(obj), compiledData(cdata),
+ ctxt(QQmlData::get(obj, true)->outerContext), metaData(meta), data(0),
+ aliasEndpoints(0), firstVarPropertyIndex(-1), varPropertiesInitialized(false),
+ v8methods(0), parent(0)
+{
+ compiledData->addref();
+
+ *static_cast<QMetaObject *>(this) = *other;
+ this->d.superdata = obj->metaObject();
+
+ QObjectPrivate *op = QObjectPrivate::get(obj);
+ if (op->metaObject)
+ parent = static_cast<QAbstractDynamicMetaObject*>(op->metaObject);
+ op->metaObject = this;
+
+ propOffset = QAbstractDynamicMetaObject::propertyOffset();
+ methodOffset = QAbstractDynamicMetaObject::methodOffset();
+
+ data = new QQmlVMEVariant[metaData->propertyCount - metaData->varPropertyCount];
+
+ aConnected.resize(metaData->aliasCount);
+ int list_type = qMetaTypeId<QQmlListProperty<QObject> >();
+
+ // ### Optimize
+ for (int ii = 0; ii < metaData->propertyCount - metaData->varPropertyCount; ++ii) {
+ int t = (metaData->propertyData() + ii)->propertyType;
+ if (t == list_type) {
+ listProperties.append(List(methodOffset + ii));
+ data[ii].setValue(listProperties.count() - 1);
+ }
+ }
+
+ firstVarPropertyIndex = metaData->propertyCount - metaData->varPropertyCount;
+ if (metaData->varPropertyCount)
+ QV8GCCallback::addGcCallbackNode(this);
+}
+
+QQmlVMEMetaObject::~QQmlVMEMetaObject()
+{
+ compiledData->release();
+ delete parent;
+ delete [] data;
+ delete [] aliasEndpoints;
+
+ for (int ii = 0; v8methods && ii < metaData->methodCount; ++ii) {
+ qPersistentDispose(v8methods[ii]);
+ }
+ delete [] v8methods;
+
+ if (metaData->varPropertyCount)
+ qPersistentDispose(varProperties); // if not weak, will not have been cleaned up by the callback.
+}
+
+int QQmlVMEMetaObject::metaCall(QMetaObject::Call c, int _id, void **a)
+{
+ int id = _id;
+ if(c == QMetaObject::WriteProperty) {
+ int flags = *reinterpret_cast<int*>(a[3]);
+ if (!(flags & QQmlPropertyPrivate::BypassInterceptor)
+ && !aInterceptors.isEmpty()
+ && aInterceptors.testBit(id)) {
+ QPair<int, QQmlPropertyValueInterceptor*> pair = interceptors.value(id);
+ int valueIndex = pair.first;
+ QQmlPropertyValueInterceptor *vi = pair.second;
+ int type = property(id).userType();
+
+ if (type != QVariant::Invalid) {
+ if (valueIndex != -1) {
+ QQmlEnginePrivate *ep = ctxt?QQmlEnginePrivate::get(ctxt->engine):0;
+ QQmlValueType *valueType = 0;
+ if (ep) valueType = ep->valueTypes[type];
+ else valueType = QQmlValueTypeFactory::valueType(type);
+ Q_ASSERT(valueType);
+
+ valueType->setValue(QVariant(type, a[0]));
+ QMetaProperty valueProp = valueType->metaObject()->property(valueIndex);
+ vi->write(valueProp.read(valueType));
+
+ if (!ep) delete valueType;
+ return -1;
+ } else {
+ vi->write(QVariant(type, a[0]));
+ return -1;
+ }
+ }
+ }
+ }
+ if (c == QMetaObject::ReadProperty || c == QMetaObject::WriteProperty || c == QMetaObject::ResetProperty) {
+ if (id >= propOffset) {
+ id -= propOffset;
+
+ if (id < metaData->propertyCount) {
+ int t = (metaData->propertyData() + id)->propertyType;
+ bool needActivate = false;
+
+ if (id >= firstVarPropertyIndex) {
+ Q_ASSERT(t == QMetaType::QVariant);
+ // the context can be null if accessing var properties from cpp after re-parenting an item.
+ QQmlEnginePrivate *ep = (ctxt == 0 || ctxt->engine == 0) ? 0 : QQmlEnginePrivate::get(ctxt->engine);
+ QV8Engine *v8e = (ep == 0) ? 0 : ep->v8engine();
+ if (v8e) {
+ v8::HandleScope handleScope;
+ v8::Context::Scope contextScope(v8e->context());
+ if (c == QMetaObject::ReadProperty) {
+ *reinterpret_cast<QVariant *>(a[0]) = readPropertyAsVariant(id);
+ } else if (c == QMetaObject::WriteProperty) {
+ writeProperty(id, *reinterpret_cast<QVariant *>(a[0]));
+ }
+ } else if (c == QMetaObject::ReadProperty) {
+ // if the context was disposed, we just return an invalid variant from read.
+ *reinterpret_cast<QVariant *>(a[0]) = QVariant();
+ }
+
+ } else {
+
+ if (c == QMetaObject::ReadProperty) {
+ switch(t) {
+ case QVariant::Int:
+ *reinterpret_cast<int *>(a[0]) = data[id].asInt();
+ break;
+ case QVariant::Bool:
+ *reinterpret_cast<bool *>(a[0]) = data[id].asBool();
+ break;
+ case QVariant::Double:
+ *reinterpret_cast<double *>(a[0]) = data[id].asDouble();
+ break;
+ case QVariant::String:
+ *reinterpret_cast<QString *>(a[0]) = data[id].asQString();
+ break;
+ case QVariant::Url:
+ *reinterpret_cast<QUrl *>(a[0]) = data[id].asQUrl();
+ break;
+ case QVariant::Color:
+ *reinterpret_cast<QColor *>(a[0]) = data[id].asQColor();
+ break;
+ case QVariant::Date:
+ *reinterpret_cast<QDate *>(a[0]) = data[id].asQDate();
+ break;
+ case QVariant::DateTime:
+ *reinterpret_cast<QDateTime *>(a[0]) = data[id].asQDateTime();
+ break;
+ case QMetaType::QObjectStar:
+ *reinterpret_cast<QObject **>(a[0]) = data[id].asQObject();
+ break;
+ case QMetaType::QVariant:
+ *reinterpret_cast<QVariant *>(a[0]) = readPropertyAsVariant(id);
+ break;
+ default:
+ break;
+ }
+ if (t == qMetaTypeId<QQmlListProperty<QObject> >()) {
+ int listIndex = data[id].asInt();
+ const List *list = &listProperties.at(listIndex);
+ *reinterpret_cast<QQmlListProperty<QObject> *>(a[0]) =
+ QQmlListProperty<QObject>(object, (void *)list,
+ list_append, list_count, list_at,
+ list_clear);
+ }
+
+ } else if (c == QMetaObject::WriteProperty) {
+
+ switch(t) {
+ case QVariant::Int:
+ needActivate = *reinterpret_cast<int *>(a[0]) != data[id].asInt();
+ data[id].setValue(*reinterpret_cast<int *>(a[0]));
+ break;
+ case QVariant::Bool:
+ needActivate = *reinterpret_cast<bool *>(a[0]) != data[id].asBool();
+ data[id].setValue(*reinterpret_cast<bool *>(a[0]));
+ break;
+ case QVariant::Double:
+ needActivate = *reinterpret_cast<double *>(a[0]) != data[id].asDouble();
+ data[id].setValue(*reinterpret_cast<double *>(a[0]));
+ break;
+ case QVariant::String:
+ needActivate = *reinterpret_cast<QString *>(a[0]) != data[id].asQString();
+ data[id].setValue(*reinterpret_cast<QString *>(a[0]));
+ break;
+ case QVariant::Url:
+ needActivate = *reinterpret_cast<QUrl *>(a[0]) != data[id].asQUrl();
+ data[id].setValue(*reinterpret_cast<QUrl *>(a[0]));
+ break;
+ case QVariant::Color:
+ needActivate = *reinterpret_cast<QColor *>(a[0]) != data[id].asQColor();
+ data[id].setValue(*reinterpret_cast<QColor *>(a[0]));
+ break;
+ case QVariant::Date:
+ needActivate = *reinterpret_cast<QDate *>(a[0]) != data[id].asQDate();
+ data[id].setValue(*reinterpret_cast<QDate *>(a[0]));
+ break;
+ case QVariant::DateTime:
+ needActivate = *reinterpret_cast<QDateTime *>(a[0]) != data[id].asQDateTime();
+ data[id].setValue(*reinterpret_cast<QDateTime *>(a[0]));
+ break;
+ case QMetaType::QObjectStar:
+ needActivate = *reinterpret_cast<QObject **>(a[0]) != data[id].asQObject();
+ data[id].setValue(*reinterpret_cast<QObject **>(a[0]));
+ break;
+ case QMetaType::QVariant:
+ writeProperty(id, *reinterpret_cast<QVariant *>(a[0]));
+ break;
+ default:
+ break;
+ }
+ }
+
+ }
+
+ if (c == QMetaObject::WriteProperty && needActivate) {
+ activate(object, methodOffset + id, 0);
+ }
+
+ return -1;
+ }
+
+ id -= metaData->propertyCount;
+
+ if (id < metaData->aliasCount) {
+
+ QQmlVMEMetaData::AliasData *d = metaData->aliasData() + id;
+
+ if (d->flags & QML_ALIAS_FLAG_PTR && c == QMetaObject::ReadProperty)
+ *reinterpret_cast<void **>(a[0]) = 0;
+
+ if (!ctxt) return -1;
+
+ QQmlContext *context = ctxt->asQQmlContext();
+ QQmlContextPrivate *ctxtPriv = QQmlContextPrivate::get(context);
+
+ QObject *target = ctxtPriv->data->idValues[d->contextIdx].data();
+ if (!target)
+ return -1;
+
+ connectAlias(id);
+
+ if (d->isObjectAlias()) {
+ *reinterpret_cast<QObject **>(a[0]) = target;
+ return -1;
+ }
+
+ // Remove binding (if any) on write
+ if(c == QMetaObject::WriteProperty) {
+ int flags = *reinterpret_cast<int*>(a[3]);
+ if (flags & QQmlPropertyPrivate::RemoveBindingOnAliasWrite) {
+ QQmlData *targetData = QQmlData::get(target);
+ if (targetData && targetData->hasBindingBit(d->propertyIndex())) {
+ QQmlAbstractBinding *binding = QQmlPropertyPrivate::setBinding(target, d->propertyIndex(), d->isValueTypeAlias()?d->valueTypeIndex():-1, 0);
+ if (binding) binding->destroy();
+ }
+ }
+ }
+
+ if (d->isValueTypeAlias()) {
+ // Value type property
+ QQmlEnginePrivate *ep = QQmlEnginePrivate::get(ctxt->engine);
+
+ QQmlValueType *valueType = ep->valueTypes[d->valueType()];
+ Q_ASSERT(valueType);
+
+ valueType->read(target, d->propertyIndex());
+ int rv = QMetaObject::metacall(valueType, c, d->valueTypeIndex(), a);
+
+ if (c == QMetaObject::WriteProperty)
+ valueType->write(target, d->propertyIndex(), 0x00);
+
+ return rv;
+
+ } else {
+ return QMetaObject::metacall(target, c, d->propertyIndex(), a);
+ }
+
+ }
+ return -1;
+
+ }
+
+ } else if(c == QMetaObject::InvokeMetaMethod) {
+
+ if (id >= methodOffset) {
+
+ id -= methodOffset;
+ int plainSignals = metaData->signalCount + metaData->propertyCount +
+ metaData->aliasCount;
+ if (id < plainSignals) {
+ QMetaObject::activate(object, _id, a);
+ return -1;
+ }
+
+ id -= plainSignals;
+
+ if (id < metaData->methodCount) {
+ if (!ctxt->engine)
+ return -1; // We can't run the method
+
+ QQmlEnginePrivate *ep = QQmlEnginePrivate::get(ctxt->engine);
+ ep->referenceScarceResources(); // "hold" scarce resources in memory during evaluation.
+
+ v8::Handle<v8::Function> function = method(id);
+ if (function.IsEmpty()) {
+ // The function was not compiled. There are some exceptional cases which the
+ // expression rewriter does not rewrite properly (e.g., \r-terminated lines
+ // are not rewritten correctly but this bug is deemed out-of-scope to fix for
+ // performance reasons; see QTBUG-24064) and thus compilation will have failed.
+ QQmlError e;
+ e.setDescription(QString(QLatin1String("Exception occurred during compilation of function: %1")).
+ arg(QLatin1String(QMetaObject::method(_id).signature())));
+ ep->warning(e);
+ return -1; // The dynamic method with that id is not available.
+ }
+
+ QQmlVMEMetaData::MethodData *data = metaData->methodData() + id;
+
+ v8::HandleScope handle_scope;
+ v8::Context::Scope scope(ep->v8engine()->context());
+ v8::Handle<v8::Value> *args = 0;
+
+ if (data->parameterCount) {
+ args = new v8::Handle<v8::Value>[data->parameterCount];
+ for (int ii = 0; ii < data->parameterCount; ++ii)
+ args[ii] = ep->v8engine()->fromVariant(*(QVariant *)a[ii + 1]);
+ }
+
+ v8::TryCatch try_catch;
+
+ v8::Local<v8::Value> result = function->Call(ep->v8engine()->global(), data->parameterCount, args);
+
+ QVariant rv;
+ if (try_catch.HasCaught()) {
+ QQmlError error;
+ QQmlExpressionPrivate::exceptionToError(try_catch.Message(), error);
+ 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.
+ return -1;
+ }
+ return -1;
+ }
+ }
+
+ if (parent)
+ return parent->metaCall(c, _id, a);
+ else
+ return object->qt_metacall(c, _id, a);
+}
+
+v8::Handle<v8::Function> QQmlVMEMetaObject::method(int index)
+{
+ if (!v8methods)
+ v8methods = new v8::Persistent<v8::Function>[metaData->methodCount];
+
+ if (v8methods[index].IsEmpty()) {
+ QQmlVMEMetaData::MethodData *data = metaData->methodData() + index;
+
+ const char *body = ((const char*)metaData) + data->bodyOffset;
+ int bodyLength = data->bodyLength;
+
+ // XXX We should evaluate all methods in a single big script block to
+ // improve the call time between dynamic methods defined on the same
+ // object
+ v8methods[index] = QQmlExpressionPrivate::evalFunction(ctxt, object, body,
+ bodyLength,
+ ctxt->urlString,
+ data->lineNumber);
+ }
+
+ return v8methods[index];
+}
+
+v8::Handle<v8::Value> QQmlVMEMetaObject::readVarProperty(int id)
+{
+ Q_ASSERT(id >= firstVarPropertyIndex);
+
+ ensureVarPropertiesAllocated();
+ return varProperties->Get(id - firstVarPropertyIndex);
+}
+
+QVariant QQmlVMEMetaObject::readPropertyAsVariant(int id)
+{
+ if (id >= firstVarPropertyIndex) {
+ ensureVarPropertiesAllocated();
+ return QQmlEnginePrivate::get(ctxt->engine)->v8engine()->toVariant(varProperties->Get(id - firstVarPropertyIndex), -1);
+ } else {
+ if (data[id].dataType() == QMetaType::QObjectStar) {
+ return QVariant::fromValue(data[id].asQObject());
+ } else {
+ return data[id].asQVariant();
+ }
+ }
+}
+
+void QQmlVMEMetaObject::writeVarProperty(int id, v8::Handle<v8::Value> value)
+{
+ Q_ASSERT(id >= firstVarPropertyIndex);
+ ensureVarPropertiesAllocated();
+
+ // Importantly, if the current value is a scarce resource, we need to ensure that it
+ // gets automatically released by the engine if no other references to it exist.
+ v8::Local<v8::Value> oldv = varProperties->Get(id - firstVarPropertyIndex);
+ if (oldv->IsObject()) {
+ QV8VariantResource *r = v8_resource_cast<QV8VariantResource>(v8::Handle<v8::Object>::Cast(oldv));
+ if (r) {
+ r->removeVmePropertyReference();
+ }
+ }
+
+ // And, if the new value is a scarce resource, we need to ensure that it does not get
+ // automatically released by the engine until no other references to it exist.
+ if (value->IsObject()) {
+ QV8VariantResource *r = v8_resource_cast<QV8VariantResource>(v8::Handle<v8::Object>::Cast(value));
+ if (r) {
+ r->addVmePropertyReference();
+ }
+ }
+
+ // Write the value and emit change signal as appropriate.
+ varProperties->Set(id - firstVarPropertyIndex, value);
+ activate(object, methodOffset + id, 0);
+}
+
+void QQmlVMEMetaObject::writeProperty(int id, const QVariant &value)
+{
+ if (id >= firstVarPropertyIndex) {
+ ensureVarPropertiesAllocated();
+
+ // Importantly, if the current value is a scarce resource, we need to ensure that it
+ // gets automatically released by the engine if no other references to it exist.
+ v8::Local<v8::Value> oldv = varProperties->Get(id - firstVarPropertyIndex);
+ if (oldv->IsObject()) {
+ QV8VariantResource *r = v8_resource_cast<QV8VariantResource>(v8::Handle<v8::Object>::Cast(oldv));
+ if (r) {
+ r->removeVmePropertyReference();
+ }
+ }
+
+ // And, if the new value is a scarce resource, we need to ensure that it does not get
+ // automatically released by the engine until no other references to it exist.
+ v8::Handle<v8::Value> newv = QQmlEnginePrivate::get(ctxt->engine)->v8engine()->fromVariant(value);
+ if (newv->IsObject()) {
+ QV8VariantResource *r = v8_resource_cast<QV8VariantResource>(v8::Handle<v8::Object>::Cast(newv));
+ if (r) {
+ r->addVmePropertyReference();
+ }
+ }
+
+ // Write the value and emit change signal as appropriate.
+ QVariant currentValue = readPropertyAsVariant(id);
+ varProperties->Set(id - firstVarPropertyIndex, newv);
+ if ((currentValue.userType() != value.userType() || currentValue != value))
+ activate(object, methodOffset + id, 0);
+ } else {
+ bool needActivate = false;
+ if (value.userType() == QMetaType::QObjectStar) {
+ QObject *o = qvariant_cast<QObject *>(value);
+ needActivate = (data[id].dataType() != QMetaType::QObjectStar || data[id].asQObject() != o);
+ data[id].setValue(qvariant_cast<QObject *>(value));
+ } else {
+ needActivate = (data[id].dataType() != qMetaTypeId<QVariant>() ||
+ data[id].asQVariant().userType() != value.userType() ||
+ data[id].asQVariant() != value);
+ data[id].setValue(value);
+ }
+
+ if (needActivate)
+ activate(object, methodOffset + id, 0);
+ }
+}
+
+void QQmlVMEMetaObject::listChanged(int id)
+{
+ activate(object, methodOffset + id, 0);
+}
+
+void QQmlVMEMetaObject::list_append(QQmlListProperty<QObject> *prop, QObject *o)
+{
+ List *list = static_cast<List *>(prop->data);
+ list->append(o);
+ QMetaObject::activate(prop->object, list->notifyIndex, 0);
+}
+
+int QQmlVMEMetaObject::list_count(QQmlListProperty<QObject> *prop)
+{
+ return static_cast<List *>(prop->data)->count();
+}
+
+QObject *QQmlVMEMetaObject::list_at(QQmlListProperty<QObject> *prop, int index)
+{
+ return static_cast<List *>(prop->data)->at(index);
+}
+
+void QQmlVMEMetaObject::list_clear(QQmlListProperty<QObject> *prop)
+{
+ List *list = static_cast<List *>(prop->data);
+ list->clear();
+ QMetaObject::activate(prop->object, list->notifyIndex, 0);
+}
+
+void QQmlVMEMetaObject::registerInterceptor(int index, int valueIndex, QQmlPropertyValueInterceptor *interceptor)
+{
+ if (aInterceptors.isEmpty())
+ aInterceptors.resize(propertyCount() + metaData->propertyCount);
+ aInterceptors.setBit(index);
+ interceptors.insert(index, qMakePair(valueIndex, interceptor));
+}
+
+int QQmlVMEMetaObject::vmeMethodLineNumber(int index)
+{
+ if (index < methodOffset) {
+ Q_ASSERT(parent);
+ return static_cast<QQmlVMEMetaObject *>(parent)->vmeMethodLineNumber(index);
+ }
+
+ int plainSignals = metaData->signalCount + metaData->propertyCount + metaData->aliasCount;
+ Q_ASSERT(index >= (methodOffset + plainSignals) && index < (methodOffset + plainSignals + metaData->methodCount));
+
+ int rawIndex = index - methodOffset - plainSignals;
+
+ QQmlVMEMetaData::MethodData *data = metaData->methodData() + rawIndex;
+ return data->lineNumber;
+}
+
+v8::Handle<v8::Function> QQmlVMEMetaObject::vmeMethod(int index)
+{
+ if (index < methodOffset) {
+ Q_ASSERT(parent);
+ return static_cast<QQmlVMEMetaObject *>(parent)->vmeMethod(index);
+ }
+ int plainSignals = metaData->signalCount + metaData->propertyCount + metaData->aliasCount;
+ Q_ASSERT(index >= (methodOffset + plainSignals) && index < (methodOffset + plainSignals + metaData->methodCount));
+ return method(index - methodOffset - plainSignals);
+}
+
+// Used by debugger
+void QQmlVMEMetaObject::setVmeMethod(int index, v8::Persistent<v8::Function> value)
+{
+ if (index < methodOffset) {
+ Q_ASSERT(parent);
+ return static_cast<QQmlVMEMetaObject *>(parent)->setVmeMethod(index, value);
+ }
+ int plainSignals = metaData->signalCount + metaData->propertyCount + metaData->aliasCount;
+ Q_ASSERT(index >= (methodOffset + plainSignals) && index < (methodOffset + plainSignals + metaData->methodCount));
+
+ if (!v8methods)
+ v8methods = new v8::Persistent<v8::Function>[metaData->methodCount];
+
+ int methodIndex = index - methodOffset - plainSignals;
+ if (!v8methods[methodIndex].IsEmpty())
+ qPersistentDispose(v8methods[methodIndex]);
+ v8methods[methodIndex] = value;
+}
+
+v8::Handle<v8::Value> QQmlVMEMetaObject::vmeProperty(int index)
+{
+ if (index < propOffset) {
+ Q_ASSERT(parent);
+ return static_cast<QQmlVMEMetaObject *>(parent)->vmeProperty(index);
+ }
+ return readVarProperty(index - propOffset);
+}
+
+void QQmlVMEMetaObject::setVMEProperty(int index, v8::Handle<v8::Value> v)
+{
+ if (index < propOffset) {
+ Q_ASSERT(parent);
+ static_cast<QQmlVMEMetaObject *>(parent)->setVMEProperty(index, v);
+ return;
+ }
+ return writeVarProperty(index - propOffset, v);
+}
+
+void QQmlVMEMetaObject::ensureVarPropertiesAllocated()
+{
+ if (!varPropertiesInitialized)
+ allocateVarPropertiesArray();
+}
+
+// see also: QV8GCCallback::garbageCollectorPrologueCallback()
+void QQmlVMEMetaObject::allocateVarPropertiesArray()
+{
+ v8::HandleScope handleScope;
+ v8::Context::Scope cs(QQmlEnginePrivate::get(ctxt->engine)->v8engine()->context());
+ varProperties = qPersistentNew(v8::Array::New(metaData->varPropertyCount));
+ varProperties.MakeWeak(static_cast<void*>(this), VarPropertiesWeakReferenceCallback);
+ varPropertiesInitialized = true;
+}
+
+/*
+ The "var" properties are stored in a v8::Array which will be strong persistent if the object has cpp-ownership
+ and the root QObject in the parent chain does not have JS-ownership. In the weak persistent handle case,
+ this callback will dispose the handle when the v8object which owns the lifetime of the var properties array
+ is cleared as a result of all other handles to that v8object being released.
+ See QV8GCCallback::garbageCollectorPrologueCallback() for more information.
+ */
+void QQmlVMEMetaObject::VarPropertiesWeakReferenceCallback(v8::Persistent<v8::Value> object, void* parameter)
+{
+ QQmlVMEMetaObject *vmemo = static_cast<QQmlVMEMetaObject*>(parameter);
+ Q_ASSERT(vmemo);
+ qPersistentDispose(object);
+ vmemo->varProperties.Clear();
+}
+
+void QQmlVMEMetaObject::GcPrologueCallback(QV8GCCallback::Node *node)
+{
+ QQmlVMEMetaObject *vmemo = static_cast<QQmlVMEMetaObject*>(node);
+ Q_ASSERT(vmemo);
+ if (!vmemo->varPropertiesInitialized || vmemo->varProperties.IsEmpty() || !vmemo->ctxt || !vmemo->ctxt->engine)
+ return;
+ QQmlEnginePrivate *ep = QQmlEnginePrivate::get(vmemo->ctxt->engine);
+ ep->v8engine()->addRelationshipForGC(vmemo->object, vmemo->varProperties);
+}
+
+bool QQmlVMEMetaObject::aliasTarget(int index, QObject **target, int *coreIndex, int *valueTypeIndex) const
+{
+ Q_ASSERT(index >= propOffset + metaData->propertyCount);
+
+ *target = 0;
+ *coreIndex = -1;
+ *valueTypeIndex = -1;
+
+ if (!ctxt)
+ return false;
+
+ QQmlVMEMetaData::AliasData *d = metaData->aliasData() + (index - propOffset - metaData->propertyCount);
+ QQmlContext *context = ctxt->asQQmlContext();
+ QQmlContextPrivate *ctxtPriv = QQmlContextPrivate::get(context);
+
+ *target = ctxtPriv->data->idValues[d->contextIdx].data();
+ if (!*target)
+ return false;
+
+ if (d->isObjectAlias()) {
+ } else if (d->isValueTypeAlias()) {
+ *coreIndex = d->propertyIndex();
+ *valueTypeIndex = d->valueTypeIndex();
+ } else {
+ *coreIndex = d->propertyIndex();
+ }
+
+ return true;
+}
+
+void QQmlVMEMetaObject::connectAlias(int aliasId)
+{
+ if (!aConnected.testBit(aliasId)) {
+
+ if (!aliasEndpoints)
+ aliasEndpoints = new QQmlVMEMetaObjectEndpoint[metaData->aliasCount];
+
+ aConnected.setBit(aliasId);
+
+ QQmlVMEMetaData::AliasData *d = metaData->aliasData() + aliasId;
+
+ QQmlVMEMetaObjectEndpoint *endpoint = aliasEndpoints + aliasId;
+ endpoint->metaObject = this;
+
+ endpoint->connect(&ctxt->idValues[d->contextIdx].bindings);
+
+ endpoint->tryConnect();
+ }
+}
+
+void QQmlVMEMetaObject::connectAliasSignal(int index)
+{
+ int aliasId = (index - methodOffset) - metaData->propertyCount;
+ if (aliasId < 0 || aliasId >= metaData->aliasCount)
+ return;
+
+ connectAlias(aliasId);
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlvmemetaobject_p.h b/src/qml/qml/qqmlvmemetaobject_p.h
new file mode 100644
index 0000000000..deee989383
--- /dev/null
+++ b/src/qml/qml/qqmlvmemetaobject_p.h
@@ -0,0 +1,221 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLVMEMETAOBJECT_P_H
+#define QQMLVMEMETAOBJECT_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qqml.h"
+
+#include <QtCore/QMetaObject>
+#include <QtCore/QBitArray>
+#include <QtCore/QPair>
+#include <QtGui/QColor>
+#include <QtCore/QDate>
+#include <QtCore/qlist.h>
+#include <QtCore/qdebug.h>
+
+#include <private/qobject_p.h>
+
+#include "qqmlguard_p.h"
+#include "qqmlcompiler_p.h"
+#include "qqmlcontext_p.h"
+
+#include <private/qv8engine_p.h>
+
+#include <private/qv8_p.h>
+
+QT_BEGIN_NAMESPACE
+
+#define QML_ALIAS_FLAG_PTR 0x00000001
+
+struct QQmlVMEMetaData
+{
+ short varPropertyCount;
+ short propertyCount;
+ short aliasCount;
+ short signalCount;
+ short methodCount;
+ short dummyForAlignment; // Add padding to ensure that the following
+ // AliasData/PropertyData/MethodData is int aligned.
+
+ struct AliasData {
+ int contextIdx;
+ int propertyIdx;
+ int flags;
+
+ bool isObjectAlias() const {
+ return propertyIdx == -1;
+ }
+ bool isPropertyAlias() const {
+ return !isObjectAlias() && !(propertyIdx & 0xFF000000);
+ }
+ bool isValueTypeAlias() const {
+ return !isObjectAlias() && (propertyIdx & 0xFF000000);
+ }
+ int propertyIndex() const {
+ return propertyIdx & 0x0000FFFF;
+ }
+ int valueTypeIndex() const {
+ return (propertyIdx & 0x00FF0000) >> 16;
+ }
+ int valueType() const {
+ return ((unsigned int)propertyIdx) >> 24;
+ }
+ };
+
+ struct PropertyData {
+ int propertyType;
+ };
+
+ struct MethodData {
+ int parameterCount;
+ int bodyOffset;
+ int bodyLength;
+ int lineNumber;
+ };
+
+ PropertyData *propertyData() const {
+ return (PropertyData *)(((const char *)this) + sizeof(QQmlVMEMetaData));
+ }
+
+ AliasData *aliasData() const {
+ return (AliasData *)(propertyData() + propertyCount);
+ }
+
+ MethodData *methodData() const {
+ return (MethodData *)(aliasData() + aliasCount);
+ }
+};
+
+class QV8QObjectWrapper;
+class QQmlVMEVariant;
+class QQmlRefCount;
+class QQmlVMEMetaObjectEndpoint;
+class Q_AUTOTEST_EXPORT QQmlVMEMetaObject : public QAbstractDynamicMetaObject,
+ public QV8GCCallback::Node
+{
+public:
+ QQmlVMEMetaObject(QObject *obj, const QMetaObject *other, const QQmlVMEMetaData *data,
+ QQmlCompiledData *compiledData);
+ ~QQmlVMEMetaObject();
+
+ bool aliasTarget(int index, QObject **target, int *coreIndex, int *valueTypeIndex) const;
+ void registerInterceptor(int index, int valueIndex, QQmlPropertyValueInterceptor *interceptor);
+ v8::Handle<v8::Function> vmeMethod(int index);
+ int vmeMethodLineNumber(int index);
+ void setVmeMethod(int index, v8::Persistent<v8::Function>);
+ v8::Handle<v8::Value> vmeProperty(int index);
+ void setVMEProperty(int index, v8::Handle<v8::Value> v);
+
+ void connectAliasSignal(int index);
+
+protected:
+ virtual int metaCall(QMetaObject::Call _c, int _id, void **_a);
+
+private:
+ friend class QQmlVMEMetaObjectEndpoint;
+
+ QObject *object;
+ QQmlCompiledData *compiledData;
+ QQmlGuardedContextData ctxt;
+
+ const QQmlVMEMetaData *metaData;
+ int propOffset;
+ int methodOffset;
+
+ QQmlVMEVariant *data;
+ QQmlVMEMetaObjectEndpoint *aliasEndpoints;
+
+ v8::Persistent<v8::Array> varProperties;
+ int firstVarPropertyIndex;
+ bool varPropertiesInitialized;
+ static void VarPropertiesWeakReferenceCallback(v8::Persistent<v8::Value> object, void* parameter);
+ static void GcPrologueCallback(QV8GCCallback::Node *node);
+ inline void allocateVarPropertiesArray();
+ inline void ensureVarPropertiesAllocated();
+
+ void connectAlias(int aliasId);
+ QBitArray aConnected;
+ QBitArray aInterceptors;
+ QHash<int, QPair<int, QQmlPropertyValueInterceptor*> > interceptors;
+
+ v8::Persistent<v8::Function> *v8methods;
+ v8::Handle<v8::Function> method(int);
+
+ v8::Handle<v8::Value> readVarProperty(int);
+ void writeVarProperty(int, v8::Handle<v8::Value>);
+ QVariant readPropertyAsVariant(int);
+ void writeProperty(int, const QVariant &);
+
+ QAbstractDynamicMetaObject *parent;
+
+ void listChanged(int);
+ class List : public QList<QObject*>
+ {
+ public:
+ List(int lpi) : notifyIndex(lpi) {}
+ int notifyIndex;
+ };
+ QList<List> listProperties;
+
+ static void list_append(QQmlListProperty<QObject> *, QObject *);
+ static int list_count(QQmlListProperty<QObject> *);
+ static QObject *list_at(QQmlListProperty<QObject> *, int);
+ static void list_clear(QQmlListProperty<QObject> *);
+
+ friend class QV8GCCallback;
+ friend class QV8QObjectWrapper;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQMLVMEMETAOBJECT_P_H
diff --git a/src/qml/qml/qqmlwatcher.cpp b/src/qml/qml/qqmlwatcher.cpp
new file mode 100644
index 0000000000..500185762f
--- /dev/null
+++ b/src/qml/qml/qqmlwatcher.cpp
@@ -0,0 +1,188 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qqmlwatcher_p.h"
+
+#include "qqmlexpression.h"
+#include "qqmlcontext.h"
+#include "qqml.h"
+
+#include <private/qqmldebugservice_p.h>
+#include "qqmlproperty_p.h"
+#include "qqmlvaluetype_p.h"
+
+#include <QtCore/qmetaobject.h>
+#include <QtCore/qdebug.h>
+
+QT_BEGIN_NAMESPACE
+
+
+class QQmlWatchProxy : public QObject
+{
+ Q_OBJECT
+public:
+ QQmlWatchProxy(int id,
+ QObject *object,
+ int debugId,
+ const QMetaProperty &prop,
+ QQmlWatcher *parent = 0);
+
+ QQmlWatchProxy(int id,
+ QQmlExpression *exp,
+ int debugId,
+ QQmlWatcher *parent = 0);
+
+public slots:
+ void notifyValueChanged();
+
+private:
+ friend class QQmlWatcher;
+ int m_id;
+ QQmlWatcher *m_watch;
+ QObject *m_object;
+ int m_debugId;
+ QMetaProperty m_property;
+
+ QQmlExpression *m_expr;
+};
+
+QQmlWatchProxy::QQmlWatchProxy(int id,
+ QQmlExpression *exp,
+ int debugId,
+ QQmlWatcher *parent)
+: QObject(parent), m_id(id), m_watch(parent), m_object(0), m_debugId(debugId), m_expr(exp)
+{
+ QObject::connect(m_expr, SIGNAL(valueChanged()), this, SLOT(notifyValueChanged()));
+}
+
+QQmlWatchProxy::QQmlWatchProxy(int id,
+ QObject *object,
+ int debugId,
+ const QMetaProperty &prop,
+ QQmlWatcher *parent)
+: QObject(parent), m_id(id), m_watch(parent), m_object(object), m_debugId(debugId), m_property(prop), m_expr(0)
+{
+ static int refreshIdx = -1;
+ if(refreshIdx == -1)
+ refreshIdx = QQmlWatchProxy::staticMetaObject.indexOfMethod("notifyValueChanged()");
+
+ if (prop.hasNotifySignal())
+ QQmlPropertyPrivate::connect(m_object, prop.notifySignalIndex(), this, refreshIdx);
+}
+
+void QQmlWatchProxy::notifyValueChanged()
+{
+ QVariant v;
+ if (m_expr)
+ v = m_expr->evaluate();
+ else if (QQmlValueTypeFactory::isValueType(m_property.userType()))
+ v = m_property.read(m_object);
+
+ emit m_watch->propertyChanged(m_id, m_debugId, m_property, v);
+}
+
+
+QQmlWatcher::QQmlWatcher(QObject *parent)
+ : QObject(parent)
+{
+}
+
+bool QQmlWatcher::addWatch(int id, quint32 debugId)
+{
+ QObject *object = QQmlDebugService::objectForId(debugId);
+ if (object) {
+ int propCount = object->metaObject()->propertyCount();
+ for (int ii=0; ii<propCount; ii++)
+ addPropertyWatch(id, object, debugId, object->metaObject()->property(ii));
+ return true;
+ }
+ return false;
+}
+
+bool QQmlWatcher::addWatch(int id, quint32 debugId, const QByteArray &property)
+{
+ QObject *object = QQmlDebugService::objectForId(debugId);
+ if (object) {
+ int index = object->metaObject()->indexOfProperty(property.constData());
+ if (index >= 0) {
+ addPropertyWatch(id, object, debugId, object->metaObject()->property(index));
+ return true;
+ }
+ }
+ return false;
+}
+
+bool QQmlWatcher::addWatch(int id, quint32 objectId, const QString &expr)
+{
+ QObject *object = QQmlDebugService::objectForId(objectId);
+ QQmlContext *context = qmlContext(object);
+ if (context) {
+ QQmlExpression *exprObj = new QQmlExpression(context, object, expr);
+ exprObj->setNotifyOnValueChanged(true);
+ QQmlWatchProxy *proxy = new QQmlWatchProxy(id, exprObj, objectId, this);
+ exprObj->setParent(proxy);
+ m_proxies[id].append(proxy);
+ proxy->notifyValueChanged();
+ return true;
+ }
+ return false;
+}
+
+void QQmlWatcher::removeWatch(int id)
+{
+ if (!m_proxies.contains(id))
+ return;
+
+ QList<QPointer<QQmlWatchProxy> > proxies = m_proxies.take(id);
+ qDeleteAll(proxies);
+}
+
+void QQmlWatcher::addPropertyWatch(int id, QObject *object, quint32 debugId, const QMetaProperty &property)
+{
+ QQmlWatchProxy *proxy = new QQmlWatchProxy(id, object, debugId, property, this);
+ m_proxies[id].append(proxy);
+
+ proxy->notifyValueChanged();
+}
+
+QT_END_NAMESPACE
+
+#include <qqmlwatcher.moc>
diff --git a/src/qml/qml/qqmlwatcher_p.h b/src/qml/qml/qqmlwatcher_p.h
new file mode 100644
index 0000000000..70dc9d468c
--- /dev/null
+++ b/src/qml/qml/qqmlwatcher_p.h
@@ -0,0 +1,94 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLWATCHER_P_H
+#define QQMLWATCHER_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qobject.h>
+#include <QtCore/qlist.h>
+#include <QtCore/qpair.h>
+#include <QtCore/qhash.h>
+#include <QtCore/qset.h>
+#include <QtCore/qpointer.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQmlWatchProxy;
+class QQmlExpression;
+class QQmlContext;
+class QMetaProperty;
+
+class QQmlWatcher : public QObject
+{
+ Q_OBJECT
+public:
+ QQmlWatcher(QObject * = 0);
+
+ bool addWatch(int id, quint32 objectId);
+ bool addWatch(int id, quint32 objectId, const QByteArray &property);
+ bool addWatch(int id, quint32 objectId, const QString &expr);
+
+ void removeWatch(int id);
+
+Q_SIGNALS:
+ void propertyChanged(int id, int objectId, const QMetaProperty &property, const QVariant &value);
+
+private:
+ friend class QQmlWatchProxy;
+ void addPropertyWatch(int id, QObject *object, quint32 objectId, const QMetaProperty &property);
+
+ QHash<int, QList<QPointer<QQmlWatchProxy> > > m_proxies;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQMLWATCHER_P_H
diff --git a/src/qml/qml/qqmlxmlhttprequest.cpp b/src/qml/qml/qqmlxmlhttprequest.cpp
new file mode 100644
index 0000000000..122693ad91
--- /dev/null
+++ b/src/qml/qml/qqmlxmlhttprequest.cpp
@@ -0,0 +1,1797 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qqmlxmlhttprequest_p.h"
+
+#include <private/qv8engine_p.h>
+
+#include "qqmlengine.h"
+#include "qqmlengine_p.h"
+#include <private/qqmlrefcount_p.h>
+#include "qqmlengine_p.h"
+#include "qqmlexpression_p.h"
+#include "qqmlglobal_p.h"
+#include <private/qv8domerrors_p.h>
+
+#include <QtCore/qobject.h>
+#include <QtQml/qjsvalue.h>
+#include <QtQml/qjsengine.h>
+#include <QtNetwork/qnetworkreply.h>
+#include <QtCore/qtextcodec.h>
+#include <QtCore/qxmlstream.h>
+#include <QtCore/qstack.h>
+#include <QtCore/qdebug.h>
+
+#include <QtCore/QStringBuilder>
+
+#ifndef QT_NO_XMLSTREAMREADER
+
+#define V8THROW_REFERENCE(string) { \
+ v8::ThrowException(v8::Exception::ReferenceError(v8::String::New(string))); \
+ return v8::Handle<v8::Value>(); \
+}
+
+#define D(arg) (arg)->release()
+#define A(arg) (arg)->addref()
+
+QT_BEGIN_NAMESPACE
+
+DEFINE_BOOL_CONFIG_OPTION(xhrDump, QML_XHR_DUMP);
+
+struct QQmlXMLHttpRequestData {
+ QQmlXMLHttpRequestData();
+ ~QQmlXMLHttpRequestData();
+
+ v8::Persistent<v8::Function> nodeFunction;
+
+ v8::Persistent<v8::Object> namedNodeMapPrototype;
+ v8::Persistent<v8::Object> nodeListPrototype;
+ v8::Persistent<v8::Object> nodePrototype;
+ v8::Persistent<v8::Object> elementPrototype;
+ v8::Persistent<v8::Object> attrPrototype;
+ v8::Persistent<v8::Object> characterDataPrototype;
+ v8::Persistent<v8::Object> textPrototype;
+ v8::Persistent<v8::Object> cdataPrototype;
+ v8::Persistent<v8::Object> documentPrototype;
+
+ v8::Local<v8::Object> newNode();
+};
+
+static inline QQmlXMLHttpRequestData *xhrdata(QV8Engine *engine)
+{
+ return (QQmlXMLHttpRequestData *)engine->xmlHttpRequestData();
+}
+
+QQmlXMLHttpRequestData::QQmlXMLHttpRequestData()
+{
+}
+
+QQmlXMLHttpRequestData::~QQmlXMLHttpRequestData()
+{
+ qPersistentDispose(nodeFunction);
+ qPersistentDispose(namedNodeMapPrototype);
+ qPersistentDispose(nodeListPrototype);
+ qPersistentDispose(nodePrototype);
+ qPersistentDispose(elementPrototype);
+ qPersistentDispose(attrPrototype);
+ qPersistentDispose(characterDataPrototype);
+ qPersistentDispose(textPrototype);
+ qPersistentDispose(cdataPrototype);
+ qPersistentDispose(documentPrototype);
+}
+
+v8::Local<v8::Object> QQmlXMLHttpRequestData::newNode()
+{
+ if (nodeFunction.IsEmpty()) {
+ v8::Local<v8::FunctionTemplate> ft = v8::FunctionTemplate::New();
+ ft->InstanceTemplate()->SetHasExternalResource(true);
+ nodeFunction = qPersistentNew<v8::Function>(ft->GetFunction());
+ }
+
+ return nodeFunction->NewInstance();
+}
+
+namespace {
+
+class DocumentImpl;
+class NodeImpl
+{
+public:
+ NodeImpl() : type(Element), document(0), parent(0) {}
+ virtual ~NodeImpl() {
+ for (int ii = 0; ii < children.count(); ++ii)
+ delete children.at(ii);
+ for (int ii = 0; ii < attributes.count(); ++ii)
+ delete attributes.at(ii);
+ }
+
+ // These numbers are copied from the Node IDL definition
+ enum Type {
+ Attr = 2,
+ CDATA = 4,
+ Comment = 8,
+ Document = 9,
+ DocumentFragment = 11,
+ DocumentType = 10,
+ Element = 1,
+ Entity = 6,
+ EntityReference = 5,
+ Notation = 12,
+ ProcessingInstruction = 7,
+ Text = 3
+ };
+ Type type;
+
+ QString namespaceUri;
+ QString name;
+
+ QString data;
+
+ void addref();
+ void release();
+
+ DocumentImpl *document;
+ NodeImpl *parent;
+
+ QList<NodeImpl *> children;
+ QList<NodeImpl *> attributes;
+};
+
+class DocumentImpl : public QQmlRefCount, public NodeImpl
+{
+public:
+ DocumentImpl() : root(0) { type = Document; }
+ virtual ~DocumentImpl() {
+ if (root) delete root;
+ }
+
+ QString version;
+ QString encoding;
+ bool isStandalone;
+
+ NodeImpl *root;
+
+ void addref() { QQmlRefCount::addref(); }
+ void release() { QQmlRefCount::release(); }
+};
+
+class NamedNodeMap
+{
+public:
+ // JS API
+ static v8::Handle<v8::Value> length(v8::Local<v8::String>, const v8::AccessorInfo& args);
+ static v8::Handle<v8::Value> indexed(uint32_t index, const v8::AccessorInfo& info);
+ static v8::Handle<v8::Value> named(v8::Local<v8::String> property, const v8::AccessorInfo& args);
+
+ // C++ API
+ static v8::Handle<v8::Object> prototype(QV8Engine *);
+ static v8::Handle<v8::Value> create(QV8Engine *, NodeImpl *, QList<NodeImpl *> *);
+};
+
+class NodeList
+{
+public:
+ // JS API
+ static v8::Handle<v8::Value> length(v8::Local<v8::String>, const v8::AccessorInfo& args);
+ static v8::Handle<v8::Value> indexed(uint32_t index, const v8::AccessorInfo& info);
+
+ // C++ API
+ static v8::Handle<v8::Object> prototype(QV8Engine *);
+ static v8::Handle<v8::Value> create(QV8Engine *, NodeImpl *);
+};
+
+class Node
+{
+public:
+ // JS API
+ static v8::Handle<v8::Value> nodeName(v8::Local<v8::String>, const v8::AccessorInfo& args);
+ static v8::Handle<v8::Value> nodeValue(v8::Local<v8::String>, const v8::AccessorInfo& args);
+ static v8::Handle<v8::Value> nodeType(v8::Local<v8::String>, const v8::AccessorInfo& args);
+
+ static v8::Handle<v8::Value> parentNode(v8::Local<v8::String>, const v8::AccessorInfo& args);
+ static v8::Handle<v8::Value> childNodes(v8::Local<v8::String>, const v8::AccessorInfo& args);
+ static v8::Handle<v8::Value> firstChild(v8::Local<v8::String>, const v8::AccessorInfo& args);
+ static v8::Handle<v8::Value> lastChild(v8::Local<v8::String>, const v8::AccessorInfo& args);
+ static v8::Handle<v8::Value> previousSibling(v8::Local<v8::String>, const v8::AccessorInfo& args);
+ static v8::Handle<v8::Value> nextSibling(v8::Local<v8::String>, const v8::AccessorInfo& args);
+ static v8::Handle<v8::Value> attributes(v8::Local<v8::String>, const v8::AccessorInfo& args);
+
+ //static v8::Handle<v8::Value> ownerDocument(v8::Local<v8::String>, const v8::AccessorInfo& args);
+ //static v8::Handle<v8::Value> namespaceURI(v8::Local<v8::String>, const v8::AccessorInfo& args);
+ //static v8::Handle<v8::Value> prefix(v8::Local<v8::String>, const v8::AccessorInfo& args);
+ //static v8::Handle<v8::Value> localName(v8::Local<v8::String>, const v8::AccessorInfo& args);
+ //static v8::Handle<v8::Value> baseURI(v8::Local<v8::String>, const v8::AccessorInfo& args);
+ //static v8::Handle<v8::Value> textContent(v8::Local<v8::String>, const v8::AccessorInfo& args);
+
+ // C++ API
+ static v8::Handle<v8::Object> prototype(QV8Engine *);
+ static v8::Handle<v8::Value> create(QV8Engine *, NodeImpl *);
+
+ Node();
+ Node(const Node &o);
+ ~Node();
+ bool isNull() const;
+
+ NodeImpl *d;
+
+private:
+ Node &operator=(const Node &);
+};
+
+class Element : public Node
+{
+public:
+ // C++ API
+ static v8::Handle<v8::Object> prototype(QV8Engine *);
+};
+
+class Attr : public Node
+{
+public:
+ // JS API
+ static v8::Handle<v8::Value> name(v8::Local<v8::String>, const v8::AccessorInfo& args);
+ static v8::Handle<v8::Value> specified(v8::Local<v8::String>, const v8::AccessorInfo& args);
+ static v8::Handle<v8::Value> value(v8::Local<v8::String>, const v8::AccessorInfo& args);
+ static v8::Handle<v8::Value> ownerElement(v8::Local<v8::String>, const v8::AccessorInfo& args);
+ static v8::Handle<v8::Value> schemaTypeInfo(v8::Local<v8::String>, const v8::AccessorInfo& args);
+ static v8::Handle<v8::Value> isId(v8::Local<v8::String>, const v8::AccessorInfo& args);
+
+ // C++ API
+ static v8::Handle<v8::Object> prototype(QV8Engine *);
+};
+
+class CharacterData : public Node
+{
+public:
+ // JS API
+ static v8::Handle<v8::Value> length(v8::Local<v8::String>, const v8::AccessorInfo& args);
+
+ // C++ API
+ static v8::Handle<v8::Object> prototype(QV8Engine *);
+};
+
+class Text : public CharacterData
+{
+public:
+ // JS API
+ static v8::Handle<v8::Value> isElementContentWhitespace(v8::Local<v8::String>, const v8::AccessorInfo& args);
+ static v8::Handle<v8::Value> wholeText(v8::Local<v8::String>, const v8::AccessorInfo& args);
+
+ // C++ API
+ static v8::Handle<v8::Object> prototype(QV8Engine *);
+};
+
+class CDATA : public Text
+{
+public:
+ // C++ API
+ static v8::Handle<v8::Object> prototype(QV8Engine *);
+};
+
+class Document : public Node
+{
+public:
+ // JS API
+ static v8::Handle<v8::Value> xmlVersion(v8::Local<v8::String>, const v8::AccessorInfo& args);
+ static v8::Handle<v8::Value> xmlEncoding(v8::Local<v8::String>, const v8::AccessorInfo& args);
+ static v8::Handle<v8::Value> xmlStandalone(v8::Local<v8::String>, const v8::AccessorInfo& args);
+ static v8::Handle<v8::Value> documentElement(v8::Local<v8::String>, const v8::AccessorInfo& args);
+
+ // C++ API
+ static v8::Handle<v8::Object> prototype(QV8Engine *);
+ static v8::Handle<v8::Value> load(QV8Engine *engine, const QByteArray &data);
+};
+
+}
+
+class QQmlDOMNodeResource : public QV8ObjectResource, public Node
+{
+ V8_RESOURCE_TYPE(DOMNodeType);
+public:
+ QQmlDOMNodeResource(QV8Engine *e);
+
+ QList<NodeImpl *> *list; // Only used in NamedNodeMap
+};
+
+QQmlDOMNodeResource::QQmlDOMNodeResource(QV8Engine *e)
+: QV8ObjectResource(e), list(0)
+{
+}
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(Node)
+Q_DECLARE_METATYPE(NodeList)
+Q_DECLARE_METATYPE(NamedNodeMap)
+
+QT_BEGIN_NAMESPACE
+
+void NodeImpl::addref()
+{
+ A(document);
+}
+
+void NodeImpl::release()
+{
+ D(document);
+}
+
+v8::Handle<v8::Value> Node::nodeName(v8::Local<v8::String>, const v8::AccessorInfo &args)
+{
+ QQmlDOMNodeResource *r = v8_resource_cast<QQmlDOMNodeResource>(args.This());
+ if (!r) return v8::Undefined();
+ QV8Engine *engine = V8ENGINE();
+
+ switch (r->d->type) {
+ case NodeImpl::Document:
+ return v8::String::New("#document");
+ case NodeImpl::CDATA:
+ return v8::String::New("#cdata-section");
+ case NodeImpl::Text:
+ return v8::String::New("#text");
+ default:
+ return engine->toString(r->d->name);
+ }
+}
+
+v8::Handle<v8::Value> Node::nodeValue(v8::Local<v8::String>, const v8::AccessorInfo &args)
+{
+ QQmlDOMNodeResource *r = v8_resource_cast<QQmlDOMNodeResource>(args.This());
+ if (!r) return v8::Undefined();
+ QV8Engine *engine = V8ENGINE();
+
+ if (r->d->type == NodeImpl::Document ||
+ r->d->type == NodeImpl::DocumentFragment ||
+ r->d->type == NodeImpl::DocumentType ||
+ r->d->type == NodeImpl::Element ||
+ r->d->type == NodeImpl::Entity ||
+ r->d->type == NodeImpl::EntityReference ||
+ r->d->type == NodeImpl::Notation)
+ return v8::Null();
+
+ return engine->toString(r->d->data);
+}
+
+v8::Handle<v8::Value> Node::nodeType(v8::Local<v8::String>, const v8::AccessorInfo &args)
+{
+ QQmlDOMNodeResource *r = v8_resource_cast<QQmlDOMNodeResource>(args.This());
+ if (!r) return v8::Undefined();
+ return v8::Integer::New(r->d->type);
+}
+
+v8::Handle<v8::Value> Node::parentNode(v8::Local<v8::String>, const v8::AccessorInfo &args)
+{
+ QQmlDOMNodeResource *r = v8_resource_cast<QQmlDOMNodeResource>(args.This());
+ if (!r) return v8::Undefined();
+ QV8Engine *engine = V8ENGINE();
+
+ if (r->d->parent) return Node::create(engine, r->d->parent);
+ else return v8::Null();
+}
+
+v8::Handle<v8::Value> Node::childNodes(v8::Local<v8::String>, const v8::AccessorInfo &args)
+{
+ QQmlDOMNodeResource *r = v8_resource_cast<QQmlDOMNodeResource>(args.This());
+ if (!r) return v8::Undefined();
+ QV8Engine *engine = V8ENGINE();
+
+ return NodeList::create(engine, r->d);
+}
+
+v8::Handle<v8::Value> Node::firstChild(v8::Local<v8::String>, const v8::AccessorInfo &args)
+{
+ QQmlDOMNodeResource *r = v8_resource_cast<QQmlDOMNodeResource>(args.This());
+ if (!r) return v8::Undefined();
+ QV8Engine *engine = V8ENGINE();
+
+ if (r->d->children.isEmpty()) return v8::Null();
+ else return Node::create(engine, r->d->children.first());
+}
+
+v8::Handle<v8::Value> Node::lastChild(v8::Local<v8::String>, const v8::AccessorInfo &args)
+{
+ QQmlDOMNodeResource *r = v8_resource_cast<QQmlDOMNodeResource>(args.This());
+ if (!r) return v8::Undefined();
+ QV8Engine *engine = V8ENGINE();
+
+ if (r->d->children.isEmpty()) return v8::Null();
+ else return Node::create(engine, r->d->children.last());
+}
+
+v8::Handle<v8::Value> Node::previousSibling(v8::Local<v8::String>, const v8::AccessorInfo &args)
+{
+ QQmlDOMNodeResource *r = v8_resource_cast<QQmlDOMNodeResource>(args.This());
+ if (!r) return v8::Undefined();
+ QV8Engine *engine = V8ENGINE();
+
+ if (!r->d->parent) return v8::Null();
+
+ for (int ii = 0; ii < r->d->parent->children.count(); ++ii) {
+ if (r->d->parent->children.at(ii) == r->d) {
+ if (ii == 0) return v8::Null();
+ else return Node::create(engine, r->d->parent->children.at(ii - 1));
+ }
+ }
+
+ return v8::Null();
+}
+
+v8::Handle<v8::Value> Node::nextSibling(v8::Local<v8::String>, const v8::AccessorInfo &args)
+{
+ QQmlDOMNodeResource *r = v8_resource_cast<QQmlDOMNodeResource>(args.This());
+ if (!r) return v8::Undefined();
+ QV8Engine *engine = V8ENGINE();
+
+ if (!r->d->parent) return v8::Null();
+
+ for (int ii = 0; ii < r->d->parent->children.count(); ++ii) {
+ if (r->d->parent->children.at(ii) == r->d) {
+ if ((ii + 1) == r->d->parent->children.count()) return v8::Null();
+ else return Node::create(engine, r->d->parent->children.at(ii + 1));
+ }
+ }
+
+ return v8::Null();
+}
+
+v8::Handle<v8::Value> Node::attributes(v8::Local<v8::String>, const v8::AccessorInfo &args)
+{
+ QQmlDOMNodeResource *r = v8_resource_cast<QQmlDOMNodeResource>(args.This());
+ if (!r) return v8::Undefined();
+ QV8Engine *engine = V8ENGINE();
+
+ if (r->d->type != NodeImpl::Element)
+ return v8::Null();
+ else
+ return NamedNodeMap::create(engine, r->d, &r->d->attributes);
+}
+
+v8::Handle<v8::Object> Node::prototype(QV8Engine *engine)
+{
+ QQmlXMLHttpRequestData *d = xhrdata(engine);
+ if (d->nodePrototype.IsEmpty()) {
+ d->nodePrototype = qPersistentNew<v8::Object>(v8::Object::New());
+ d->nodePrototype->SetAccessor(v8::String::New("nodeName"), nodeName,
+ 0, v8::External::Wrap(engine));
+ d->nodePrototype->SetAccessor(v8::String::New("nodeValue"), nodeValue,
+ 0, v8::External::Wrap(engine));
+ d->nodePrototype->SetAccessor(v8::String::New("nodeType"), nodeType,
+ 0, v8::External::Wrap(engine));
+ d->nodePrototype->SetAccessor(v8::String::New("parentNode"), parentNode,
+ 0, v8::External::Wrap(engine));
+ d->nodePrototype->SetAccessor(v8::String::New("childNodes"), childNodes,
+ 0, v8::External::Wrap(engine));
+ d->nodePrototype->SetAccessor(v8::String::New("firstChild"), firstChild,
+ 0, v8::External::Wrap(engine));
+ d->nodePrototype->SetAccessor(v8::String::New("lastChild"), lastChild,
+ 0, v8::External::Wrap(engine));
+ d->nodePrototype->SetAccessor(v8::String::New("previousSibling"), previousSibling,
+ 0, v8::External::Wrap(engine));
+ d->nodePrototype->SetAccessor(v8::String::New("nextSibling"), nextSibling,
+ 0, v8::External::Wrap(engine));
+ d->nodePrototype->SetAccessor(v8::String::New("attributes"), attributes,
+ 0, v8::External::Wrap(engine));
+ engine->freezeObject(d->nodePrototype);
+ }
+ return d->nodePrototype;
+}
+
+v8::Handle<v8::Value> Node::create(QV8Engine *engine, NodeImpl *data)
+{
+ QQmlXMLHttpRequestData *d = xhrdata(engine);
+ v8::Local<v8::Object> instance = d->newNode();
+
+ switch (data->type) {
+ case NodeImpl::Attr:
+ instance->SetPrototype(Attr::prototype(engine));
+ break;
+ case NodeImpl::Comment:
+ case NodeImpl::Document:
+ case NodeImpl::DocumentFragment:
+ case NodeImpl::DocumentType:
+ case NodeImpl::Entity:
+ case NodeImpl::EntityReference:
+ case NodeImpl::Notation:
+ case NodeImpl::ProcessingInstruction:
+ return v8::Undefined();
+ case NodeImpl::CDATA:
+ instance->SetPrototype(CDATA::prototype(engine));
+ break;
+ case NodeImpl::Text:
+ instance->SetPrototype(Text::prototype(engine));
+ break;
+ case NodeImpl::Element:
+ instance->SetPrototype(Element::prototype(engine));
+ break;
+ }
+
+ QQmlDOMNodeResource *r = new QQmlDOMNodeResource(engine);
+ r->d = data;
+ if (data) A(data);
+ instance->SetExternalResource(r);
+
+ return instance;
+}
+
+v8::Handle<v8::Object> Element::prototype(QV8Engine *engine)
+{
+ QQmlXMLHttpRequestData *d = xhrdata(engine);
+ if (d->elementPrototype.IsEmpty()) {
+ d->elementPrototype = qPersistentNew<v8::Object>(v8::Object::New());
+ d->elementPrototype->SetPrototype(Node::prototype(engine));
+ d->elementPrototype->SetAccessor(v8::String::New("tagName"), nodeName,
+ 0, v8::External::Wrap(engine));
+ engine->freezeObject(d->elementPrototype);
+ }
+ return d->elementPrototype;
+}
+
+v8::Handle<v8::Object> Attr::prototype(QV8Engine *engine)
+{
+ QQmlXMLHttpRequestData *d = xhrdata(engine);
+ if (d->attrPrototype.IsEmpty()) {
+ d->attrPrototype = qPersistentNew<v8::Object>(v8::Object::New());
+ d->attrPrototype->SetPrototype(Node::prototype(engine));
+ d->attrPrototype->SetAccessor(v8::String::New("name"), name,
+ 0, v8::External::Wrap(engine));
+ d->attrPrototype->SetAccessor(v8::String::New("value"), value,
+ 0, v8::External::Wrap(engine));
+ d->attrPrototype->SetAccessor(v8::String::New("ownerElement"), ownerElement,
+ 0, v8::External::Wrap(engine));
+ engine->freezeObject(d->attrPrototype);
+ }
+ return d->attrPrototype;
+}
+
+v8::Handle<v8::Value> Attr::name(v8::Local<v8::String>, const v8::AccessorInfo &args)
+{
+ QQmlDOMNodeResource *r = v8_resource_cast<QQmlDOMNodeResource>(args.This());
+ if (!r) return v8::Undefined();
+ QV8Engine *engine = V8ENGINE();
+
+ return engine->toString(r->d->name);
+}
+
+v8::Handle<v8::Value> Attr::value(v8::Local<v8::String>, const v8::AccessorInfo &args)
+{
+ QQmlDOMNodeResource *r = v8_resource_cast<QQmlDOMNodeResource>(args.This());
+ if (!r) return v8::Undefined();
+ QV8Engine *engine = V8ENGINE();
+
+ return engine->toString(r->d->data);
+}
+
+v8::Handle<v8::Value> Attr::ownerElement(v8::Local<v8::String>, const v8::AccessorInfo &args)
+{
+ QQmlDOMNodeResource *r = v8_resource_cast<QQmlDOMNodeResource>(args.This());
+ if (!r) return v8::Undefined();
+ QV8Engine *engine = V8ENGINE();
+
+ return Node::create(engine, r->d->parent);
+}
+
+v8::Handle<v8::Value> CharacterData::length(v8::Local<v8::String>, const v8::AccessorInfo &args)
+{
+ QQmlDOMNodeResource *r = v8_resource_cast<QQmlDOMNodeResource>(args.This());
+ if (!r) return v8::Undefined();
+ QV8Engine *engine = V8ENGINE();
+ Q_UNUSED(engine)
+ return v8::Integer::New(r->d->data.length());
+}
+
+v8::Handle<v8::Object> CharacterData::prototype(QV8Engine *engine)
+{
+ QQmlXMLHttpRequestData *d = xhrdata(engine);
+ if (d->characterDataPrototype.IsEmpty()) {
+ d->characterDataPrototype = qPersistentNew<v8::Object>(v8::Object::New());
+ d->characterDataPrototype->SetPrototype(Node::prototype(engine));
+ d->characterDataPrototype->SetAccessor(v8::String::New("data"), nodeValue,
+ 0, v8::External::Wrap(engine));
+ d->characterDataPrototype->SetAccessor(v8::String::New("length"), length,
+ 0, v8::External::Wrap(engine));
+ engine->freezeObject(d->characterDataPrototype);
+ }
+ return d->characterDataPrototype;
+}
+
+v8::Handle<v8::Value> Text::isElementContentWhitespace(v8::Local<v8::String>, const v8::AccessorInfo &args)
+{
+ QQmlDOMNodeResource *r = v8_resource_cast<QQmlDOMNodeResource>(args.This());
+ if (!r) return v8::Undefined();
+ QV8Engine *engine = V8ENGINE();
+ Q_UNUSED(engine)
+ return v8::Boolean::New(r->d->data.trimmed().isEmpty());
+}
+
+v8::Handle<v8::Value> Text::wholeText(v8::Local<v8::String>, const v8::AccessorInfo &args)
+{
+ QQmlDOMNodeResource *r = v8_resource_cast<QQmlDOMNodeResource>(args.This());
+ if (!r) return v8::Undefined();
+ QV8Engine *engine = V8ENGINE();
+
+ return engine->toString(r->d->data);
+}
+
+v8::Handle<v8::Object> Text::prototype(QV8Engine *engine)
+{
+ QQmlXMLHttpRequestData *d = xhrdata(engine);
+ if (d->textPrototype.IsEmpty()) {
+ d->textPrototype = qPersistentNew<v8::Object>(v8::Object::New());
+ d->textPrototype->SetPrototype(CharacterData::prototype(engine));
+ d->textPrototype->SetAccessor(v8::String::New("isElementContentWhitespace"), isElementContentWhitespace,
+ 0, v8::External::Wrap(engine));
+ d->textPrototype->SetAccessor(v8::String::New("wholeText"), wholeText,
+ 0, v8::External::Wrap(engine));
+ engine->freezeObject(d->textPrototype);
+ }
+ return d->textPrototype;
+}
+
+v8::Handle<v8::Object> CDATA::prototype(QV8Engine *engine)
+{
+ QQmlXMLHttpRequestData *d = xhrdata(engine);
+ if (d->cdataPrototype.IsEmpty()) {
+ d->cdataPrototype = qPersistentNew<v8::Object>(v8::Object::New());
+ d->cdataPrototype->SetPrototype(Text::prototype(engine));
+ engine->freezeObject(d->cdataPrototype);
+ }
+ return d->cdataPrototype;
+}
+
+v8::Handle<v8::Object> Document::prototype(QV8Engine *engine)
+{
+ QQmlXMLHttpRequestData *d = xhrdata(engine);
+ if (d->documentPrototype.IsEmpty()) {
+ d->documentPrototype = qPersistentNew<v8::Object>(v8::Object::New());
+ d->documentPrototype->SetPrototype(Node::prototype(engine));
+ d->documentPrototype->SetAccessor(v8::String::New("xmlVersion"), xmlVersion,
+ 0, v8::External::Wrap(engine));
+ d->documentPrototype->SetAccessor(v8::String::New("xmlEncoding"), xmlEncoding,
+ 0, v8::External::Wrap(engine));
+ d->documentPrototype->SetAccessor(v8::String::New("xmlStandalone"), xmlStandalone,
+ 0, v8::External::Wrap(engine));
+ d->documentPrototype->SetAccessor(v8::String::New("documentElement"), documentElement,
+ 0, v8::External::Wrap(engine));
+ engine->freezeObject(d->documentPrototype);
+ }
+ return d->documentPrototype;
+}
+
+v8::Handle<v8::Value> Document::load(QV8Engine *engine, const QByteArray &data)
+{
+ Q_ASSERT(engine);
+
+ DocumentImpl *document = 0;
+ QStack<NodeImpl *> nodeStack;
+
+ QXmlStreamReader reader(data);
+
+ while (!reader.atEnd()) {
+ switch (reader.readNext()) {
+ case QXmlStreamReader::NoToken:
+ break;
+ case QXmlStreamReader::Invalid:
+ break;
+ case QXmlStreamReader::StartDocument:
+ Q_ASSERT(!document);
+ document = new DocumentImpl;
+ document->document = document;
+ document->version = reader.documentVersion().toString();
+ document->encoding = reader.documentEncoding().toString();
+ document->isStandalone = reader.isStandaloneDocument();
+ break;
+ case QXmlStreamReader::EndDocument:
+ break;
+ case QXmlStreamReader::StartElement:
+ {
+ Q_ASSERT(document);
+ NodeImpl *node = new NodeImpl;
+ node->document = document;
+ node->namespaceUri = reader.namespaceUri().toString();
+ node->name = reader.name().toString();
+ if (nodeStack.isEmpty()) {
+ document->root = node;
+ } else {
+ node->parent = nodeStack.top();
+ node->parent->children.append(node);
+ }
+ nodeStack.append(node);
+
+ foreach (const QXmlStreamAttribute &a, reader.attributes()) {
+ NodeImpl *attr = new NodeImpl;
+ attr->document = document;
+ attr->type = NodeImpl::Attr;
+ attr->namespaceUri = a.namespaceUri().toString();
+ attr->name = a.name().toString();
+ attr->data = a.value().toString();
+ attr->parent = node;
+ node->attributes.append(attr);
+ }
+ }
+ break;
+ case QXmlStreamReader::EndElement:
+ nodeStack.pop();
+ break;
+ case QXmlStreamReader::Characters:
+ {
+ NodeImpl *node = new NodeImpl;
+ node->document = document;
+ node->type = reader.isCDATA()?NodeImpl::CDATA:NodeImpl::Text;
+ node->parent = nodeStack.top();
+ node->parent->children.append(node);
+ node->data = reader.text().toString();
+ }
+ break;
+ case QXmlStreamReader::Comment:
+ break;
+ case QXmlStreamReader::DTD:
+ break;
+ case QXmlStreamReader::EntityReference:
+ break;
+ case QXmlStreamReader::ProcessingInstruction:
+ break;
+ }
+ }
+
+ if (!document || reader.hasError()) {
+ if (document) D(document);
+ return v8::Null();
+ }
+
+ v8::Local<v8::Object> instance = xhrdata(engine)->newNode();
+ QQmlDOMNodeResource *r = new QQmlDOMNodeResource(engine);
+ r->d = document;
+ instance->SetExternalResource(r);
+ instance->SetPrototype(Document::prototype(engine));
+ return instance;
+}
+
+Node::Node()
+: d(0)
+{
+}
+
+Node::Node(const Node &o)
+: d(o.d)
+{
+ if (d) A(d);
+}
+
+Node::~Node()
+{
+ if (d) D(d);
+}
+
+bool Node::isNull() const
+{
+ return d == 0;
+}
+
+v8::Handle<v8::Value> NamedNodeMap::length(v8::Local<v8::String>, const v8::AccessorInfo &args)
+{
+ QQmlDOMNodeResource *r = v8_resource_cast<QQmlDOMNodeResource>(args.This());
+ if (!r) return v8::Undefined();
+ QV8Engine *engine = V8ENGINE();
+ Q_UNUSED(engine)
+ return v8::Integer::New(r->list->count());
+}
+
+v8::Handle<v8::Value> NamedNodeMap::indexed(uint32_t index, const v8::AccessorInfo& args)
+{
+ QQmlDOMNodeResource *r = v8_resource_cast<QQmlDOMNodeResource>(args.This());
+ if (!r || !r->list) return v8::Undefined();
+ QV8Engine *engine = V8ENGINE();
+
+ if ((int)index < r->list->count()) {
+ return Node::create(engine, r->list->at(index));
+ } else {
+ return v8::Undefined();
+ }
+}
+
+v8::Handle<v8::Value> NamedNodeMap::named(v8::Local<v8::String> property, const v8::AccessorInfo& args)
+{
+ QQmlDOMNodeResource *r = v8_resource_cast<QQmlDOMNodeResource>(args.This());
+ if (!r || !r->list) return v8::Undefined();
+ QV8Engine *engine = V8ENGINE();
+
+ QString str = engine->toString(property);
+ for (int ii = 0; ii < r->list->count(); ++ii) {
+ if (r->list->at(ii)->name == str) {
+ return Node::create(engine, r->list->at(ii));
+ }
+ }
+
+ return v8::Undefined();
+}
+
+v8::Handle<v8::Object> NamedNodeMap::prototype(QV8Engine *engine)
+{
+ QQmlXMLHttpRequestData *d = xhrdata(engine);
+ if (d->namedNodeMapPrototype.IsEmpty()) {
+ v8::Local<v8::ObjectTemplate> ot = v8::ObjectTemplate::New();
+ ot->SetAccessor(v8::String::New("length"), length, 0, v8::External::Wrap(engine));
+ ot->SetIndexedPropertyHandler(indexed, 0, 0, 0, 0, v8::External::Wrap(engine));
+ ot->SetFallbackPropertyHandler(named, 0, 0, 0, 0, v8::External::Wrap(engine));
+ d->namedNodeMapPrototype = qPersistentNew<v8::Object>(ot->NewInstance());
+ engine->freezeObject(d->namedNodeMapPrototype);
+ }
+ return d->namedNodeMapPrototype;
+}
+
+v8::Handle<v8::Value> NamedNodeMap::create(QV8Engine *engine, NodeImpl *data, QList<NodeImpl *> *list)
+{
+ QQmlXMLHttpRequestData *d = xhrdata(engine);
+ v8::Local<v8::Object> instance = d->newNode();
+ instance->SetPrototype(NamedNodeMap::prototype(engine));
+ QQmlDOMNodeResource *r = new QQmlDOMNodeResource(engine);
+ r->d = data;
+ r->list = list;
+ if (data) A(data);
+ instance->SetExternalResource(r);
+ return instance;
+}
+
+v8::Handle<v8::Value> NodeList::indexed(uint32_t index, const v8::AccessorInfo& args)
+{
+ QQmlDOMNodeResource *r = v8_resource_cast<QQmlDOMNodeResource>(args.This());
+ if (!r) return v8::Undefined();
+ QV8Engine *engine = V8ENGINE();
+
+ if ((int)index < r->d->children.count()) {
+ return Node::create(engine, r->d->children.at(index));
+ } else {
+ return v8::Undefined();
+ }
+}
+
+v8::Handle<v8::Value> NodeList::length(v8::Local<v8::String>, const v8::AccessorInfo& args)
+{
+ QQmlDOMNodeResource *r = v8_resource_cast<QQmlDOMNodeResource>(args.This());
+ if (!r) return v8::Undefined();
+ QV8Engine *engine = V8ENGINE();
+ Q_UNUSED(engine)
+ return v8::Integer::New(r->d->children.count());
+}
+
+v8::Handle<v8::Object> NodeList::prototype(QV8Engine *engine)
+{
+ QQmlXMLHttpRequestData *d = xhrdata(engine);
+ if (d->nodeListPrototype.IsEmpty()) {
+ v8::Local<v8::ObjectTemplate> ot = v8::ObjectTemplate::New();
+ ot->SetAccessor(v8::String::New("length"), length, 0, v8::External::Wrap(engine));
+ ot->SetIndexedPropertyHandler(indexed, 0, 0, 0, 0, v8::External::Wrap(engine));
+ d->nodeListPrototype = qPersistentNew<v8::Object>(ot->NewInstance());
+ engine->freezeObject(d->nodeListPrototype);
+ }
+ return d->nodeListPrototype;
+}
+
+v8::Handle<v8::Value> NodeList::create(QV8Engine *engine, NodeImpl *data)
+{
+ QQmlXMLHttpRequestData *d = xhrdata(engine);
+ v8::Local<v8::Object> instance = d->newNode();
+ instance->SetPrototype(NodeList::prototype(engine));
+ QQmlDOMNodeResource *r = new QQmlDOMNodeResource(engine);
+ r->d = data;
+ if (data) A(data);
+ instance->SetExternalResource(r);
+ return instance;
+}
+
+v8::Handle<v8::Value> Document::documentElement(v8::Local<v8::String>, const v8::AccessorInfo& args)
+{
+ QQmlDOMNodeResource *r = v8_resource_cast<QQmlDOMNodeResource>(args.This());
+ if (!r || r->d->type != NodeImpl::Document) return v8::Undefined();
+ QV8Engine *engine = V8ENGINE();
+
+ return Node::create(engine, static_cast<DocumentImpl *>(r->d)->root);
+}
+
+v8::Handle<v8::Value> Document::xmlStandalone(v8::Local<v8::String>, const v8::AccessorInfo& args)
+{
+ QQmlDOMNodeResource *r = v8_resource_cast<QQmlDOMNodeResource>(args.This());
+ if (!r || r->d->type != NodeImpl::Document) return v8::Undefined();
+ QV8Engine *engine = V8ENGINE();
+ Q_UNUSED(engine)
+ return v8::Boolean::New(static_cast<DocumentImpl *>(r->d)->isStandalone);
+}
+
+v8::Handle<v8::Value> Document::xmlVersion(v8::Local<v8::String>, const v8::AccessorInfo& args)
+{
+ QQmlDOMNodeResource *r = v8_resource_cast<QQmlDOMNodeResource>(args.This());
+ if (!r || r->d->type != NodeImpl::Document) return v8::Undefined();
+ QV8Engine *engine = V8ENGINE();
+
+ return engine->toString(static_cast<DocumentImpl *>(r->d)->version);
+}
+
+v8::Handle<v8::Value> Document::xmlEncoding(v8::Local<v8::String>, const v8::AccessorInfo& args)
+{
+ QQmlDOMNodeResource *r = v8_resource_cast<QQmlDOMNodeResource>(args.This());
+ if (!r || r->d->type != NodeImpl::Document) return v8::Undefined();
+ QV8Engine *engine = V8ENGINE();
+
+ return engine->toString(static_cast<DocumentImpl *>(r->d)->encoding);
+}
+
+class QQmlXMLHttpRequest : public QObject, public QV8ObjectResource
+{
+Q_OBJECT
+V8_RESOURCE_TYPE(XMLHttpRequestType)
+public:
+ enum State { Unsent = 0,
+ Opened = 1, HeadersReceived = 2,
+ Loading = 3, Done = 4 };
+
+ QQmlXMLHttpRequest(QV8Engine *engine, QNetworkAccessManager *manager);
+ virtual ~QQmlXMLHttpRequest();
+
+ bool sendFlag() const;
+ bool errorFlag() const;
+ quint32 readyState() const;
+ int replyStatus() const;
+ QString replyStatusText() const;
+
+ v8::Handle<v8::Value> open(v8::Handle<v8::Object> me, const QString &, const QUrl &);
+ v8::Handle<v8::Value> send(v8::Handle<v8::Object> me, const QByteArray &);
+ v8::Handle<v8::Value> abort(v8::Handle<v8::Object> me);
+
+ void addHeader(const QString &, const QString &);
+ QString header(const QString &name);
+ QString headers();
+
+
+ QString responseBody();
+ const QByteArray & rawResponseBody() const;
+ bool receivedXml() const;
+private slots:
+ void downloadProgress(qint64);
+ void error(QNetworkReply::NetworkError);
+ void finished();
+
+private:
+ void requestFromUrl(const QUrl &url);
+
+ State m_state;
+ bool m_errorFlag;
+ bool m_sendFlag;
+ QString m_method;
+ QUrl m_url;
+ QByteArray m_responseEntityBody;
+ QByteArray m_data;
+ int m_redirectCount;
+
+ typedef QPair<QByteArray, QByteArray> HeaderPair;
+ typedef QList<HeaderPair> HeadersList;
+ HeadersList m_headersList;
+ void fillHeadersList();
+
+ bool m_gotXml;
+ QByteArray m_mime;
+ QByteArray m_charset;
+ QTextCodec *m_textCodec;
+#ifndef QT_NO_TEXTCODEC
+ QTextCodec* findTextCodec() const;
+#endif
+ void readEncoding();
+
+ v8::Handle<v8::Object> getMe() const;
+ void setMe(v8::Handle<v8::Object> me);
+ v8::Persistent<v8::Object> m_me;
+
+ void dispatchCallback(v8::Handle<v8::Object> me);
+ void printError(v8::Handle<v8::Message>);
+
+ int m_status;
+ QString m_statusText;
+ QNetworkRequest m_request;
+ QQmlGuard<QNetworkReply> m_network;
+ void destroyNetwork();
+
+ QNetworkAccessManager *m_nam;
+ QNetworkAccessManager *networkAccessManager() { return m_nam; }
+};
+
+QQmlXMLHttpRequest::QQmlXMLHttpRequest(QV8Engine *engine, QNetworkAccessManager *manager)
+: QV8ObjectResource(engine), m_state(Unsent), m_errorFlag(false), m_sendFlag(false),
+ m_redirectCount(0), m_gotXml(false), m_textCodec(0), m_network(0), m_nam(manager)
+{
+}
+
+QQmlXMLHttpRequest::~QQmlXMLHttpRequest()
+{
+ destroyNetwork();
+}
+
+bool QQmlXMLHttpRequest::sendFlag() const
+{
+ return m_sendFlag;
+}
+
+bool QQmlXMLHttpRequest::errorFlag() const
+{
+ return m_errorFlag;
+}
+
+quint32 QQmlXMLHttpRequest::readyState() const
+{
+ return m_state;
+}
+
+int QQmlXMLHttpRequest::replyStatus() const
+{
+ return m_status;
+}
+
+QString QQmlXMLHttpRequest::replyStatusText() const
+{
+ return m_statusText;
+}
+
+v8::Handle<v8::Value> QQmlXMLHttpRequest::open(v8::Handle<v8::Object> me, const QString &method,
+ const QUrl &url)
+{
+ destroyNetwork();
+ m_sendFlag = false;
+ m_errorFlag = false;
+ m_responseEntityBody = QByteArray();
+ m_method = method;
+ m_url = url;
+ m_state = Opened;
+ dispatchCallback(me);
+ return v8::Undefined();
+}
+
+void QQmlXMLHttpRequest::addHeader(const QString &name, const QString &value)
+{
+ QByteArray utfname = name.toUtf8();
+
+ if (m_request.hasRawHeader(utfname)) {
+ m_request.setRawHeader(utfname, m_request.rawHeader(utfname) + ',' + value.toUtf8());
+ } else {
+ m_request.setRawHeader(utfname, value.toUtf8());
+ }
+}
+
+QString QQmlXMLHttpRequest::header(const QString &name)
+{
+ QByteArray utfname = name.toLower().toUtf8();
+
+ foreach (const HeaderPair &header, m_headersList) {
+ if (header.first == utfname)
+ return QString::fromUtf8(header.second);
+ }
+ return QString();
+}
+
+QString QQmlXMLHttpRequest::headers()
+{
+ QString ret;
+
+ foreach (const HeaderPair &header, m_headersList) {
+ if (ret.length())
+ ret.append(QLatin1String("\r\n"));
+ ret = ret % QString::fromUtf8(header.first) % QLatin1String(": ")
+ % QString::fromUtf8(header.second);
+ }
+ return ret;
+}
+
+void QQmlXMLHttpRequest::fillHeadersList()
+{
+ QList<QByteArray> headerList = m_network->rawHeaderList();
+
+ m_headersList.clear();
+ foreach (const QByteArray &header, headerList) {
+ HeaderPair pair (header.toLower(), m_network->rawHeader(header));
+ if (pair.first == "set-cookie" ||
+ pair.first == "set-cookie2")
+ continue;
+
+ m_headersList << pair;
+ }
+}
+
+void QQmlXMLHttpRequest::requestFromUrl(const QUrl &url)
+{
+ QNetworkRequest request = m_request;
+ request.setUrl(url);
+ if(m_method == QLatin1String("POST") ||
+ m_method == QLatin1String("PUT")) {
+ QVariant var = request.header(QNetworkRequest::ContentTypeHeader);
+ if (var.isValid()) {
+ QString str = var.toString();
+ int charsetIdx = str.indexOf(QLatin1String("charset="));
+ if (charsetIdx == -1) {
+ // No charset - append
+ if (!str.isEmpty()) str.append(QLatin1Char(';'));
+ str.append(QLatin1String("charset=UTF-8"));
+ } else {
+ charsetIdx += 8;
+ int n = 0;
+ int semiColon = str.indexOf(QLatin1Char(';'), charsetIdx);
+ if (semiColon == -1) {
+ n = str.length() - charsetIdx;
+ } else {
+ n = semiColon - charsetIdx;
+ }
+
+ str.replace(charsetIdx, n, QLatin1String("UTF-8"));
+ }
+ request.setHeader(QNetworkRequest::ContentTypeHeader, str);
+ } else {
+ request.setHeader(QNetworkRequest::ContentTypeHeader,
+ QLatin1String("text/plain;charset=UTF-8"));
+ }
+ }
+
+ if (xhrDump()) {
+ qWarning().nospace() << "XMLHttpRequest: " << qPrintable(m_method) << " " << qPrintable(url.toString());
+ if (!m_data.isEmpty()) {
+ qWarning().nospace() << " "
+ << qPrintable(QString::fromUtf8(m_data));
+ }
+ }
+
+ if (m_method == QLatin1String("GET"))
+ m_network = networkAccessManager()->get(request);
+ else if (m_method == QLatin1String("HEAD"))
+ m_network = networkAccessManager()->head(request);
+ else if (m_method == QLatin1String("POST"))
+ m_network = networkAccessManager()->post(request, m_data);
+ else if (m_method == QLatin1String("PUT"))
+ m_network = networkAccessManager()->put(request, m_data);
+ else if (m_method == QLatin1String("DELETE"))
+ m_network = networkAccessManager()->deleteResource(request);
+
+ QObject::connect(m_network, SIGNAL(downloadProgress(qint64,qint64)),
+ this, SLOT(downloadProgress(qint64)));
+ QObject::connect(m_network, SIGNAL(error(QNetworkReply::NetworkError)),
+ this, SLOT(error(QNetworkReply::NetworkError)));
+ QObject::connect(m_network, SIGNAL(finished()),
+ this, SLOT(finished()));
+}
+
+v8::Handle<v8::Value> QQmlXMLHttpRequest::send(v8::Handle<v8::Object> me, const QByteArray &data)
+{
+ m_errorFlag = false;
+ m_sendFlag = true;
+ m_redirectCount = 0;
+ m_data = data;
+
+ setMe(me);
+
+ requestFromUrl(m_url);
+
+ return v8::Undefined();
+}
+
+v8::Handle<v8::Value> QQmlXMLHttpRequest::abort(v8::Handle<v8::Object> me)
+{
+ destroyNetwork();
+ m_responseEntityBody = QByteArray();
+ m_errorFlag = true;
+ m_request = QNetworkRequest();
+
+ if (!(m_state == Unsent ||
+ (m_state == Opened && !m_sendFlag) ||
+ m_state == Done)) {
+
+ m_state = Done;
+ m_sendFlag = false;
+ dispatchCallback(me);
+ }
+
+ m_state = Unsent;
+
+ return v8::Undefined();
+}
+
+v8::Handle<v8::Object> QQmlXMLHttpRequest::getMe() const
+{
+ return m_me;
+}
+
+void QQmlXMLHttpRequest::setMe(v8::Handle<v8::Object> me)
+{
+ qPersistentDispose(m_me);
+
+ if (!me.IsEmpty())
+ m_me = qPersistentNew<v8::Object>(me);
+}
+
+void QQmlXMLHttpRequest::downloadProgress(qint64 bytes)
+{
+ v8::HandleScope handle_scope;
+
+ Q_UNUSED(bytes)
+ m_status =
+ m_network->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
+ m_statusText =
+ QString::fromUtf8(m_network->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toByteArray());
+
+ // ### We assume if this is called the headers are now available
+ if (m_state < HeadersReceived) {
+ m_state = HeadersReceived;
+ fillHeadersList ();
+ v8::TryCatch tc;
+ dispatchCallback(m_me);
+ if (tc.HasCaught()) printError(tc.Message());
+ }
+
+ bool wasEmpty = m_responseEntityBody.isEmpty();
+ m_responseEntityBody.append(m_network->readAll());
+ if (wasEmpty && !m_responseEntityBody.isEmpty()) {
+ m_state = Loading;
+ v8::TryCatch tc;
+ dispatchCallback(m_me);
+ if (tc.HasCaught()) printError(tc.Message());
+ }
+}
+
+static const char *errorToString(QNetworkReply::NetworkError error)
+{
+ int idx = QNetworkReply::staticMetaObject.indexOfEnumerator("NetworkError");
+ if (idx == -1) return "EnumLookupFailed";
+
+ QMetaEnum e = QNetworkReply::staticMetaObject.enumerator(idx);
+
+ const char *name = e.valueToKey(error);
+ if (!name) return "EnumLookupFailed";
+ else return name;
+}
+
+void QQmlXMLHttpRequest::error(QNetworkReply::NetworkError error)
+{
+ v8::HandleScope handle_scope;
+
+ Q_UNUSED(error)
+ m_status =
+ m_network->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
+ m_statusText =
+ QString::fromUtf8(m_network->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toByteArray());
+
+ m_responseEntityBody = QByteArray();
+
+ m_request = QNetworkRequest();
+ m_data.clear();
+ destroyNetwork();
+
+ if (xhrDump()) {
+ qWarning().nospace() << "XMLHttpRequest: ERROR " << qPrintable(m_url.toString());
+ qWarning().nospace() << " " << error << " " << errorToString(error) << " " << m_statusText;
+ }
+
+ if (error == QNetworkReply::ContentAccessDenied ||
+ error == QNetworkReply::ContentOperationNotPermittedError ||
+ error == QNetworkReply::ContentNotFoundError ||
+ error == QNetworkReply::AuthenticationRequiredError ||
+ error == QNetworkReply::ContentReSendError ||
+ error == QNetworkReply::UnknownContentError) {
+ m_state = Loading;
+ v8::TryCatch tc;
+ dispatchCallback(m_me);
+ if (tc.HasCaught()) printError(tc.Message());
+ } else {
+ m_errorFlag = true;
+ }
+
+ m_state = Done;
+
+ v8::TryCatch tc;
+ dispatchCallback(m_me);
+ if (tc.HasCaught()) printError(tc.Message());
+}
+
+#define XMLHTTPREQUEST_MAXIMUM_REDIRECT_RECURSION 15
+void QQmlXMLHttpRequest::finished()
+{
+ v8::HandleScope handle_scope;
+
+ m_redirectCount++;
+ if (m_redirectCount < XMLHTTPREQUEST_MAXIMUM_REDIRECT_RECURSION) {
+ QVariant redirect = m_network->attribute(QNetworkRequest::RedirectionTargetAttribute);
+ if (redirect.isValid()) {
+ QUrl url = m_network->url().resolved(redirect.toUrl());
+ destroyNetwork();
+ requestFromUrl(url);
+ return;
+ }
+ }
+
+ m_status =
+ m_network->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
+ m_statusText =
+ QString::fromUtf8(m_network->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toByteArray());
+
+ if (m_state < HeadersReceived) {
+ m_state = HeadersReceived;
+ fillHeadersList ();
+ v8::TryCatch tc;
+ dispatchCallback(m_me);
+ if (tc.HasCaught()) printError(tc.Message());
+ }
+ m_responseEntityBody.append(m_network->readAll());
+ readEncoding();
+
+ if (xhrDump()) {
+ qWarning().nospace() << "XMLHttpRequest: RESPONSE " << qPrintable(m_url.toString());
+ if (!m_responseEntityBody.isEmpty()) {
+ qWarning().nospace() << " "
+ << qPrintable(QString::fromUtf8(m_responseEntityBody));
+ }
+ }
+
+
+ m_data.clear();
+ destroyNetwork();
+ if (m_state < Loading) {
+ m_state = Loading;
+ v8::TryCatch tc;
+ dispatchCallback(m_me);
+ if (tc.HasCaught()) printError(tc.Message());
+ }
+ m_state = Done;
+
+ v8::TryCatch tc;
+ dispatchCallback(m_me);
+ if (tc.HasCaught()) printError(tc.Message());
+
+ setMe(v8::Handle<v8::Object>());
+}
+
+
+void QQmlXMLHttpRequest::readEncoding()
+{
+ foreach (const HeaderPair &header, m_headersList) {
+ if (header.first == "content-type") {
+ int separatorIdx = header.second.indexOf(';');
+ if (separatorIdx == -1) {
+ m_mime == header.second;
+ } else {
+ m_mime = header.second.mid(0, separatorIdx);
+ int charsetIdx = header.second.indexOf("charset=");
+ if (charsetIdx != -1) {
+ charsetIdx += 8;
+ separatorIdx = header.second.indexOf(';', charsetIdx);
+ m_charset = header.second.mid(charsetIdx, separatorIdx >= 0 ? separatorIdx : header.second.length());
+ }
+ }
+ break;
+ }
+ }
+
+ if (m_mime.isEmpty() || m_mime == "text/xml" || m_mime == "application/xml" || m_mime.endsWith("+xml"))
+ m_gotXml = true;
+}
+
+bool QQmlXMLHttpRequest::receivedXml() const
+{
+ return m_gotXml;
+}
+
+
+#ifndef QT_NO_TEXTCODEC
+QTextCodec* QQmlXMLHttpRequest::findTextCodec() const
+{
+ QTextCodec *codec = 0;
+
+ if (!m_charset.isEmpty())
+ codec = QTextCodec::codecForName(m_charset);
+
+ if (!codec && m_gotXml) {
+ QXmlStreamReader reader(m_responseEntityBody);
+ reader.readNext();
+ codec = QTextCodec::codecForName(reader.documentEncoding().toString().toUtf8());
+ }
+
+ if (!codec && m_mime == "text/html")
+ codec = QTextCodec::codecForHtml(m_responseEntityBody, 0);
+
+ if (!codec)
+ codec = QTextCodec::codecForUtfText(m_responseEntityBody, 0);
+
+ if (!codec)
+ codec = QTextCodec::codecForName("UTF-8");
+ return codec;
+}
+#endif
+
+
+QString QQmlXMLHttpRequest::responseBody()
+{
+#ifndef QT_NO_TEXTCODEC
+ if (!m_textCodec)
+ m_textCodec = findTextCodec();
+ if (m_textCodec)
+ return m_textCodec->toUnicode(m_responseEntityBody);
+#endif
+
+ return QString::fromUtf8(m_responseEntityBody);
+}
+
+const QByteArray &QQmlXMLHttpRequest::rawResponseBody() const
+{
+ return m_responseEntityBody;
+}
+
+// Requires a TryCatch scope
+void QQmlXMLHttpRequest::dispatchCallback(v8::Handle<v8::Object> me)
+{
+ v8::Local<v8::Value> callback = me->Get(v8::String::New("onreadystatechange"));
+ if (callback->IsFunction()) {
+ v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(callback);
+
+ f->Call(me, 0, 0);
+ }
+}
+
+// Must have a handle scope
+void QQmlXMLHttpRequest::printError(v8::Handle<v8::Message> message)
+{
+ v8::Context::Scope scope(engine->context());
+
+ QQmlError error;
+ QQmlExpressionPrivate::exceptionToError(message, error);
+ QQmlEnginePrivate::warning(QQmlEnginePrivate::get(engine->engine()), error);
+}
+
+void QQmlXMLHttpRequest::destroyNetwork()
+{
+ if (m_network) {
+ m_network->disconnect();
+ m_network->deleteLater();
+ m_network = 0;
+ }
+}
+
+// XMLHttpRequest methods
+static v8::Handle<v8::Value> qmlxmlhttprequest_open(const v8::Arguments &args)
+{
+ QQmlXMLHttpRequest *r = v8_resource_cast<QQmlXMLHttpRequest>(args.This());
+ if (!r)
+ V8THROW_REFERENCE("Not an XMLHttpRequest object");
+
+ if (args.Length() < 2 || args.Length() > 5)
+ V8THROW_DOM(DOMEXCEPTION_SYNTAX_ERR, "Incorrect argument count");
+
+ QV8Engine *engine = r->engine;
+
+ // Argument 0 - Method
+ QString method = engine->toString(args[0]).toUpper();
+ if (method != QLatin1String("GET") &&
+ method != QLatin1String("PUT") &&
+ method != QLatin1String("HEAD") &&
+ method != QLatin1String("POST") &&
+ method != QLatin1String("DELETE"))
+ V8THROW_DOM(DOMEXCEPTION_SYNTAX_ERR, "Unsupported HTTP method type");
+
+ // Argument 1 - URL
+ QUrl url = QUrl::fromEncoded(engine->toString(args[1]).toUtf8());
+
+ if (url.isRelative())
+ url = engine->callingContext()->resolvedUrl(url);
+
+ // Argument 2 - async (optional)
+ if (args.Length() > 2 && !args[2]->BooleanValue())
+ V8THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "Synchronous XMLHttpRequest calls are not supported");
+
+ // Argument 3/4 - user/pass (optional)
+ QString username, password;
+ if (args.Length() > 3)
+ username = engine->toString(args[3]);
+ if (args.Length() > 4)
+ password = engine->toString(args[4]);
+
+ // Clear the fragment (if any)
+ url.setFragment(QString());
+
+ // Set username/password
+ if (!username.isNull()) url.setUserName(username);
+ if (!password.isNull()) url.setPassword(password);
+
+ return r->open(args.This(), method, url);
+}
+
+static v8::Handle<v8::Value> qmlxmlhttprequest_setRequestHeader(const v8::Arguments &args)
+{
+ QQmlXMLHttpRequest *r = v8_resource_cast<QQmlXMLHttpRequest>(args.This());
+ if (!r)
+ V8THROW_REFERENCE("Not an XMLHttpRequest object");
+
+ if (args.Length() != 2)
+ V8THROW_DOM(DOMEXCEPTION_SYNTAX_ERR, "Incorrect argument count");
+
+ if (r->readyState() != QQmlXMLHttpRequest::Opened || r->sendFlag())
+ V8THROW_DOM(DOMEXCEPTION_INVALID_STATE_ERR, "Invalid state");
+
+ QV8Engine *engine = r->engine;
+
+ QString name = engine->toString(args[0]);
+ QString value = engine->toString(args[1]);
+
+ // ### Check that name and value are well formed
+
+ QString nameUpper = name.toUpper();
+ if (nameUpper == QLatin1String("ACCEPT-CHARSET") ||
+ nameUpper == QLatin1String("ACCEPT-ENCODING") ||
+ nameUpper == QLatin1String("CONNECTION") ||
+ nameUpper == QLatin1String("CONTENT-LENGTH") ||
+ nameUpper == QLatin1String("COOKIE") ||
+ nameUpper == QLatin1String("COOKIE2") ||
+ nameUpper == QLatin1String("CONTENT-TRANSFER-ENCODING") ||
+ nameUpper == QLatin1String("DATE") ||
+ nameUpper == QLatin1String("EXPECT") ||
+ nameUpper == QLatin1String("HOST") ||
+ nameUpper == QLatin1String("KEEP-ALIVE") ||
+ nameUpper == QLatin1String("REFERER") ||
+ nameUpper == QLatin1String("TE") ||
+ nameUpper == QLatin1String("TRAILER") ||
+ nameUpper == QLatin1String("TRANSFER-ENCODING") ||
+ nameUpper == QLatin1String("UPGRADE") ||
+ nameUpper == QLatin1String("USER-AGENT") ||
+ nameUpper == QLatin1String("VIA") ||
+ nameUpper.startsWith(QLatin1String("PROXY-")) ||
+ nameUpper.startsWith(QLatin1String("SEC-")))
+ return v8::Undefined();
+
+ r->addHeader(name, value);
+
+ return v8::Undefined();
+}
+
+static v8::Handle<v8::Value> qmlxmlhttprequest_send(const v8::Arguments &args)
+{
+ QQmlXMLHttpRequest *r = v8_resource_cast<QQmlXMLHttpRequest>(args.This());
+ if (!r)
+ V8THROW_REFERENCE("Not an XMLHttpRequest object");
+
+ QV8Engine *engine = r->engine;
+
+ if (r->readyState() != QQmlXMLHttpRequest::Opened ||
+ r->sendFlag())
+ V8THROW_DOM(DOMEXCEPTION_INVALID_STATE_ERR, "Invalid state");
+
+ QByteArray data;
+ if (args.Length() > 0)
+ data = engine->toString(args[0]).toUtf8();
+
+ return r->send(args.This(), data);
+}
+
+static v8::Handle<v8::Value> qmlxmlhttprequest_abort(const v8::Arguments &args)
+{
+ QQmlXMLHttpRequest *r = v8_resource_cast<QQmlXMLHttpRequest>(args.This());
+ if (!r)
+ V8THROW_REFERENCE("Not an XMLHttpRequest object");
+
+ return r->abort(args.This());
+}
+
+static v8::Handle<v8::Value> qmlxmlhttprequest_getResponseHeader(const v8::Arguments &args)
+{
+ QQmlXMLHttpRequest *r = v8_resource_cast<QQmlXMLHttpRequest>(args.This());
+ if (!r)
+ V8THROW_REFERENCE("Not an XMLHttpRequest object");
+
+ QV8Engine *engine = r->engine;
+
+ if (args.Length() != 1)
+ V8THROW_DOM(DOMEXCEPTION_SYNTAX_ERR, "Incorrect argument count");
+
+ if (r->readyState() != QQmlXMLHttpRequest::Loading &&
+ r->readyState() != QQmlXMLHttpRequest::Done &&
+ r->readyState() != QQmlXMLHttpRequest::HeadersReceived)
+ V8THROW_DOM(DOMEXCEPTION_INVALID_STATE_ERR, "Invalid state");
+
+ return engine->toString(r->header(engine->toString(args[0])));
+}
+
+static v8::Handle<v8::Value> qmlxmlhttprequest_getAllResponseHeaders(const v8::Arguments &args)
+{
+ QQmlXMLHttpRequest *r = v8_resource_cast<QQmlXMLHttpRequest>(args.This());
+ if (!r)
+ V8THROW_REFERENCE("Not an XMLHttpRequest object");
+
+ QV8Engine *engine = r->engine;
+
+ if (args.Length() != 0)
+ V8THROW_DOM(DOMEXCEPTION_SYNTAX_ERR, "Incorrect argument count");
+
+ if (r->readyState() != QQmlXMLHttpRequest::Loading &&
+ r->readyState() != QQmlXMLHttpRequest::Done &&
+ r->readyState() != QQmlXMLHttpRequest::HeadersReceived)
+ V8THROW_DOM(DOMEXCEPTION_INVALID_STATE_ERR, "Invalid state");
+
+ return engine->toString(r->headers());
+}
+
+// XMLHttpRequest properties
+static v8::Handle<v8::Value> qmlxmlhttprequest_readyState(v8::Local<v8::String> /* property */,
+ const v8::AccessorInfo& info)
+{
+ QQmlXMLHttpRequest *r = v8_resource_cast<QQmlXMLHttpRequest>(info.This());
+ if (!r)
+ V8THROW_REFERENCE("Not an XMLHttpRequest object");
+
+ return v8::Integer::NewFromUnsigned(r->readyState());
+}
+
+static v8::Handle<v8::Value> qmlxmlhttprequest_status(v8::Local<v8::String> /* property */,
+ const v8::AccessorInfo& info)
+{
+ QQmlXMLHttpRequest *r = v8_resource_cast<QQmlXMLHttpRequest>(info.This());
+ if (!r)
+ V8THROW_REFERENCE("Not an XMLHttpRequest object");
+
+ if (r->readyState() == QQmlXMLHttpRequest::Unsent ||
+ r->readyState() == QQmlXMLHttpRequest::Opened)
+ V8THROW_DOM(DOMEXCEPTION_INVALID_STATE_ERR, "Invalid state");
+
+ if (r->errorFlag())
+ return v8::Integer::New(0);
+ else
+ return v8::Integer::New(r->replyStatus());
+}
+
+static v8::Handle<v8::Value> qmlxmlhttprequest_statusText(v8::Local<v8::String> /* property */,
+ const v8::AccessorInfo& info)
+{
+ QQmlXMLHttpRequest *r = v8_resource_cast<QQmlXMLHttpRequest>(info.This());
+ if (!r)
+ V8THROW_REFERENCE("Not an XMLHttpRequest object");
+
+ QV8Engine *engine = r->engine;
+
+ if (r->readyState() == QQmlXMLHttpRequest::Unsent ||
+ r->readyState() == QQmlXMLHttpRequest::Opened)
+ V8THROW_DOM(DOMEXCEPTION_INVALID_STATE_ERR, "Invalid state");
+
+ if (r->errorFlag())
+ return engine->toString(QString());
+ else
+ return engine->toString(r->replyStatusText());
+}
+
+static v8::Handle<v8::Value> qmlxmlhttprequest_responseText(v8::Local<v8::String> /* property */,
+ const v8::AccessorInfo& info)
+{
+ QQmlXMLHttpRequest *r = v8_resource_cast<QQmlXMLHttpRequest>(info.This());
+ if (!r)
+ V8THROW_REFERENCE("Not an XMLHttpRequest object");
+
+ QV8Engine *engine = r->engine;
+
+ if (r->readyState() != QQmlXMLHttpRequest::Loading &&
+ r->readyState() != QQmlXMLHttpRequest::Done)
+ return engine->toString(QString());
+ else
+ return engine->toString(r->responseBody());
+}
+
+static v8::Handle<v8::Value> qmlxmlhttprequest_responseXML(v8::Local<v8::String> /* property */,
+ const v8::AccessorInfo& info)
+{
+ QQmlXMLHttpRequest *r = v8_resource_cast<QQmlXMLHttpRequest>(info.This());
+ if (!r)
+ V8THROW_REFERENCE("Not an XMLHttpRequest object");
+
+ if (!r->receivedXml() ||
+ (r->readyState() != QQmlXMLHttpRequest::Loading &&
+ r->readyState() != QQmlXMLHttpRequest::Done)) {
+ return v8::Null();
+ } else {
+ return Document::load(r->engine, r->rawResponseBody());
+ }
+}
+
+static v8::Handle<v8::Value> qmlxmlhttprequest_new(const v8::Arguments &args)
+{
+ if (args.IsConstructCall()) {
+ QV8Engine *engine = V8ENGINE();
+ QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine->engine());
+ Q_UNUSED(ep)
+ QQmlXMLHttpRequest *r = new QQmlXMLHttpRequest(engine, engine->networkAccessManager());
+ args.This()->SetExternalResource(r);
+
+ return args.This();
+ } else {
+ return v8::Undefined();
+ }
+}
+
+#define NEWFUNCTION(function) v8::FunctionTemplate::New(function)->GetFunction()
+
+void qt_rem_qmlxmlhttprequest(QV8Engine * /* engine */, void *d)
+{
+ QQmlXMLHttpRequestData *data = (QQmlXMLHttpRequestData *)d;
+ delete data;
+}
+
+void *qt_add_qmlxmlhttprequest(QV8Engine *engine)
+{
+ v8::PropertyAttribute attributes = (v8::PropertyAttribute)(v8::ReadOnly | v8::DontEnum | v8::DontDelete);
+
+ // XMLHttpRequest
+ v8::Local<v8::FunctionTemplate> xmlhttprequest = v8::FunctionTemplate::New(qmlxmlhttprequest_new,
+ v8::External::Wrap(engine));
+ xmlhttprequest->InstanceTemplate()->SetHasExternalResource(true);
+
+ // Methods
+ xmlhttprequest->PrototypeTemplate()->Set(v8::String::New("open"), NEWFUNCTION(qmlxmlhttprequest_open), attributes);
+ xmlhttprequest->PrototypeTemplate()->Set(v8::String::New("setRequestHeader"), NEWFUNCTION(qmlxmlhttprequest_setRequestHeader), attributes);
+ xmlhttprequest->PrototypeTemplate()->Set(v8::String::New("send"), NEWFUNCTION(qmlxmlhttprequest_send), attributes);
+ xmlhttprequest->PrototypeTemplate()->Set(v8::String::New("abort"), NEWFUNCTION(qmlxmlhttprequest_abort), attributes);
+ xmlhttprequest->PrototypeTemplate()->Set(v8::String::New("getResponseHeader"), NEWFUNCTION(qmlxmlhttprequest_getResponseHeader), attributes);
+ xmlhttprequest->PrototypeTemplate()->Set(v8::String::New("getAllResponseHeaders"), NEWFUNCTION(qmlxmlhttprequest_getAllResponseHeaders), attributes);
+
+ // Read-only properties
+ xmlhttprequest->PrototypeTemplate()->SetAccessor(v8::String::New("readyState"), qmlxmlhttprequest_readyState, 0, v8::Handle<v8::Value>(), v8::DEFAULT, attributes);
+ xmlhttprequest->PrototypeTemplate()->SetAccessor(v8::String::New("status"),qmlxmlhttprequest_status, 0, v8::Handle<v8::Value>(), v8::DEFAULT, attributes);
+ xmlhttprequest->PrototypeTemplate()->SetAccessor(v8::String::New("statusText"),qmlxmlhttprequest_statusText, 0, v8::Handle<v8::Value>(), v8::DEFAULT, attributes);
+ xmlhttprequest->PrototypeTemplate()->SetAccessor(v8::String::New("responseText"),qmlxmlhttprequest_responseText, 0, v8::Handle<v8::Value>(), v8::DEFAULT, attributes);
+ xmlhttprequest->PrototypeTemplate()->SetAccessor(v8::String::New("responseXML"),qmlxmlhttprequest_responseXML, 0, v8::Handle<v8::Value>(), v8::DEFAULT, attributes);
+
+ // State values
+ xmlhttprequest->PrototypeTemplate()->Set(v8::String::New("UNSENT"), v8::Integer::New(0), attributes);
+ xmlhttprequest->PrototypeTemplate()->Set(v8::String::New("OPENED"), v8::Integer::New(1), attributes);
+ xmlhttprequest->PrototypeTemplate()->Set(v8::String::New("HEADERS_RECEIVED"), v8::Integer::New(2), attributes);
+ xmlhttprequest->PrototypeTemplate()->Set(v8::String::New("LOADING"), v8::Integer::New(3), attributes);
+ xmlhttprequest->PrototypeTemplate()->Set(v8::String::New("DONE"), v8::Integer::New(4), attributes);
+
+ // Constructor
+ xmlhttprequest->Set(v8::String::New("UNSENT"), v8::Integer::New(0), attributes);
+ xmlhttprequest->Set(v8::String::New("OPENED"), v8::Integer::New(1), attributes);
+ xmlhttprequest->Set(v8::String::New("HEADERS_RECEIVED"), v8::Integer::New(2), attributes);
+ xmlhttprequest->Set(v8::String::New("LOADING"), v8::Integer::New(3), attributes);
+ xmlhttprequest->Set(v8::String::New("DONE"), v8::Integer::New(4), attributes);
+ engine->global()->Set(v8::String::New("XMLHttpRequest"), xmlhttprequest->GetFunction());
+
+ QQmlXMLHttpRequestData *data = new QQmlXMLHttpRequestData;
+ return data;
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_XMLSTREAMREADER
+
+#include <qqmlxmlhttprequest.moc>
diff --git a/src/qml/qml/qqmlxmlhttprequest_p.h b/src/qml/qml/qqmlxmlhttprequest_p.h
new file mode 100644
index 0000000000..2cfdf6a140
--- /dev/null
+++ b/src/qml/qml/qqmlxmlhttprequest_p.h
@@ -0,0 +1,73 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLXMLHTTPREQUEST_P_H
+#define QQMLXMLHTTPREQUEST_P_H
+
+#include <QtQml/qjsengine.h>
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qglobal.h>
+
+#ifndef QT_NO_XMLSTREAMREADER
+
+QT_BEGIN_NAMESPACE
+
+class QV8Engine;
+
+void *qt_add_qmlxmlhttprequest(QV8Engine *engine);
+void qt_rem_qmlxmlhttprequest(QV8Engine *engine, void *);
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_XMLSTREAMREADER
+
+#endif // QQMLXMLHTTPREQUEST_P_H
+
diff --git a/src/qml/qml/qquickapplication.cpp b/src/qml/qml/qquickapplication.cpp
new file mode 100644
index 0000000000..198a917cb8
--- /dev/null
+++ b/src/qml/qml/qquickapplication.cpp
@@ -0,0 +1,124 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickapplication_p.h"
+#include <private/qobject_p.h>
+#include <QtGui/QGuiApplication>
+#include <QtGui/QInputMethod>
+#include <QtCore/QDebug>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickApplicationPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QQuickApplication)
+public:
+ QQuickApplicationPrivate() : active(QGuiApplication::activeWindow() != 0),
+ layoutDirection(QGuiApplication::layoutDirection()) {}
+ bool active;
+ Qt::LayoutDirection layoutDirection;
+};
+
+/*
+ This object and its properties are documented as part of the Qt object,
+ in qdeclarativengine.cpp
+*/
+
+QQuickApplication::QQuickApplication(QObject *parent) : QObject(*new QQuickApplicationPrivate(), parent)
+{
+ if (qApp)
+ qApp->installEventFilter(this);
+}
+
+QQuickApplication::~QQuickApplication()
+{
+}
+
+bool QQuickApplication::active() const
+{
+ Q_D(const QQuickApplication);
+ return d->active;
+}
+
+Qt::LayoutDirection QQuickApplication::layoutDirection() const
+{
+ Q_D(const QQuickApplication);
+ return d->layoutDirection;
+}
+
+QObject *QQuickApplication::inputPanel() const
+{
+ static bool warned = false;
+ if (!warned) {
+ qWarning() << "Qt.application.inputPanel is deprecated, use Qt.inputMethod instead";
+ warned = true;
+ }
+ return qApp ? qApp->inputMethod() : 0;
+}
+
+bool QQuickApplication::eventFilter(QObject *obj, QEvent *event)
+{
+ Q_UNUSED(obj)
+ Q_D(QQuickApplication);
+ if (event->type() == QEvent::ApplicationActivate
+ || event->type() == QEvent::ApplicationDeactivate) {
+ bool active = d->active;
+ if (event->type() == QEvent::ApplicationActivate)
+ active = true;
+ else if (event->type() == QEvent::ApplicationDeactivate)
+ active = false;
+
+ if (d->active != active) {
+ d->active = active;
+ emit activeChanged();
+ }
+ }
+ if (event->type() == QEvent::LayoutDirectionChange) {
+ Qt::LayoutDirection direction = QGuiApplication::layoutDirection();
+ if (d->layoutDirection != direction) {
+ d->layoutDirection = direction;
+ emit layoutDirectionChanged();
+ }
+ }
+ return false;
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/qquickapplication_p.h b/src/qml/qml/qquickapplication_p.h
new file mode 100644
index 0000000000..66198948ac
--- /dev/null
+++ b/src/qml/qml/qquickapplication_p.h
@@ -0,0 +1,87 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKAPPLICATION_P_H
+#define QQUICKAPPLICATION_P_H
+
+#include <QtCore/QObject>
+#include <qqml.h>
+#include <private/qtqmlglobal_p.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+
+class QQuickApplicationPrivate;
+class Q_QML_PRIVATE_EXPORT QQuickApplication : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(bool active READ active NOTIFY activeChanged)
+ Q_PROPERTY(Qt::LayoutDirection layoutDirection READ layoutDirection NOTIFY layoutDirectionChanged)
+ Q_PROPERTY(QObject *inputPanel READ inputPanel CONSTANT)
+
+public:
+ explicit QQuickApplication(QObject *parent = 0);
+ virtual ~QQuickApplication();
+ bool active() const;
+ Qt::LayoutDirection layoutDirection() const;
+ QT_DEPRECATED QObject *inputPanel() const;
+
+protected:
+ bool eventFilter(QObject *obj, QEvent *event);
+
+Q_SIGNALS:
+ void activeChanged();
+ void layoutDirectionChanged();
+
+private:
+ Q_DISABLE_COPY(QQuickApplication)
+ Q_DECLARE_PRIVATE(QQuickApplication)
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickApplication)
+
+QT_END_HEADER
+
+#endif // QQUICKAPPLICATION_P_H
diff --git a/src/qml/qml/qquicklistmodel.cpp b/src/qml/qml/qquicklistmodel.cpp
new file mode 100644
index 0000000000..30c4f5d1d1
--- /dev/null
+++ b/src/qml/qml/qquicklistmodel.cpp
@@ -0,0 +1,2467 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquicklistmodel_p_p.h"
+#include "qquicklistmodelworkeragent_p.h"
+#include "qqmlopenmetaobject_p.h"
+#include <private/qqmljsast_p.h>
+#include <private/qqmljsengine_p.h>
+
+#include <private/qqmlcustomparser_p.h>
+#include <private/qqmlscript_p.h>
+#include <private/qqmlengine_p.h>
+#include <qqmlcontext.h>
+#include <qqmlinfo.h>
+
+#include <QtCore/qdebug.h>
+#include <QtCore/qstack.h>
+#include <QXmlStreamReader>
+
+Q_DECLARE_METATYPE(QListModelInterface *)
+
+QT_BEGIN_NAMESPACE
+
+// Set to 1024 as a debugging aid - easier to distinguish uids from indices of elements/models.
+enum { MIN_LISTMODEL_UID = 1024 };
+
+static QAtomicInt uidCounter(MIN_LISTMODEL_UID);
+
+template <typename T>
+static bool isMemoryUsed(const char *mem)
+{
+ for (size_t i=0 ; i < sizeof(T) ; ++i) {
+ if (mem[i] != 0)
+ return true;
+ }
+
+ return false;
+}
+
+static QString roleTypeName(ListLayout::Role::DataType t)
+{
+ QString result;
+ const char *roleTypeNames[] = { "String", "Number", "Bool", "List", "QObject", "VariantMap" };
+
+ if (t > ListLayout::Role::Invalid && t < ListLayout::Role::MaxDataType)
+ result = QString::fromLatin1(roleTypeNames[t]);
+
+ return result;
+}
+
+const ListLayout::Role &ListLayout::getRoleOrCreate(const QString &key, Role::DataType type)
+{
+ QStringHash<Role *>::Node *node = roleHash.findNode(key);
+ if (node) {
+ const Role &r = *node->value;
+ if (type != r.type)
+ qmlInfo(0) << QString::fromLatin1("Can't assign to existing role '%1' of different type [%2 -> %3]").arg(r.name).arg(roleTypeName(type)).arg(roleTypeName(r.type));
+ return r;
+ }
+
+ return createRole(key, type);
+}
+
+const ListLayout::Role &ListLayout::getRoleOrCreate(v8::Handle<v8::String> key, Role::DataType type)
+{
+ QHashedV8String hashedKey(key);
+ QStringHash<Role *>::Node *node = roleHash.findNode(hashedKey);
+ if (node) {
+ const Role &r = *node->value;
+ if (type != r.type)
+ qmlInfo(0) << QString::fromLatin1("Can't assign to existing role '%1' of different type [%2 -> %3]").arg(r.name).arg(roleTypeName(type)).arg(roleTypeName(r.type));
+ return r;
+ }
+
+ QString qkey;
+ qkey.resize(key->Length());
+ key->Write(reinterpret_cast<uint16_t*>(qkey.data()));
+
+ return createRole(qkey, type);
+}
+
+const ListLayout::Role &ListLayout::createRole(const QString &key, ListLayout::Role::DataType type)
+{
+ const int dataSizes[] = { sizeof(QString), sizeof(double), sizeof(bool), sizeof(ListModel *), sizeof(QQmlGuard<QObject>), sizeof(QVariantMap) };
+ const int dataAlignments[] = { sizeof(QString), sizeof(double), sizeof(bool), sizeof(ListModel *), sizeof(QObject *), sizeof(QVariantMap) };
+
+ Role *r = new Role;
+ r->name = key;
+ r->type = type;
+
+ if (type == Role::List) {
+ r->subLayout = new ListLayout;
+ } else {
+ r->subLayout = 0;
+ }
+
+ int dataSize = dataSizes[type];
+ int dataAlignment = dataAlignments[type];
+
+ int dataOffset = (currentBlockOffset + dataAlignment-1) & ~(dataAlignment-1);
+ if (dataOffset + dataSize > ListElement::BLOCK_SIZE) {
+ r->blockIndex = ++currentBlock;
+ r->blockOffset = 0;
+ currentBlockOffset = dataSize;
+ } else {
+ r->blockIndex = currentBlock;
+ r->blockOffset = dataOffset;
+ currentBlockOffset = dataOffset + dataSize;
+ }
+
+ int roleIndex = roles.count();
+ r->index = roleIndex;
+
+ roles.append(r);
+ roleHash.insert(key, r);
+
+ return *r;
+}
+
+ListLayout::ListLayout(const ListLayout *other) : currentBlock(0), currentBlockOffset(0)
+{
+ for (int i=0 ; i < other->roles.count() ; ++i) {
+ Role *role = new Role(other->roles[i]);
+ roles.append(role);
+ roleHash.insert(role->name, role);
+ }
+ currentBlockOffset = other->currentBlockOffset;
+ currentBlock = other->currentBlock;
+}
+
+ListLayout::~ListLayout()
+{
+ for (int i=0 ; i < roles.count() ; ++i) {
+ delete roles[i];
+ }
+}
+
+void ListLayout::sync(ListLayout *src, ListLayout *target)
+{
+ int roleOffset = target->roles.count();
+ int newRoleCount = src->roles.count() - roleOffset;
+
+ for (int i=0 ; i < newRoleCount ; ++i) {
+ Role *role = new Role(src->roles[roleOffset + i]);
+ target->roles.append(role);
+ target->roleHash.insert(role->name, role);
+ }
+
+ target->currentBlockOffset = src->currentBlockOffset;
+ target->currentBlock = src->currentBlock;
+}
+
+ListLayout::Role::Role(const Role *other)
+{
+ name = other->name;
+ type = other->type;
+ blockIndex = other->blockIndex;
+ blockOffset = other->blockOffset;
+ index = other->index;
+ if (other->subLayout)
+ subLayout = new ListLayout(other->subLayout);
+ else
+ subLayout = 0;
+}
+
+ListLayout::Role::~Role()
+{
+ delete subLayout;
+}
+
+const ListLayout::Role *ListLayout::getRoleOrCreate(const QString &key, const QVariant &data)
+{
+ Role::DataType type;
+
+ switch (data.type()) {
+ case QVariant::Double: type = Role::Number; break;
+ case QVariant::Int: type = Role::Number; break;
+ case QVariant::UserType: type = Role::List; break;
+ case QVariant::Bool: type = Role::Bool; break;
+ case QVariant::String: type = Role::String; break;
+ case QVariant::Map: type = Role::VariantMap; break;
+ default: type = Role::Invalid; break;
+ }
+
+ if (type == Role::Invalid) {
+ qmlInfo(0) << "Can't create role for unsupported data type";
+ return 0;
+ }
+
+ return &getRoleOrCreate(key, type);
+}
+
+const ListLayout::Role *ListLayout::getExistingRole(const QString &key)
+{
+ Role *r = 0;
+ QStringHash<Role *>::Node *node = roleHash.findNode(key);
+ if (node)
+ r = node->value;
+ return r;
+}
+
+const ListLayout::Role *ListLayout::getExistingRole(v8::Handle<v8::String> key)
+{
+ Role *r = 0;
+ QHashedV8String hashedKey(key);
+ QStringHash<Role *>::Node *node = roleHash.findNode(hashedKey);
+ if (node)
+ r = node->value;
+ return r;
+}
+
+ModelObject *ListModel::getOrCreateModelObject(QQuickListModel *model, int elementIndex)
+{
+ ListElement *e = elements[elementIndex];
+ if (e->m_objectCache == 0) {
+ e->m_objectCache = new ModelObject(model, elementIndex);
+ }
+ return e->m_objectCache;
+}
+
+void ListModel::sync(ListModel *src, ListModel *target, QHash<int, ListModel *> *targetModelHash)
+{
+ // Sanity check
+ target->m_uid = src->m_uid;
+ if (targetModelHash)
+ targetModelHash->insert(target->m_uid, target);
+
+ // Build hash of elements <-> uid for each of the lists
+ QHash<int, ElementSync> elementHash;
+ for (int i=0 ; i < target->elements.count() ; ++i) {
+ ListElement *e = target->elements.at(i);
+ int uid = e->getUid();
+ ElementSync sync;
+ sync.target = e;
+ elementHash.insert(uid, sync);
+ }
+ for (int i=0 ; i < src->elements.count() ; ++i) {
+ ListElement *e = src->elements.at(i);
+ int uid = e->getUid();
+
+ QHash<int, ElementSync>::iterator it = elementHash.find(uid);
+ if (it == elementHash.end()) {
+ ElementSync sync;
+ sync.src = e;
+ elementHash.insert(uid, sync);
+ } else {
+ ElementSync &sync = it.value();
+ sync.src = e;
+ }
+ }
+
+ // Get list of elements that are in the target but no longer in the source. These get deleted first.
+ QHash<int, ElementSync>::iterator it = elementHash.begin();
+ QHash<int, ElementSync>::iterator end = elementHash.end();
+ while (it != end) {
+ const ElementSync &s = it.value();
+ if (s.src == 0) {
+ s.target->destroy(target->m_layout);
+ target->elements.removeOne(s.target);
+ delete s.target;
+ }
+ ++it;
+ }
+
+ // Sync the layouts
+ ListLayout::sync(src->m_layout, target->m_layout);
+
+ // Clear the target list, and append in correct order from the source
+ target->elements.clear();
+ for (int i=0 ; i < src->elements.count() ; ++i) {
+ ListElement *srcElement = src->elements.at(i);
+ it = elementHash.find(srcElement->getUid());
+ const ElementSync &s = it.value();
+ ListElement *targetElement = s.target;
+ if (targetElement == 0) {
+ targetElement = new ListElement(srcElement->getUid());
+ }
+ ListElement::sync(srcElement, src->m_layout, targetElement, target->m_layout, targetModelHash);
+ target->elements.append(targetElement);
+ }
+
+ target->updateCacheIndices();
+
+ // Update values stored in target meta objects
+ for (int i=0 ; i < target->elements.count() ; ++i) {
+ ListElement *e = target->elements[i];
+ if (e->m_objectCache)
+ e->m_objectCache->updateValues();
+ }
+}
+
+ListModel::ListModel(ListLayout *layout, QQuickListModel *modelCache, int uid) : m_layout(layout), m_modelCache(modelCache)
+{
+ if (uid == -1)
+ uid = uidCounter.fetchAndAddOrdered(1);
+ m_uid = uid;
+}
+
+void ListModel::destroy()
+{
+ clear();
+ m_uid = -1;
+ m_layout = 0;
+ if (m_modelCache && m_modelCache->m_primary == false)
+ delete m_modelCache;
+ m_modelCache = 0;
+}
+
+int ListModel::appendElement()
+{
+ int elementIndex = elements.count();
+ newElement(elementIndex);
+ return elementIndex;
+}
+
+void ListModel::insertElement(int index)
+{
+ newElement(index);
+ updateCacheIndices();
+}
+
+void ListModel::move(int from, int to, int n)
+{
+ if (from > to) {
+ // Only move forwards - flip if backwards moving
+ int tfrom = from;
+ int tto = to;
+ from = tto;
+ to = tto+n;
+ n = tfrom-tto;
+ }
+
+ QPODVector<ListElement *, 4> store;
+ for (int i=0 ; i < (to-from) ; ++i)
+ store.append(elements[from+n+i]);
+ for (int i=0 ; i < n ; ++i)
+ store.append(elements[from+i]);
+ for (int i=0 ; i < store.count() ; ++i)
+ elements[from+i] = store[i];
+
+ updateCacheIndices();
+}
+
+void ListModel::newElement(int index)
+{
+ ListElement *e = new ListElement;
+ elements.insert(index, e);
+}
+
+void ListModel::updateCacheIndices()
+{
+ for (int i=0 ; i < elements.count() ; ++i) {
+ ListElement *e = elements.at(i);
+ if (e->m_objectCache) {
+ e->m_objectCache->m_elementIndex = i;
+ }
+ }
+}
+
+QVariant ListModel::getProperty(int elementIndex, int roleIndex, const QQuickListModel *owner, QV8Engine *eng)
+{
+ ListElement *e = elements[elementIndex];
+ const ListLayout::Role &r = m_layout->getExistingRole(roleIndex);
+ return e->getProperty(r, owner, eng);
+}
+
+ListModel *ListModel::getListProperty(int elementIndex, const ListLayout::Role &role)
+{
+ ListElement *e = elements[elementIndex];
+ return e->getListProperty(role);
+}
+
+void ListModel::set(int elementIndex, v8::Handle<v8::Object> object, QList<int> *roles, QV8Engine *eng)
+{
+ ListElement *e = elements[elementIndex];
+
+ v8::Local<v8::Array> propertyNames = object->GetPropertyNames();
+ int propertyCount = propertyNames->Length();
+
+ for (int i=0 ; i < propertyCount ; ++i) {
+ v8::Local<v8::String> propertyName = propertyNames->Get(i)->ToString();
+ v8::Local<v8::Value> propertyValue = object->Get(propertyName);
+
+ // Check if this key exists yet
+ int roleIndex = -1;
+
+ // Add the value now
+ if (propertyValue->IsString()) {
+ const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::String);
+ v8::Handle<v8::String> jsString = propertyValue->ToString();
+ QString qstr;
+ qstr.resize(jsString->Length());
+ jsString->Write(reinterpret_cast<uint16_t*>(qstr.data()));
+ roleIndex = e->setStringProperty(r, qstr);
+ } else if (propertyValue->IsNumber()) {
+ const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::Number);
+ roleIndex = e->setDoubleProperty(r, propertyValue->NumberValue());
+ } else if (propertyValue->IsArray()) {
+ const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::List);
+ ListModel *subModel = new ListModel(r.subLayout, 0, -1);
+
+ v8::Handle<v8::Array> subArray = v8::Handle<v8::Array>::Cast(propertyValue);
+ int arrayLength = subArray->Length();
+ for (int j=0 ; j < arrayLength ; ++j) {
+ v8::Handle<v8::Object> subObject = subArray->Get(j)->ToObject();
+ subModel->append(subObject, eng);
+ }
+
+ roleIndex = e->setListProperty(r, subModel);
+ } else if (propertyValue->IsBoolean()) {
+ const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::Bool);
+ roleIndex = e->setBoolProperty(r, propertyValue->BooleanValue());
+ } else if (propertyValue->IsObject()) {
+ QV8ObjectResource *r = (QV8ObjectResource *) propertyValue->ToObject()->GetExternalResource();
+ if (r && r->resourceType() == QV8ObjectResource::QObjectType) {
+ QObject *o = QV8QObjectWrapper::toQObject(r);
+ const ListLayout::Role &role = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::QObject);
+ if (role.type == ListLayout::Role::QObject)
+ roleIndex = e->setQObjectProperty(role, o);
+ } else {
+ const ListLayout::Role &role = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::VariantMap);
+ if (role.type == ListLayout::Role::VariantMap)
+ roleIndex = e->setVariantMapProperty(role, propertyValue->ToObject(), eng);
+ }
+ } else if (propertyValue.IsEmpty() || propertyValue->IsUndefined() || propertyValue->IsNull()) {
+ const ListLayout::Role *r = m_layout->getExistingRole(propertyName);
+ if (r)
+ e->clearProperty(*r);
+ }
+
+ if (roleIndex != -1)
+ roles->append(roleIndex);
+ }
+
+ if (e->m_objectCache) {
+ e->m_objectCache->updateValues(*roles);
+ }
+}
+
+void ListModel::set(int elementIndex, v8::Handle<v8::Object> object, QV8Engine *eng)
+{
+ ListElement *e = elements[elementIndex];
+
+ v8::Local<v8::Array> propertyNames = object->GetPropertyNames();
+ int propertyCount = propertyNames->Length();
+
+ for (int i=0 ; i < propertyCount ; ++i) {
+ v8::Local<v8::String> propertyName = propertyNames->Get(i)->ToString();
+ v8::Local<v8::Value> propertyValue = object->Get(propertyName);
+
+ // Add the value now
+ if (propertyValue->IsString()) {
+ const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::String);
+ if (r.type == ListLayout::Role::String) {
+ v8::Handle<v8::String> jsString = propertyValue->ToString();
+ QString qstr;
+ qstr.resize(jsString->Length());
+ jsString->Write(reinterpret_cast<uint16_t*>(qstr.data()));
+ e->setStringPropertyFast(r, qstr);
+ }
+ } else if (propertyValue->IsNumber()) {
+ const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::Number);
+ if (r.type == ListLayout::Role::Number) {
+ e->setDoublePropertyFast(r, propertyValue->NumberValue());
+ }
+ } else if (propertyValue->IsArray()) {
+ const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::List);
+ if (r.type == ListLayout::Role::List) {
+ ListModel *subModel = new ListModel(r.subLayout, 0, -1);
+
+ v8::Handle<v8::Array> subArray = v8::Handle<v8::Array>::Cast(propertyValue);
+ int arrayLength = subArray->Length();
+ for (int j=0 ; j < arrayLength ; ++j) {
+ v8::Handle<v8::Object> subObject = subArray->Get(j)->ToObject();
+ subModel->append(subObject, eng);
+ }
+
+ e->setListPropertyFast(r, subModel);
+ }
+ } else if (propertyValue->IsBoolean()) {
+ const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::Bool);
+ if (r.type == ListLayout::Role::Bool) {
+ e->setBoolPropertyFast(r, propertyValue->BooleanValue());
+ }
+ } else if (propertyValue->IsObject()) {
+ QV8ObjectResource *r = (QV8ObjectResource *) propertyValue->ToObject()->GetExternalResource();
+ if (r && r->resourceType() == QV8ObjectResource::QObjectType) {
+ QObject *o = QV8QObjectWrapper::toQObject(r);
+ const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::QObject);
+ if (r.type == ListLayout::Role::QObject)
+ e->setQObjectPropertyFast(r, o);
+ } else {
+ const ListLayout::Role &role = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::VariantMap);
+ if (role.type == ListLayout::Role::VariantMap)
+ e->setVariantMapFast(role, propertyValue->ToObject(), eng);
+ }
+ } else if (propertyValue.IsEmpty() || propertyValue->IsUndefined() || propertyValue->IsNull()) {
+ const ListLayout::Role *r = m_layout->getExistingRole(propertyName);
+ if (r)
+ e->clearProperty(*r);
+ }
+ }
+}
+
+void ListModel::clear()
+{
+ int elementCount = elements.count();
+ for (int i=0 ; i < elementCount ; ++i) {
+ elements[i]->destroy(m_layout);
+ delete elements[i];
+ }
+ elements.clear();
+}
+
+void ListModel::remove(int index, int count)
+{
+ for (int i=0 ; i < count ; ++i) {
+ elements[index+i]->destroy(m_layout);
+ delete elements[index+i];
+ }
+ elements.remove(index, count);
+ updateCacheIndices();
+}
+
+void ListModel::insert(int elementIndex, v8::Handle<v8::Object> object, QV8Engine *eng)
+{
+ insertElement(elementIndex);
+ set(elementIndex, object, eng);
+}
+
+int ListModel::append(v8::Handle<v8::Object> object, QV8Engine *eng)
+{
+ int elementIndex = appendElement();
+ set(elementIndex, object, eng);
+ return elementIndex;
+}
+
+int ListModel::setOrCreateProperty(int elementIndex, const QString &key, const QVariant &data)
+{
+ int roleIndex = -1;
+
+ if (elementIndex >= 0 && elementIndex < elements.count()) {
+ ListElement *e = elements[elementIndex];
+
+ const ListLayout::Role *r = m_layout->getRoleOrCreate(key, data);
+ if (r) {
+ roleIndex = e->setVariantProperty(*r, data);
+
+ if (roleIndex != -1 && e->m_objectCache) {
+ QList<int> roles;
+ roles << roleIndex;
+ e->m_objectCache->updateValues(roles);
+ }
+ }
+ }
+
+ return roleIndex;
+}
+
+int ListModel::setExistingProperty(int elementIndex, const QString &key, v8::Handle<v8::Value> data, QV8Engine *eng)
+{
+ int roleIndex = -1;
+
+ if (elementIndex >= 0 && elementIndex < elements.count()) {
+ ListElement *e = elements[elementIndex];
+ const ListLayout::Role *r = m_layout->getExistingRole(key);
+ if (r)
+ roleIndex = e->setJsProperty(*r, data, eng);
+ }
+
+ return roleIndex;
+}
+
+inline char *ListElement::getPropertyMemory(const ListLayout::Role &role)
+{
+ ListElement *e = this;
+ int blockIndex = 0;
+ while (blockIndex < role.blockIndex) {
+ if (e->next == 0) {
+ e->next = new ListElement;
+ e->next->uid = uid;
+ }
+ e = e->next;
+ ++blockIndex;
+ }
+
+ char *mem = &e->data[role.blockOffset];
+ return mem;
+}
+
+QString *ListElement::getStringProperty(const ListLayout::Role &role)
+{
+ char *mem = getPropertyMemory(role);
+ QString *s = reinterpret_cast<QString *>(mem);
+ return s->data_ptr() ? s : 0;
+}
+
+QObject *ListElement::getQObjectProperty(const ListLayout::Role &role)
+{
+ char *mem = getPropertyMemory(role);
+ QQmlGuard<QObject> *o = reinterpret_cast<QQmlGuard<QObject> *>(mem);
+ return o->data();
+}
+
+QVariantMap *ListElement::getVariantMapProperty(const ListLayout::Role &role)
+{
+ QVariantMap *map = 0;
+
+ char *mem = getPropertyMemory(role);
+ if (isMemoryUsed<QVariantMap>(mem))
+ map = reinterpret_cast<QVariantMap *>(mem);
+
+ return map;
+}
+
+QQmlGuard<QObject> *ListElement::getGuardProperty(const ListLayout::Role &role)
+{
+ char *mem = getPropertyMemory(role);
+
+ bool existingGuard = false;
+ for (size_t i=0 ; i < sizeof(QQmlGuard<QObject>) ; ++i) {
+ if (mem[i] != 0) {
+ existingGuard = true;
+ break;
+ }
+ }
+
+ QQmlGuard<QObject> *o = 0;
+
+ if (existingGuard)
+ o = reinterpret_cast<QQmlGuard<QObject> *>(mem);
+
+ return o;
+}
+
+ListModel *ListElement::getListProperty(const ListLayout::Role &role)
+{
+ char *mem = getPropertyMemory(role);
+ ListModel **value = reinterpret_cast<ListModel **>(mem);
+ return *value;
+}
+
+QVariant ListElement::getProperty(const ListLayout::Role &role, const QQuickListModel *owner, QV8Engine *eng)
+{
+ char *mem = getPropertyMemory(role);
+
+ QVariant data;
+
+ switch (role.type) {
+ case ListLayout::Role::Number:
+ {
+ double *value = reinterpret_cast<double *>(mem);
+ data = *value;
+ }
+ break;
+ case ListLayout::Role::String:
+ {
+ QString *value = reinterpret_cast<QString *>(mem);
+ if (value->data_ptr() != 0)
+ data = *value;
+ }
+ break;
+ case ListLayout::Role::Bool:
+ {
+ bool *value = reinterpret_cast<bool *>(mem);
+ data = *value;
+ }
+ break;
+ case ListLayout::Role::List:
+ {
+ ListModel **value = reinterpret_cast<ListModel **>(mem);
+ ListModel *model = *value;
+
+ if (model) {
+ if (model->m_modelCache == 0) {
+ model->m_modelCache = new QQuickListModel(owner, model, eng);
+ QQmlEngine::setContextForObject(model->m_modelCache, QQmlEngine::contextForObject(owner));
+ }
+
+ QObject *object = model->m_modelCache;
+ data = QVariant::fromValue(object);
+ }
+ }
+ break;
+ case ListLayout::Role::QObject:
+ {
+ QQmlGuard<QObject> *guard = reinterpret_cast<QQmlGuard<QObject> *>(mem);
+ QObject *object = guard->data();
+ if (object)
+ data = QVariant::fromValue(object);
+ }
+ break;
+ case ListLayout::Role::VariantMap:
+ {
+ if (isMemoryUsed<QVariantMap>(mem)) {
+ QVariantMap *map = reinterpret_cast<QVariantMap *>(mem);
+ data = *map;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ return data;
+}
+
+int ListElement::setStringProperty(const ListLayout::Role &role, const QString &s)
+{
+ int roleIndex = -1;
+
+ if (role.type == ListLayout::Role::String) {
+ char *mem = getPropertyMemory(role);
+ QString *c = reinterpret_cast<QString *>(mem);
+ bool changed;
+ if (c->data_ptr() == 0) {
+ new (mem) QString(s);
+ changed = true;
+ } else {
+ changed = c->compare(s) != 0;
+ *c = s;
+ }
+ if (changed)
+ roleIndex = role.index;
+ }
+
+ return roleIndex;
+}
+
+int ListElement::setDoubleProperty(const ListLayout::Role &role, double d)
+{
+ int roleIndex = -1;
+
+ if (role.type == ListLayout::Role::Number) {
+ char *mem = getPropertyMemory(role);
+ double *value = new (mem) double;
+ bool changed = *value != d;
+ *value = d;
+ if (changed)
+ roleIndex = role.index;
+ }
+
+ return roleIndex;
+}
+
+int ListElement::setBoolProperty(const ListLayout::Role &role, bool b)
+{
+ int roleIndex = -1;
+
+ if (role.type == ListLayout::Role::Bool) {
+ char *mem = getPropertyMemory(role);
+ bool *value = new (mem) bool;
+ bool changed = *value != b;
+ *value = b;
+ if (changed)
+ roleIndex = role.index;
+ }
+
+ return roleIndex;
+}
+
+int ListElement::setListProperty(const ListLayout::Role &role, ListModel *m)
+{
+ int roleIndex = -1;
+
+ if (role.type == ListLayout::Role::List) {
+ char *mem = getPropertyMemory(role);
+ ListModel **value = new (mem) ListModel *;
+ if (*value) {
+ (*value)->destroy();
+ delete *value;
+ }
+ *value = m;
+ roleIndex = role.index;
+ }
+
+ return roleIndex;
+}
+
+int ListElement::setQObjectProperty(const ListLayout::Role &role, QObject *o)
+{
+ int roleIndex = -1;
+
+ if (role.type == ListLayout::Role::QObject) {
+ char *mem = getPropertyMemory(role);
+ QQmlGuard<QObject> *g = reinterpret_cast<QQmlGuard<QObject> *>(mem);
+ bool existingGuard = false;
+ for (size_t i=0 ; i < sizeof(QQmlGuard<QObject>) ; ++i) {
+ if (mem[i] != 0) {
+ existingGuard = true;
+ break;
+ }
+ }
+ bool changed;
+ if (existingGuard) {
+ changed = g->data() != o;
+ g->~QQmlGuard();
+ } else {
+ changed = true;
+ }
+ new (mem) QQmlGuard<QObject>(o);
+ if (changed)
+ roleIndex = role.index;
+ }
+
+ return roleIndex;
+}
+
+int ListElement::setVariantMapProperty(const ListLayout::Role &role, v8::Handle<v8::Object> o, QV8Engine *eng)
+{
+ int roleIndex = -1;
+
+ if (role.type == ListLayout::Role::VariantMap) {
+ char *mem = getPropertyMemory(role);
+ if (isMemoryUsed<QVariantMap>(mem)) {
+ QVariantMap *map = reinterpret_cast<QVariantMap *>(mem);
+ map->~QMap();
+ }
+ new (mem) QVariantMap(eng->variantMapFromJS(o));
+ roleIndex = role.index;
+ }
+
+ return roleIndex;
+}
+
+int ListElement::setVariantMapProperty(const ListLayout::Role &role, QVariantMap *m)
+{
+ int roleIndex = -1;
+
+ if (role.type == ListLayout::Role::VariantMap) {
+ char *mem = getPropertyMemory(role);
+ if (isMemoryUsed<QVariantMap>(mem)) {
+ QVariantMap *map = reinterpret_cast<QVariantMap *>(mem);
+ map->~QMap();
+ }
+ if (m)
+ new (mem) QVariantMap(*m);
+ else
+ new (mem) QVariantMap;
+ roleIndex = role.index;
+ }
+
+ return roleIndex;
+}
+
+void ListElement::setStringPropertyFast(const ListLayout::Role &role, const QString &s)
+{
+ char *mem = getPropertyMemory(role);
+ new (mem) QString(s);
+}
+
+void ListElement::setDoublePropertyFast(const ListLayout::Role &role, double d)
+{
+ char *mem = getPropertyMemory(role);
+ double *value = new (mem) double;
+ *value = d;
+}
+
+void ListElement::setBoolPropertyFast(const ListLayout::Role &role, bool b)
+{
+ char *mem = getPropertyMemory(role);
+ bool *value = new (mem) bool;
+ *value = b;
+}
+
+void ListElement::setQObjectPropertyFast(const ListLayout::Role &role, QObject *o)
+{
+ char *mem = getPropertyMemory(role);
+ new (mem) QQmlGuard<QObject>(o);
+}
+
+void ListElement::setListPropertyFast(const ListLayout::Role &role, ListModel *m)
+{
+ char *mem = getPropertyMemory(role);
+ ListModel **value = new (mem) ListModel *;
+ *value = m;
+}
+
+void ListElement::setVariantMapFast(const ListLayout::Role &role, v8::Handle<v8::Object> o, QV8Engine *eng)
+{
+ char *mem = getPropertyMemory(role);
+ QVariantMap *map = new (mem) QVariantMap;
+ *map = eng->variantMapFromJS(o);
+}
+
+void ListElement::clearProperty(const ListLayout::Role &role)
+{
+ switch (role.type) {
+ case ListLayout::Role::String:
+ setStringProperty(role, QString());
+ break;
+ case ListLayout::Role::Number:
+ setDoubleProperty(role, 0.0);
+ break;
+ case ListLayout::Role::Bool:
+ setBoolProperty(role, false);
+ break;
+ case ListLayout::Role::List:
+ setListProperty(role, 0);
+ break;
+ case ListLayout::Role::QObject:
+ setQObjectProperty(role, 0);
+ break;
+ case ListLayout::Role::VariantMap:
+ setVariantMapProperty(role, 0);
+ break;
+ default:
+ break;
+ }
+}
+
+ListElement::ListElement()
+{
+ m_objectCache = 0;
+ uid = uidCounter.fetchAndAddOrdered(1);
+ next = 0;
+ qMemSet(data, 0, sizeof(data));
+}
+
+ListElement::ListElement(int existingUid)
+{
+ m_objectCache = 0;
+ uid = existingUid;
+ next = 0;
+ qMemSet(data, 0, sizeof(data));
+}
+
+ListElement::~ListElement()
+{
+ delete next;
+}
+
+void ListElement::sync(ListElement *src, ListLayout *srcLayout, ListElement *target, ListLayout *targetLayout, QHash<int, ListModel *> *targetModelHash)
+{
+ for (int i=0 ; i < srcLayout->roleCount() ; ++i) {
+ const ListLayout::Role &srcRole = srcLayout->getExistingRole(i);
+ const ListLayout::Role &targetRole = targetLayout->getExistingRole(i);
+
+ switch (srcRole.type) {
+ case ListLayout::Role::List:
+ {
+ ListModel *srcSubModel = src->getListProperty(srcRole);
+ ListModel *targetSubModel = target->getListProperty(targetRole);
+
+ if (srcSubModel) {
+ if (targetSubModel == 0) {
+ targetSubModel = new ListModel(targetRole.subLayout, 0, srcSubModel->getUid());
+ target->setListPropertyFast(targetRole, targetSubModel);
+ }
+ ListModel::sync(srcSubModel, targetSubModel, targetModelHash);
+ }
+ }
+ break;
+ case ListLayout::Role::QObject:
+ {
+ QObject *object = src->getQObjectProperty(srcRole);
+ target->setQObjectProperty(targetRole, object);
+ }
+ break;
+ case ListLayout::Role::String:
+ case ListLayout::Role::Number:
+ case ListLayout::Role::Bool:
+ {
+ QVariant v = src->getProperty(srcRole, 0, 0);
+ target->setVariantProperty(targetRole, v);
+ }
+ case ListLayout::Role::VariantMap:
+ {
+ QVariantMap *map = src->getVariantMapProperty(srcRole);
+ target->setVariantMapProperty(targetRole, map);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+}
+
+void ListElement::destroy(ListLayout *layout)
+{
+ if (layout) {
+ for (int i=0 ; i < layout->roleCount() ; ++i) {
+ const ListLayout::Role &r = layout->getExistingRole(i);
+
+ switch (r.type) {
+ case ListLayout::Role::String:
+ {
+ QString *string = getStringProperty(r);
+ if (string)
+ string->~QString();
+ }
+ break;
+ case ListLayout::Role::List:
+ {
+ ListModel *model = getListProperty(r);
+ if (model) {
+ model->destroy();
+ delete model;
+ }
+ }
+ break;
+ case ListLayout::Role::QObject:
+ {
+ QQmlGuard<QObject> *guard = getGuardProperty(r);
+ if (guard)
+ guard->~QQmlGuard();
+ }
+ break;
+ case ListLayout::Role::VariantMap:
+ {
+ QVariantMap *map = getVariantMapProperty(r);
+ if (map)
+ map->~QMap();
+ }
+ break;
+ default:
+ // other types don't need explicit cleanup.
+ break;
+ }
+ }
+
+ delete m_objectCache;
+ }
+
+ if (next)
+ next->destroy(0);
+ uid = -1;
+}
+
+int ListElement::setVariantProperty(const ListLayout::Role &role, const QVariant &d)
+{
+ int roleIndex = -1;
+
+ switch (role.type) {
+ case ListLayout::Role::Number:
+ roleIndex = setDoubleProperty(role, d.toDouble());
+ break;
+ case ListLayout::Role::String:
+ roleIndex = setStringProperty(role, d.toString());
+ break;
+ case ListLayout::Role::Bool:
+ roleIndex = setBoolProperty(role, d.toBool());
+ break;
+ case ListLayout::Role::List:
+ roleIndex = setListProperty(role, d.value<ListModel *>());
+ break;
+ case ListLayout::Role::VariantMap: {
+ QVariantMap map = d.toMap();
+ roleIndex = setVariantMapProperty(role, &map);
+ }
+ break;
+ default:
+ break;
+ }
+
+ return roleIndex;
+}
+
+int ListElement::setJsProperty(const ListLayout::Role &role, v8::Handle<v8::Value> d, QV8Engine *eng)
+{
+ // Check if this key exists yet
+ int roleIndex = -1;
+
+ // Add the value now
+ if (d->IsString()) {
+ v8::Handle<v8::String> jsString = d->ToString();
+ QString qstr;
+ qstr.resize(jsString->Length());
+ jsString->Write(reinterpret_cast<uint16_t*>(qstr.data()));
+ roleIndex = setStringProperty(role, qstr);
+ } else if (d->IsNumber()) {
+ roleIndex = setDoubleProperty(role, d->NumberValue());
+ } else if (d->IsArray()) {
+ ListModel *subModel = new ListModel(role.subLayout, 0, -1);
+ v8::Handle<v8::Array> subArray = v8::Handle<v8::Array>::Cast(d);
+ int arrayLength = subArray->Length();
+ for (int j=0 ; j < arrayLength ; ++j) {
+ v8::Handle<v8::Object> subObject = subArray->Get(j)->ToObject();
+ subModel->append(subObject, eng);
+ }
+ roleIndex = setListProperty(role, subModel);
+ } else if (d->IsBoolean()) {
+ roleIndex = setBoolProperty(role, d->BooleanValue());
+ } else if (d->IsObject()) {
+ QV8ObjectResource *r = (QV8ObjectResource *) d->ToObject()->GetExternalResource();
+ if (role.type == ListLayout::Role::QObject && r && r->resourceType() == QV8ObjectResource::QObjectType) {
+ QObject *o = QV8QObjectWrapper::toQObject(r);
+ roleIndex = setQObjectProperty(role, o);
+ } else if (role.type == ListLayout::Role::VariantMap) {
+ roleIndex = setVariantMapProperty(role, d->ToObject(), eng);
+ }
+ } else if (d.IsEmpty() || d->IsUndefined() || d->IsNull()) {
+ clearProperty(role);
+ }
+
+ return roleIndex;
+}
+
+ModelObject::ModelObject(QQuickListModel *model, int elementIndex)
+: m_model(model), m_elementIndex(elementIndex), m_meta(new ModelNodeMetaObject(this))
+{
+ updateValues();
+ setNodeUpdatesEnabled(true);
+}
+
+void ModelObject::updateValues()
+{
+ int roleCount = m_model->m_listModel->roleCount();
+ for (int i=0 ; i < roleCount ; ++i) {
+ const ListLayout::Role &role = m_model->m_listModel->getExistingRole(i);
+ QByteArray name = role.name.toUtf8();
+ const QVariant &data = m_model->data(m_elementIndex, i);
+ setValue(name, data, role.type == ListLayout::Role::List);
+ }
+}
+
+void ModelObject::updateValues(const QList<int> &roles)
+{
+ int roleCount = roles.count();
+ for (int i=0 ; i < roleCount ; ++i) {
+ int roleIndex = roles.at(i);
+ const ListLayout::Role &role = m_model->m_listModel->getExistingRole(roleIndex);
+ QByteArray name = role.name.toUtf8();
+ const QVariant &data = m_model->data(m_elementIndex, roleIndex);
+ setValue(name, data, role.type == ListLayout::Role::List);
+ }
+}
+
+ModelNodeMetaObject::ModelNodeMetaObject(ModelObject *object)
+: QQmlOpenMetaObject(object), m_enabled(false), m_obj(object)
+{
+}
+
+ModelNodeMetaObject::~ModelNodeMetaObject()
+{
+}
+
+void ModelNodeMetaObject::propertyWritten(int index)
+{
+ if (!m_enabled)
+ return;
+
+ QV8Engine *eng = m_obj->m_model->engine();
+
+ QString propName = QString::fromUtf8(name(index));
+ QVariant value = operator[](index);
+
+ v8::HandleScope handle_scope;
+ v8::Context::Scope scope(eng->context());
+
+ v8::Handle<v8::Value> v = eng->fromVariant(value);
+
+ int roleIndex = m_obj->m_model->m_listModel->setExistingProperty(m_obj->m_elementIndex, propName, v, eng);
+ if (roleIndex != -1) {
+ QList<int> roles;
+ roles << roleIndex;
+ m_obj->m_model->emitItemsChanged(m_obj->m_elementIndex, 1, roles);
+ }
+}
+
+DynamicRoleModelNode::DynamicRoleModelNode(QQuickListModel *owner, int uid) : m_owner(owner), m_uid(uid), m_meta(new DynamicRoleModelNodeMetaObject(this))
+{
+ setNodeUpdatesEnabled(true);
+}
+
+DynamicRoleModelNode *DynamicRoleModelNode::create(const QVariantMap &obj, QQuickListModel *owner)
+{
+ DynamicRoleModelNode *object = new DynamicRoleModelNode(owner, uidCounter.fetchAndAddOrdered(1));
+ QList<int> roles;
+ object->updateValues(obj, roles);
+ return object;
+}
+
+void DynamicRoleModelNode::sync(DynamicRoleModelNode *src, DynamicRoleModelNode *target, QHash<int, QQuickListModel *> *targetModelHash)
+{
+ for (int i=0 ; i < src->m_meta->count() ; ++i) {
+ const QByteArray &name = src->m_meta->name(i);
+ QVariant value = src->m_meta->value(i);
+
+ QQuickListModel *srcModel = qobject_cast<QQuickListModel *>(value.value<QObject *>());
+ QQuickListModel *targetModel = qobject_cast<QQuickListModel *>(target->m_meta->value(i).value<QObject *>());
+
+ if (srcModel) {
+ if (targetModel == 0)
+ targetModel = QQuickListModel::createWithOwner(target->m_owner);
+
+ QQuickListModel::sync(srcModel, targetModel, targetModelHash);
+
+ QObject *targetModelObject = targetModel;
+ value = QVariant::fromValue(targetModelObject);
+ } else if (targetModel) {
+ delete targetModel;
+ }
+
+ target->setValue(name, value);
+ }
+}
+
+void DynamicRoleModelNode::updateValues(const QVariantMap &object, QList<int> &roles)
+{
+ const QList<QString> &keys = object.keys();
+
+ QList<QString>::const_iterator it = keys.begin();
+ QList<QString>::const_iterator end = keys.end();
+
+ while (it != end) {
+ const QString &key = *it;
+
+ int roleIndex = m_owner->m_roles.indexOf(key);
+ if (roleIndex == -1) {
+ roleIndex = m_owner->m_roles.count();
+ m_owner->m_roles.append(key);
+ }
+
+ QVariant value = object[key];
+
+ if (value.type() == QVariant::List) {
+ QQuickListModel *subModel = QQuickListModel::createWithOwner(m_owner);
+
+ QVariantList subArray = value.toList();
+ QVariantList::const_iterator subIt = subArray.begin();
+ QVariantList::const_iterator subEnd = subArray.end();
+ while (subIt != subEnd) {
+ const QVariantMap &subObject = subIt->toMap();
+ subModel->m_modelObjects.append(DynamicRoleModelNode::create(subObject, subModel));
+ ++subIt;
+ }
+
+ QObject *subModelObject = subModel;
+ value = QVariant::fromValue(subModelObject);
+ }
+
+ const QByteArray &keyUtf8 = key.toUtf8();
+
+ QQuickListModel *existingModel = qobject_cast<QQuickListModel *>(m_meta->value(keyUtf8).value<QObject *>());
+ if (existingModel)
+ delete existingModel;
+
+ if (m_meta->setValue(keyUtf8, value))
+ roles << roleIndex;
+
+ ++it;
+ }
+}
+
+DynamicRoleModelNodeMetaObject::DynamicRoleModelNodeMetaObject(DynamicRoleModelNode *object)
+ : QQmlOpenMetaObject(object), m_enabled(false), m_owner(object)
+{
+}
+
+DynamicRoleModelNodeMetaObject::~DynamicRoleModelNodeMetaObject()
+{
+ for (int i=0 ; i < count() ; ++i) {
+ QQuickListModel *subModel = qobject_cast<QQuickListModel *>(value(i).value<QObject *>());
+ if (subModel)
+ delete subModel;
+ }
+}
+
+void DynamicRoleModelNodeMetaObject::propertyWrite(int index)
+{
+ if (!m_enabled)
+ return;
+
+ QVariant v = value(index);
+ QQuickListModel *model = qobject_cast<QQuickListModel *>(v.value<QObject *>());
+ if (model)
+ delete model;
+}
+
+void DynamicRoleModelNodeMetaObject::propertyWritten(int index)
+{
+ if (!m_enabled)
+ return;
+
+ QQuickListModel *parentModel = m_owner->m_owner;
+
+ QVariant v = value(index);
+ if (v.type() == QVariant::List) {
+ QQuickListModel *subModel = QQuickListModel::createWithOwner(parentModel);
+
+ QVariantList subArray = v.toList();
+ QVariantList::const_iterator subIt = subArray.begin();
+ QVariantList::const_iterator subEnd = subArray.end();
+ while (subIt != subEnd) {
+ const QVariantMap &subObject = subIt->toMap();
+ subModel->m_modelObjects.append(DynamicRoleModelNode::create(subObject, subModel));
+ ++subIt;
+ }
+
+ QObject *subModelObject = subModel;
+ v = QVariant::fromValue(subModelObject);
+
+ setValue(index, v);
+ }
+
+ int elementIndex = parentModel->m_modelObjects.indexOf(m_owner);
+ int roleIndex = parentModel->m_roles.indexOf(QString::fromLatin1(name(index).constData()));
+
+ if (elementIndex != -1 && roleIndex != -1) {
+ QList<int> roles;
+ roles << roleIndex;
+
+ parentModel->emitItemsChanged(elementIndex, 1, roles);
+ }
+}
+
+QQuickListModelParser::ListInstruction *QQuickListModelParser::ListModelData::instructions() const
+{
+ return (QQuickListModelParser::ListInstruction *)((char *)this + sizeof(ListModelData));
+}
+
+/*!
+ \qmlclass ListModel QQuickListModel
+ \inqmlmodule QtQuick 2
+ \ingroup qml-working-with-data
+ \brief The ListModel element defines a free-form list data source.
+
+ The ListModel is a simple container of ListElement definitions, each containing data roles.
+ The contents can be defined dynamically, or explicitly in QML.
+
+ The number of elements in the model can be obtained from its \l count property.
+ A number of familiar methods are also provided to manipulate the contents of the
+ model, including append(), insert(), move(), remove() and set(). These methods
+ accept dictionaries as their arguments; these are translated to ListElement objects
+ by the model.
+
+ Elements can be manipulated via the model using the setProperty() method, which
+ allows the roles of the specified element to be set and changed.
+
+ \section1 Example Usage
+
+ The following example shows a ListModel containing three elements, with the roles
+ "name" and "cost".
+
+ \div {class="float-right"}
+ \inlineimage listmodel.png
+ \enddiv
+
+ \snippet doc/src/snippets/qml/listmodel.qml 0
+
+ \clearfloat
+ Roles (properties) in each element must begin with a lower-case letter and
+ should be common to all elements in a model. The ListElement documentation
+ provides more guidelines for how elements should be defined.
+
+ Since the example model contains an \c id property, it can be referenced
+ by views, such as the ListView in this example:
+
+ \snippet doc/src/snippets/qml/listmodel-simple.qml 0
+ \dots 8
+ \snippet doc/src/snippets/qml/listmodel-simple.qml 1
+
+ It is possible for roles to contain list data. In the following example we
+ create a list of fruit attributes:
+
+ \snippet doc/src/snippets/qml/listmodel-nested.qml model
+
+ The delegate displays all the fruit attributes:
+
+ \div {class="float-right"}
+ \inlineimage listmodel-nested.png
+ \enddiv
+
+ \snippet doc/src/snippets/qml/listmodel-nested.qml delegate
+
+ \clearfloat
+ \section1 Modifying List Models
+
+ The content of a ListModel may be created and modified using the clear(),
+ append(), set(), insert() and setProperty() methods. For example:
+
+ \snippet doc/src/snippets/qml/listmodel-modify.qml delegate
+
+ Note that when creating content dynamically the set of available properties
+ cannot be changed once set. Whatever properties are first added to the model
+ are the only permitted properties in the model.
+
+ \section1 Using Threaded List Models with WorkerScript
+
+ ListModel can be used together with WorkerScript access a list model
+ from multiple threads. This is useful if list modifications are
+ synchronous and take some time: the list operations can be moved to a
+ different thread to avoid blocking of the main GUI thread.
+
+ Here is an example that uses WorkerScript to periodically append the
+ current time to a list model:
+
+ \snippet examples/declarative/threading/threadedlistmodel/timedisplay.qml 0
+
+ The included file, \tt dataloader.js, looks like this:
+
+ \snippet examples/declarative/threading/threadedlistmodel/dataloader.js 0
+
+ The timer in the main example sends messages to the worker script by calling
+ \l WorkerScript::sendMessage(). When this message is received,
+ \l{WorkerScript::onMessage}{WorkerScript.onMessage()} is invoked in \c dataloader.js,
+ which appends the current time to the list model.
+
+ Note the call to sync() from the \l{WorkerScript::onMessage}{WorkerScript.onMessage()}
+ handler. You must call sync() or else the changes made to the list from the external
+ thread will not be reflected in the list model in the main thread.
+
+ \sa {qmlmodels}{Data Models}, {declarative/threading/threadedlistmodel}{Threaded ListModel example}, QtQml
+*/
+
+QQuickListModel::QQuickListModel(QObject *parent)
+: QListModelInterface(parent)
+{
+ m_mainThread = true;
+ m_primary = true;
+ m_agent = 0;
+ m_uid = uidCounter.fetchAndAddOrdered(1);
+ m_dynamicRoles = false;
+
+ m_layout = new ListLayout;
+ m_listModel = new ListModel(m_layout, this, -1);
+
+ m_engine = 0;
+}
+
+QQuickListModel::QQuickListModel(const QQuickListModel *owner, ListModel *data, QV8Engine *eng, QObject *parent)
+: QListModelInterface(parent)
+{
+ m_mainThread = owner->m_mainThread;
+ m_primary = false;
+ m_agent = owner->m_agent;
+
+ Q_ASSERT(owner->m_dynamicRoles == false);
+ m_dynamicRoles = false;
+ m_layout = 0;
+ m_listModel = data;
+
+ m_engine = eng;
+}
+
+QQuickListModel::QQuickListModel(QQuickListModel *orig, QQuickListModelWorkerAgent *agent)
+: QListModelInterface(agent)
+{
+ m_mainThread = false;
+ m_primary = true;
+ m_agent = agent;
+ m_dynamicRoles = orig->m_dynamicRoles;
+
+ m_layout = new ListLayout(orig->m_layout);
+ m_listModel = new ListModel(m_layout, this, orig->m_listModel->getUid());
+
+ if (m_dynamicRoles)
+ sync(orig, this, 0);
+ else
+ ListModel::sync(orig->m_listModel, m_listModel, 0);
+
+ m_engine = 0;
+}
+
+QQuickListModel::~QQuickListModel()
+{
+ for (int i=0 ; i < m_modelObjects.count() ; ++i)
+ delete m_modelObjects[i];
+
+ if (m_primary) {
+ m_listModel->destroy();
+ delete m_listModel;
+
+ if (m_mainThread && m_agent) {
+ m_agent->modelDestroyed();
+ m_agent->release();
+ }
+ }
+
+ m_listModel = 0;
+
+ delete m_layout;
+ m_layout = 0;
+}
+
+QQuickListModel *QQuickListModel::createWithOwner(QQuickListModel *newOwner)
+{
+ QQuickListModel *model = new QQuickListModel;
+
+ model->m_mainThread = newOwner->m_mainThread;
+ model->m_engine = newOwner->m_engine;
+ model->m_agent = newOwner->m_agent;
+ model->m_dynamicRoles = newOwner->m_dynamicRoles;
+
+ if (model->m_mainThread && model->m_agent)
+ model->m_agent->addref();
+
+ QQmlEngine::setContextForObject(model, QQmlEngine::contextForObject(newOwner));
+
+ return model;
+}
+
+QV8Engine *QQuickListModel::engine() const
+{
+ if (m_engine == 0) {
+ m_engine = QQmlEnginePrivate::getV8Engine(qmlEngine(this));
+ }
+
+ return m_engine;
+}
+
+void QQuickListModel::sync(QQuickListModel *src, QQuickListModel *target, QHash<int, QQuickListModel *> *targetModelHash)
+{
+ Q_ASSERT(src->m_dynamicRoles && target->m_dynamicRoles);
+
+ target->m_uid = src->m_uid;
+ if (targetModelHash)
+ targetModelHash->insert(target->m_uid, target);
+ target->m_roles = src->m_roles;
+
+ // Build hash of elements <-> uid for each of the lists
+ QHash<int, ElementSync> elementHash;
+ for (int i=0 ; i < target->m_modelObjects.count() ; ++i) {
+ DynamicRoleModelNode *e = target->m_modelObjects.at(i);
+ int uid = e->getUid();
+ ElementSync sync;
+ sync.target = e;
+ elementHash.insert(uid, sync);
+ }
+ for (int i=0 ; i < src->m_modelObjects.count() ; ++i) {
+ DynamicRoleModelNode *e = src->m_modelObjects.at(i);
+ int uid = e->getUid();
+
+ QHash<int, ElementSync>::iterator it = elementHash.find(uid);
+ if (it == elementHash.end()) {
+ ElementSync sync;
+ sync.src = e;
+ elementHash.insert(uid, sync);
+ } else {
+ ElementSync &sync = it.value();
+ sync.src = e;
+ }
+ }
+
+ // Get list of elements that are in the target but no longer in the source. These get deleted first.
+ QHash<int, ElementSync>::iterator it = elementHash.begin();
+ QHash<int, ElementSync>::iterator end = elementHash.end();
+ while (it != end) {
+ const ElementSync &s = it.value();
+ if (s.src == 0) {
+ int targetIndex = target->m_modelObjects.indexOf(s.target);
+ target->m_modelObjects.remove(targetIndex, 1);
+ delete s.target;
+ }
+ ++it;
+ }
+
+ // Clear the target list, and append in correct order from the source
+ target->m_modelObjects.clear();
+ for (int i=0 ; i < src->m_modelObjects.count() ; ++i) {
+ DynamicRoleModelNode *srcElement = src->m_modelObjects.at(i);
+ it = elementHash.find(srcElement->getUid());
+ const ElementSync &s = it.value();
+ DynamicRoleModelNode *targetElement = s.target;
+ if (targetElement == 0) {
+ targetElement = new DynamicRoleModelNode(target, srcElement->getUid());
+ }
+ DynamicRoleModelNode::sync(srcElement, targetElement, targetModelHash);
+ target->m_modelObjects.append(targetElement);
+ }
+}
+
+void QQuickListModel::emitItemsChanged(int index, int count, const QList<int> &roles)
+{
+ if (m_mainThread) {
+ emit itemsChanged(index, count, roles);
+ } else {
+ int uid = m_dynamicRoles ? getUid() : m_listModel->getUid();
+ m_agent->data.changedChange(uid, index, count, roles);
+ }
+}
+
+void QQuickListModel::emitItemsRemoved(int index, int count)
+{
+ if (m_mainThread) {
+ emit itemsRemoved(index, count);
+ emit countChanged();
+ } else {
+ int uid = m_dynamicRoles ? getUid() : m_listModel->getUid();
+ if (index == 0 && count == this->count())
+ m_agent->data.clearChange(uid);
+ m_agent->data.removeChange(uid, index, count);
+ }
+}
+
+void QQuickListModel::emitItemsInserted(int index, int count)
+{
+ if (m_mainThread) {
+ emit itemsInserted(index, count);
+ emit countChanged();
+ } else {
+ int uid = m_dynamicRoles ? getUid() : m_listModel->getUid();
+ m_agent->data.insertChange(uid, index, count);
+ }
+}
+
+void QQuickListModel::emitItemsMoved(int from, int to, int n)
+{
+ if (m_mainThread) {
+ emit itemsMoved(from, to, n);
+ } else {
+ int uid = m_dynamicRoles ? getUid() : m_listModel->getUid();
+ m_agent->data.moveChange(uid, from, n, to);
+ }
+}
+
+QQuickListModelWorkerAgent *QQuickListModel::agent()
+{
+ if (m_agent)
+ return m_agent;
+
+ m_agent = new QQuickListModelWorkerAgent(this);
+ return m_agent;
+}
+
+QList<int> QQuickListModel::roles() const
+{
+ QList<int> rolesArray;
+
+ if (m_dynamicRoles) {
+ for (int i=0 ; i < m_roles.count() ; ++i)
+ rolesArray << i;
+ } else {
+ for (int i=0 ; i < m_listModel->roleCount() ; ++i)
+ rolesArray << i;
+ }
+
+ return rolesArray;
+}
+
+QString QQuickListModel::toString(int role) const
+{
+ QString roleName;
+
+ if (m_dynamicRoles) {
+ roleName = m_roles[role];
+ } else {
+ const ListLayout::Role &r = m_listModel->getExistingRole(role);
+ roleName = r.name;
+ }
+
+ return roleName;
+}
+
+QVariant QQuickListModel::data(int index, int role) const
+{
+ QVariant v;
+
+ if (index >= count() || index < 0)
+ return v;
+
+ if (m_dynamicRoles)
+ v = m_modelObjects[index]->getValue(m_roles[role]);
+ else
+ v = m_listModel->getProperty(index, role, this, engine());
+
+ return v;
+}
+
+/*!
+ \qmlproperty bool QtQuick2::ListModel::dynamicRoles
+
+ By default, the type of a role is fixed the first time
+ the role is used. For example, if you create a role called
+ "data" and assign a number to it, you can no longer assign
+ a string to the "data" role. However, when the dynamicRoles
+ property is enabled, the type of a given role is not fixed
+ and can be different between elements.
+
+ The dynamicRoles property must be set before any data is
+ added to the ListModel, and must be set from the main
+ thread.
+
+ A ListModel that has data statically defined (via the
+ ListElement QML syntax) cannot have the dynamicRoles
+ property enabled.
+
+ There is a significant performance cost to using a
+ ListModel with dynamic roles enabled. The cost varies
+ from platform to platform but is typically somewhere
+ between 4-6x slower than using static role types.
+
+ Due to the performance cost of using dynamic roles,
+ they are disabled by default.
+*/
+void QQuickListModel::setDynamicRoles(bool enableDynamicRoles)
+{
+ if (m_mainThread && m_agent == 0) {
+ if (enableDynamicRoles) {
+ if (m_layout->roleCount())
+ qmlInfo(this) << tr("unable to enable dynamic roles as this model is not empty!");
+ else
+ m_dynamicRoles = true;
+ } else {
+ if (m_roles.count()) {
+ qmlInfo(this) << tr("unable to enable static roles as this model is not empty!");
+ } else {
+ m_dynamicRoles = false;
+ }
+ }
+ } else {
+ qmlInfo(this) << tr("dynamic role setting must be made from the main thread, before any worker scripts are created");
+ }
+}
+
+/*!
+ \qmlproperty int QtQuick2::ListModel::count
+ The number of data entries in the model.
+*/
+int QQuickListModel::count() const
+{
+ int count;
+
+ if (m_dynamicRoles)
+ count = m_modelObjects.count();
+ else {
+ count = m_listModel->elementCount();
+ }
+
+ return count;
+}
+
+/*!
+ \qmlmethod QtQuick2::ListModel::clear()
+
+ Deletes all content from the model.
+
+ \sa append() remove()
+*/
+void QQuickListModel::clear()
+{
+ int cleared = count();
+
+ if (m_dynamicRoles) {
+ for (int i=0 ; i < m_modelObjects.count() ; ++i)
+ delete m_modelObjects[i];
+ m_modelObjects.clear();
+ } else {
+ m_listModel->clear();
+ }
+
+ emitItemsRemoved(0, cleared);
+}
+
+/*!
+ \qmlmethod QtQuick2::ListModel::remove(int index, int count = 1)
+
+ Deletes the content at \a index from the model.
+
+ \sa clear()
+*/
+void QQuickListModel::remove(QQmlV8Function *args)
+{
+ int argLength = args->Length();
+
+ if (argLength == 1 || argLength == 2) {
+ int index = (*args)[0]->Int32Value();
+ int removeCount = (argLength == 2 ? ((*args)[1]->Int32Value()) : 1);
+
+ if (index < 0 || index+removeCount > count() || removeCount <= 0) {
+ qmlInfo(this) << tr("remove: indices [%1 - %2] out of range [0 - %3]").arg(index).arg(index+removeCount).arg(count());
+ return;
+ }
+
+ if (m_dynamicRoles) {
+ for (int i=0 ; i < removeCount ; ++i)
+ delete m_modelObjects[index+i];
+ m_modelObjects.remove(index, removeCount);
+ } else {
+ m_listModel->remove(index, removeCount);
+ }
+
+ emitItemsRemoved(index, removeCount);
+ } else {
+ qmlInfo(this) << tr("remove: incorrect number of arguments");
+ }
+}
+
+/*!
+ \qmlmethod QtQuick2::ListModel::insert(int index, jsobject dict)
+
+ Adds a new item to the list model at position \a index, with the
+ values in \a dict.
+
+ \code
+ fruitModel.insert(2, {"cost": 5.95, "name":"Pizza"})
+ \endcode
+
+ The \a index must be to an existing item in the list, or one past
+ the end of the list (equivalent to append).
+
+ \sa set() append()
+*/
+
+void QQuickListModel::insert(QQmlV8Function *args)
+{
+ if (args->Length() == 2) {
+
+ v8::Handle<v8::Value> arg0 = (*args)[0];
+ int index = arg0->Int32Value();
+
+ if (index < 0 || index > count()) {
+ qmlInfo(this) << tr("insert: index %1 out of range").arg(index);
+ return;
+ }
+
+ v8::Handle<v8::Value> arg1 = (*args)[1];
+
+ if (arg1->IsArray()) {
+ v8::Handle<v8::Array> objectArray = v8::Handle<v8::Array>::Cast(arg1);
+ int objectArrayLength = objectArray->Length();
+ for (int i=0 ; i < objectArrayLength ; ++i) {
+ v8::Handle<v8::Object> argObject = objectArray->Get(i)->ToObject();
+
+ if (m_dynamicRoles) {
+ m_modelObjects.insert(index+i, DynamicRoleModelNode::create(args->engine()->variantMapFromJS(argObject), this));
+ } else {
+ m_listModel->insert(index+i, argObject, args->engine());
+ }
+ }
+ emitItemsInserted(index, objectArrayLength);
+ } else if (arg1->IsObject()) {
+ v8::Handle<v8::Object> argObject = arg1->ToObject();
+
+ if (m_dynamicRoles) {
+ m_modelObjects.insert(index, DynamicRoleModelNode::create(args->engine()->variantMapFromJS(argObject), this));
+ } else {
+ m_listModel->insert(index, argObject, args->engine());
+ }
+
+ emitItemsInserted(index, 1);
+ } else {
+ qmlInfo(this) << tr("insert: value is not an object");
+ }
+ } else {
+ qmlInfo(this) << tr("insert: value is not an object");
+ }
+}
+
+/*!
+ \qmlmethod QtQuick2::ListModel::move(int from, int to, int n)
+
+ Moves \a n items \a from one position \a to another.
+
+ The from and to ranges must exist; for example, to move the first 3 items
+ to the end of the list:
+
+ \code
+ fruitModel.move(0, fruitModel.count - 3, 3)
+ \endcode
+
+ \sa append()
+*/
+void QQuickListModel::move(int from, int to, int n)
+{
+ if (n==0 || from==to)
+ return;
+ if (!canMove(from, to, n)) {
+ qmlInfo(this) << tr("move: out of range");
+ return;
+ }
+
+ if (m_dynamicRoles) {
+
+ int realFrom = from;
+ int realTo = to;
+ int realN = n;
+
+ if (from > to) {
+ // Only move forwards - flip if backwards moving
+ int tfrom = from;
+ int tto = to;
+ realFrom = tto;
+ realTo = tto+n;
+ realN = tfrom-tto;
+ }
+
+ QPODVector<DynamicRoleModelNode *, 4> store;
+ for (int i=0 ; i < (realTo-realFrom) ; ++i)
+ store.append(m_modelObjects[realFrom+realN+i]);
+ for (int i=0 ; i < realN ; ++i)
+ store.append(m_modelObjects[realFrom+i]);
+ for (int i=0 ; i < store.count() ; ++i)
+ m_modelObjects[realFrom+i] = store[i];
+
+ } else {
+ m_listModel->move(from, to, n);
+ }
+
+ emitItemsMoved(from, to, n);
+}
+
+/*!
+ \qmlmethod QtQuick2::ListModel::append(jsobject dict)
+
+ Adds a new item to the end of the list model, with the
+ values in \a dict.
+
+ \code
+ fruitModel.append({"cost": 5.95, "name":"Pizza"})
+ \endcode
+
+ \sa set() remove()
+*/
+void QQuickListModel::append(QQmlV8Function *args)
+{
+ if (args->Length() == 1) {
+ v8::Handle<v8::Value> arg = (*args)[0];
+
+ if (arg->IsArray()) {
+ v8::Handle<v8::Array> objectArray = v8::Handle<v8::Array>::Cast(arg);
+ int objectArrayLength = objectArray->Length();
+
+ int index = count();
+ for (int i=0 ; i < objectArrayLength ; ++i) {
+ v8::Handle<v8::Object> argObject = objectArray->Get(i)->ToObject();
+
+ if (m_dynamicRoles) {
+ m_modelObjects.append(DynamicRoleModelNode::create(args->engine()->variantMapFromJS(argObject), this));
+ } else {
+ m_listModel->append(argObject, args->engine());
+ }
+ }
+
+ emitItemsInserted(index, objectArrayLength);
+ } else if (arg->IsObject()) {
+ v8::Handle<v8::Object> argObject = arg->ToObject();
+
+ int index;
+
+ if (m_dynamicRoles) {
+ index = m_modelObjects.count();
+ m_modelObjects.append(DynamicRoleModelNode::create(args->engine()->variantMapFromJS(argObject), this));
+ } else {
+ index = m_listModel->append(argObject, args->engine());
+ }
+
+ emitItemsInserted(index, 1);
+ } else {
+ qmlInfo(this) << tr("append: value is not an object");
+ }
+ } else {
+ qmlInfo(this) << tr("append: value is not an object");
+ }
+}
+
+/*!
+ \qmlmethod object QtQuick2::ListModel::get(int index)
+
+ Returns the item at \a index in the list model. This allows the item
+ data to be accessed or modified from JavaScript:
+
+ \code
+ Component.onCompleted: {
+ fruitModel.append({"cost": 5.95, "name":"Jackfruit"});
+ console.log(fruitModel.get(0).cost);
+ fruitModel.get(0).cost = 10.95;
+ }
+ \endcode
+
+ The \a index must be an element in the list.
+
+ Note that properties of the returned object that are themselves objects
+ will also be models, and this get() method is used to access elements:
+
+ \code
+ fruitModel.append(..., "attributes":
+ [{"name":"spikes","value":"7mm"},
+ {"name":"color","value":"green"}]);
+ fruitModel.get(0).attributes.get(1).value; // == "green"
+ \endcode
+
+ \warning The returned object is not guaranteed to remain valid. It
+ should not be used in \l{Property Binding}{property bindings}.
+
+ \sa append()
+*/
+QQmlV8Handle QQuickListModel::get(int index) const
+{
+ v8::Handle<v8::Value> result = v8::Undefined();
+
+ if (index >= 0 && index < count()) {
+ QV8Engine *v8engine = engine();
+
+ if (m_dynamicRoles) {
+ DynamicRoleModelNode *object = m_modelObjects[index];
+ result = v8engine->newQObject(object);
+ } else {
+ ModelObject *object = m_listModel->getOrCreateModelObject(const_cast<QQuickListModel *>(this), index);
+ result = v8engine->newQObject(object);
+ }
+ }
+
+ return QQmlV8Handle::fromHandle(result);
+}
+
+/*!
+ \qmlmethod QtQuick2::ListModel::set(int index, jsobject dict)
+
+ Changes the item at \a index in the list model with the
+ values in \a dict. Properties not appearing in \a dict
+ are left unchanged.
+
+ \code
+ fruitModel.set(3, {"cost": 5.95, "name":"Pizza"})
+ \endcode
+
+ If \a index is equal to count() then a new item is appended to the
+ list. Otherwise, \a index must be an element in the list.
+
+ \sa append()
+*/
+void QQuickListModel::set(int index, const QQmlV8Handle &handle)
+{
+ v8::Handle<v8::Value> valuemap = handle.toHandle();
+
+ if (!valuemap->IsObject() || valuemap->IsArray()) {
+ qmlInfo(this) << tr("set: value is not an object");
+ return;
+ }
+ if (index > count() || index < 0) {
+ qmlInfo(this) << tr("set: index %1 out of range").arg(index);
+ return;
+ }
+
+ v8::Handle<v8::Object> object = valuemap->ToObject();
+
+ if (index == count()) {
+
+ if (m_dynamicRoles) {
+ m_modelObjects.append(DynamicRoleModelNode::create(engine()->variantMapFromJS(object), this));
+ } else {
+ m_listModel->insert(index, object, engine());
+ }
+
+ emitItemsInserted(index, 1);
+ } else {
+
+ QList<int> roles;
+
+ if (m_dynamicRoles) {
+ m_modelObjects[index]->updateValues(engine()->variantMapFromJS(object), roles);
+ } else {
+ m_listModel->set(index, object, &roles, engine());
+ }
+
+ if (roles.count())
+ emitItemsChanged(index, 1, roles);
+ }
+}
+
+/*!
+ \qmlmethod QtQuick2::ListModel::setProperty(int index, string property, variant value)
+
+ Changes the \a property of the item at \a index in the list model to \a value.
+
+ \code
+ fruitModel.setProperty(3, "cost", 5.95)
+ \endcode
+
+ The \a index must be an element in the list.
+
+ \sa append()
+*/
+void QQuickListModel::setProperty(int index, const QString& property, const QVariant& value)
+{
+ if (count() == 0 || index >= count() || index < 0) {
+ qmlInfo(this) << tr("set: index %1 out of range").arg(index);
+ return;
+ }
+
+ if (m_dynamicRoles) {
+ int roleIndex = m_roles.indexOf(property);
+ if (roleIndex == -1) {
+ roleIndex = m_roles.count();
+ m_roles.append(property);
+ }
+ if (m_modelObjects[index]->setValue(property.toUtf8(), value)) {
+ QList<int> roles;
+ roles << roleIndex;
+ emitItemsChanged(index, 1, roles);
+ }
+ } else {
+ int roleIndex = m_listModel->setOrCreateProperty(index, property, value);
+ if (roleIndex != -1) {
+
+ QList<int> roles;
+ roles << roleIndex;
+
+ emitItemsChanged(index, 1, roles);
+ }
+ }
+}
+
+/*!
+ \qmlmethod QtQuick2::ListModel::sync()
+
+ Writes any unsaved changes to the list model after it has been modified
+ from a worker script.
+*/
+void QQuickListModel::sync()
+{
+ // This is just a dummy method to make it look like sync() exists in
+ // ListModel (and not just QQuickListModelWorkerAgent) and to let
+ // us document sync().
+ qmlInfo(this) << "List sync() can only be called from a WorkerScript";
+}
+
+bool QQuickListModelParser::compileProperty(const QQmlCustomParserProperty &prop, QList<ListInstruction> &instr, QByteArray &data)
+{
+ QList<QVariant> values = prop.assignedValues();
+ for(int ii = 0; ii < values.count(); ++ii) {
+ const QVariant &value = values.at(ii);
+
+ if(value.userType() == qMetaTypeId<QQmlCustomParserNode>()) {
+ QQmlCustomParserNode node =
+ qvariant_cast<QQmlCustomParserNode>(value);
+
+ if (node.name() != listElementTypeName) {
+ const QMetaObject *mo = resolveType(node.name());
+ if (mo != &QQuickListElement::staticMetaObject) {
+ error(node, QQuickListModel::tr("ListElement: cannot contain nested elements"));
+ return false;
+ }
+ listElementTypeName = node.name(); // cache right name for next time
+ }
+
+ {
+ ListInstruction li;
+ li.type = ListInstruction::Push;
+ li.dataIdx = -1;
+ instr << li;
+ }
+
+ QList<QQmlCustomParserProperty> props = node.properties();
+ for(int jj = 0; jj < props.count(); ++jj) {
+ const QQmlCustomParserProperty &nodeProp = props.at(jj);
+ if (nodeProp.name().isEmpty()) {
+ error(nodeProp, QQuickListModel::tr("ListElement: cannot contain nested elements"));
+ return false;
+ }
+ if (nodeProp.name() == QStringLiteral("id")) {
+ error(nodeProp, QQuickListModel::tr("ListElement: cannot use reserved \"id\" property"));
+ return false;
+ }
+
+ ListInstruction li;
+ int ref = data.count();
+ data.append(nodeProp.name().toUtf8());
+ data.append('\0');
+ li.type = ListInstruction::Set;
+ li.dataIdx = ref;
+ instr << li;
+
+ if(!compileProperty(nodeProp, instr, data))
+ return false;
+
+ li.type = ListInstruction::Pop;
+ li.dataIdx = -1;
+ instr << li;
+ }
+
+ {
+ ListInstruction li;
+ li.type = ListInstruction::Pop;
+ li.dataIdx = -1;
+ instr << li;
+ }
+
+ } else {
+
+ QQmlScript::Variant variant =
+ qvariant_cast<QQmlScript::Variant>(value);
+
+ int ref = data.count();
+
+ QByteArray d;
+ d += char(variant.type()); // type tag
+ if (variant.isString()) {
+ d += variant.asString().toUtf8();
+ } else if (variant.isNumber()) {
+ d += QByteArray::number(variant.asNumber(),'g',20);
+ } else if (variant.isBoolean()) {
+ d += char(variant.asBoolean());
+ } else if (variant.isScript()) {
+ if (definesEmptyList(variant.asScript())) {
+ d[0] = char(QQmlScript::Variant::Invalid); // marks empty list
+ } else {
+ QByteArray script = variant.asScript().toUtf8();
+ int v = evaluateEnum(script);
+ if (v<0) {
+ using namespace QQmlJS;
+ AST::Node *node = variant.asAST();
+ AST::StringLiteral *literal = 0;
+ if (AST::CallExpression *callExpr = AST::cast<AST::CallExpression *>(node)) {
+ if (AST::IdentifierExpression *idExpr = AST::cast<AST::IdentifierExpression *>(callExpr->base)) {
+ if (idExpr->name == QLatin1String("QT_TR_NOOP") || idExpr->name == QLatin1String("QT_TRID_NOOP")) {
+ if (callExpr->arguments && !callExpr->arguments->next)
+ literal = AST::cast<AST::StringLiteral *>(callExpr->arguments->expression);
+ if (!literal) {
+ error(prop, QQuickListModel::tr("ListElement: improperly specified %1").arg(idExpr->name.toString()));
+ return false;
+ }
+ } else if (idExpr->name == QLatin1String("QT_TRANSLATE_NOOP")) {
+ if (callExpr->arguments && callExpr->arguments->next && !callExpr->arguments->next->next)
+ literal = AST::cast<AST::StringLiteral *>(callExpr->arguments->next->expression);
+ if (!literal) {
+ error(prop, QQuickListModel::tr("ListElement: improperly specified QT_TRANSLATE_NOOP"));
+ return false;
+ }
+ }
+ }
+ }
+
+ if (literal) {
+ d[0] = char(QQmlScript::Variant::String);
+ d += literal->value.toUtf8();
+ } else {
+ error(prop, QQuickListModel::tr("ListElement: cannot use script for property value"));
+ return false;
+ }
+ } else {
+ d[0] = char(QQmlScript::Variant::Number);
+ d += QByteArray::number(v);
+ }
+ }
+ }
+ d.append('\0');
+ data.append(d);
+
+ ListInstruction li;
+ li.type = ListInstruction::Value;
+ li.dataIdx = ref;
+ instr << li;
+ }
+ }
+
+ return true;
+}
+
+QByteArray QQuickListModelParser::compile(const QList<QQmlCustomParserProperty> &customProps)
+{
+ QList<ListInstruction> instr;
+ QByteArray data;
+ listElementTypeName = QString(); // unknown
+
+ for(int ii = 0; ii < customProps.count(); ++ii) {
+ const QQmlCustomParserProperty &prop = customProps.at(ii);
+ if(!prop.name().isEmpty()) { // isn't default property
+ error(prop, QQuickListModel::tr("ListModel: undefined property '%1'").arg(prop.name()));
+ return QByteArray();
+ }
+
+ if(!compileProperty(prop, instr, data)) {
+ return QByteArray();
+ }
+ }
+
+ int size = sizeof(ListModelData) +
+ instr.count() * sizeof(ListInstruction) +
+ data.count();
+
+ QByteArray rv;
+ rv.resize(size);
+
+ ListModelData *lmd = (ListModelData *)rv.data();
+ lmd->dataOffset = sizeof(ListModelData) +
+ instr.count() * sizeof(ListInstruction);
+ lmd->instrCount = instr.count();
+ for (int ii = 0; ii < instr.count(); ++ii)
+ lmd->instructions()[ii] = instr.at(ii);
+ ::memcpy(rv.data() + lmd->dataOffset, data.constData(), data.count());
+
+ return rv;
+}
+
+void QQuickListModelParser::setCustomData(QObject *obj, const QByteArray &d)
+{
+ QQuickListModel *rv = static_cast<QQuickListModel *>(obj);
+
+ QV8Engine *engine = QQmlEnginePrivate::getV8Engine(qmlEngine(rv));
+ rv->m_engine = engine;
+
+ const ListModelData *lmd = (const ListModelData *)d.constData();
+ const char *data = ((const char *)lmd) + lmd->dataOffset;
+
+ QStack<DataStackElement> stack;
+
+ for (int ii = 0; ii < lmd->instrCount; ++ii) {
+ const ListInstruction &instr = lmd->instructions()[ii];
+
+ switch(instr.type) {
+ case ListInstruction::Push:
+ {
+ Q_ASSERT(!rv->m_dynamicRoles);
+
+ ListModel *subModel = 0;
+
+ if (stack.count() == 0) {
+ subModel = rv->m_listModel;
+ } else {
+ const DataStackElement &e0 = stack.at(stack.size() - 1);
+ DataStackElement &e1 = stack[stack.size() - 2];
+
+ const ListLayout::Role &role = e1.model->getOrCreateListRole(e0.name);
+ if (role.type == ListLayout::Role::List) {
+ subModel = e1.model->getListProperty(e1.elementIndex, role);
+
+ if (subModel == 0) {
+ subModel = new ListModel(role.subLayout, 0, -1);
+ QVariant vModel = QVariant::fromValue(subModel);
+ e1.model->setOrCreateProperty(e1.elementIndex, e0.name, vModel);
+ }
+ }
+ }
+
+ DataStackElement e;
+ e.model = subModel;
+ e.elementIndex = subModel ? subModel->appendElement() : -1;
+ stack.push(e);
+ }
+ break;
+
+ case ListInstruction::Pop:
+ stack.pop();
+ break;
+
+ case ListInstruction::Value:
+ {
+ const DataStackElement &e0 = stack.at(stack.size() - 1);
+ DataStackElement &e1 = stack[stack.size() - 2];
+
+ QString name = e0.name;
+ QVariant value;
+
+ switch (QQmlScript::Variant::Type(data[instr.dataIdx])) {
+ case QQmlScript::Variant::Invalid:
+ {
+ const ListLayout::Role &role = e1.model->getOrCreateListRole(e0.name);
+ ListModel *emptyModel = new ListModel(role.subLayout, 0, -1);
+ value = QVariant::fromValue(emptyModel);
+ }
+ break;
+ case QQmlScript::Variant::Boolean:
+ value = bool(data[1 + instr.dataIdx]);
+ break;
+ case QQmlScript::Variant::Number:
+ value = QByteArray(data + 1 + instr.dataIdx).toDouble();
+ break;
+ case QQmlScript::Variant::String:
+ value = QString::fromUtf8(data + 1 + instr.dataIdx);
+ break;
+ default:
+ Q_ASSERT("Format error in ListInstruction");
+ }
+
+ e1.model->setOrCreateProperty(e1.elementIndex, name, value);
+ }
+ break;
+
+ case ListInstruction::Set:
+ {
+ DataStackElement e;
+ e.name = QString::fromUtf8(data + instr.dataIdx);
+ stack.push(e);
+ }
+ break;
+ }
+ }
+}
+
+bool QQuickListModelParser::definesEmptyList(const QString &s)
+{
+ if (s.startsWith(QLatin1Char('[')) && s.endsWith(QLatin1Char(']'))) {
+ for (int i=1; i<s.length()-1; i++) {
+ if (!s[i].isSpace())
+ return false;
+ }
+ return true;
+ }
+ return false;
+}
+
+
+/*!
+ \qmlclass ListElement QQuickListElement
+ \inqmlmodule QtQuick 2
+ \ingroup qml-working-with-data
+ \brief The ListElement element defines a data item in a ListModel.
+
+ List elements are defined inside ListModel definitions, and represent items in a
+ list that will be displayed using ListView or \l Repeater items.
+
+ List elements are defined like other QML elements except that they contain
+ a collection of \e role definitions instead of properties. Using the same
+ syntax as property definitions, roles both define how the data is accessed
+ and include the data itself.
+
+ The names used for roles must begin with a lower-case letter and should be
+ common to all elements in a given model. Values must be simple constants; either
+ strings (quoted and optionally within a call to QT_TR_NOOP), boolean values
+ (true, false), numbers, or enumeration values (such as AlignText.AlignHCenter).
+
+ \section1 Referencing Roles
+
+ The role names are used by delegates to obtain data from list elements.
+ Each role name is accessible in the delegate's scope, and refers to the
+ corresponding role in the current element. Where a role name would be
+ ambiguous to use, it can be accessed via the \l{ListView::}{model}
+ property (e.g., \c{model.cost} instead of \c{cost}).
+
+ \section1 Example Usage
+
+ The following model defines a series of list elements, each of which
+ contain "name" and "cost" roles and their associated values.
+
+ \snippet doc/src/snippets/qml/qml-data-models/listelements.qml model
+
+ The delegate obtains the name and cost for each element by simply referring
+ to \c name and \c cost:
+
+ \snippet doc/src/snippets/qml/qml-data-models/listelements.qml view
+
+ \sa ListModel
+*/
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/qquicklistmodel_p.h b/src/qml/qml/qquicklistmodel_p.h
new file mode 100644
index 0000000000..2941de9148
--- /dev/null
+++ b/src/qml/qml/qquicklistmodel_p.h
@@ -0,0 +1,199 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKLISTMODEL_H
+#define QQUICKLISTMODEL_H
+
+#include <qqml.h>
+#include <private/qqmlcustomparser_p.h>
+
+#include <QtCore/QObject>
+#include <QtCore/QStringList>
+#include <QtCore/QHash>
+#include <QtCore/QList>
+#include <QtCore/QVariant>
+#include "qlistmodelinterface_p.h"
+
+#include <private/qv8engine_p.h>
+#include <private/qpodvector_p.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+
+class QQuickListModelWorkerAgent;
+class ListModel;
+class ListLayout;
+
+class Q_QML_PRIVATE_EXPORT QQuickListModel : public QListModelInterface
+{
+ Q_OBJECT
+ Q_PROPERTY(int count READ count NOTIFY countChanged)
+ Q_PROPERTY(bool dynamicRoles READ dynamicRoles WRITE setDynamicRoles)
+
+public:
+ QQuickListModel(QObject *parent=0);
+ ~QQuickListModel();
+
+ virtual QList<int> roles() const;
+ virtual QString toString(int role) const;
+ virtual int count() const;
+ virtual QVariant data(int index, int role) const;
+
+ Q_INVOKABLE void clear();
+ Q_INVOKABLE void remove(QQmlV8Function *args);
+ Q_INVOKABLE void append(QQmlV8Function *args);
+ Q_INVOKABLE void insert(QQmlV8Function *args);
+ Q_INVOKABLE QQmlV8Handle get(int index) const;
+ Q_INVOKABLE void set(int index, const QQmlV8Handle &);
+ Q_INVOKABLE void setProperty(int index, const QString& property, const QVariant& value);
+ Q_INVOKABLE void move(int from, int to, int count);
+ Q_INVOKABLE void sync();
+
+ QQuickListModelWorkerAgent *agent();
+
+ bool dynamicRoles() const { return m_dynamicRoles; }
+ void setDynamicRoles(bool enableDynamicRoles);
+
+Q_SIGNALS:
+ void countChanged();
+
+private:
+ friend class QQuickListModelParser;
+ friend class QQuickListModelWorkerAgent;
+ friend class ModelObject;
+ friend class ModelNodeMetaObject;
+ friend class ListModel;
+ friend class ListElement;
+ friend class DynamicRoleModelNode;
+ friend class DynamicRoleModelNodeMetaObject;
+
+ // Constructs a flat list model for a worker agent
+ QQuickListModel(QQuickListModel *orig, QQuickListModelWorkerAgent *agent);
+ QQuickListModel(const QQuickListModel *owner, ListModel *data, QV8Engine *eng, QObject *parent=0);
+
+ QV8Engine *engine() const;
+
+ inline bool canMove(int from, int to, int n) const { return !(from+n > count() || to+n > count() || from < 0 || to < 0 || n < 0); }
+
+ QQuickListModelWorkerAgent *m_agent;
+ mutable QV8Engine *m_engine;
+ bool m_mainThread;
+ bool m_primary;
+
+ bool m_dynamicRoles;
+
+ ListLayout *m_layout;
+ ListModel *m_listModel;
+
+ QVector<class DynamicRoleModelNode *> m_modelObjects;
+ QVector<QString> m_roles;
+ int m_uid;
+
+ struct ElementSync
+ {
+ ElementSync() : src(0), target(0) {}
+
+ DynamicRoleModelNode *src;
+ DynamicRoleModelNode *target;
+ };
+
+ int getUid() const { return m_uid; }
+
+ static void sync(QQuickListModel *src, QQuickListModel *target, QHash<int, QQuickListModel *> *targetModelHash);
+ static QQuickListModel *createWithOwner(QQuickListModel *newOwner);
+
+ void emitItemsChanged(int index, int count, const QList<int> &roles);
+ void emitItemsRemoved(int index, int count);
+ void emitItemsInserted(int index, int count);
+ void emitItemsMoved(int from, int to, int n);
+};
+
+// ### FIXME
+class QQuickListElement : public QObject
+{
+Q_OBJECT
+};
+
+class QQuickListModelParser : public QQmlCustomParser
+{
+public:
+ QQuickListModelParser() : QQmlCustomParser(QQmlCustomParser::AcceptsSignalHandlers) {}
+ QByteArray compile(const QList<QQmlCustomParserProperty> &);
+ void setCustomData(QObject *, const QByteArray &);
+
+private:
+ struct ListInstruction
+ {
+ enum { Push, Pop, Value, Set } type;
+ int dataIdx;
+ };
+ struct ListModelData
+ {
+ int dataOffset;
+ int instrCount;
+ ListInstruction *instructions() const;
+ };
+ bool compileProperty(const QQmlCustomParserProperty &prop, QList<ListInstruction> &instr, QByteArray &data);
+
+ bool definesEmptyList(const QString &);
+
+ QString listElementTypeName;
+
+ struct DataStackElement
+ {
+ DataStackElement() : model(0), elementIndex(0) {}
+
+ QString name;
+ ListModel *model;
+ int elementIndex;
+ };
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickListModel)
+QML_DECLARE_TYPE(QQuickListElement)
+
+QT_END_HEADER
+
+#endif // QQUICKLISTMODEL_H
diff --git a/src/qml/qml/qquicklistmodel_p_p.h b/src/qml/qml/qquicklistmodel_p_p.h
new file mode 100644
index 0000000000..f9256c9f0a
--- /dev/null
+++ b/src/qml/qml/qquicklistmodel_p_p.h
@@ -0,0 +1,378 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKLISTMODEL_P_P_H
+#define QQUICKLISTMODEL_P_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qquicklistmodel_p.h"
+#include <private/qqmlengine_p.h>
+#include "qqmlopenmetaobject_p.h"
+#include <qqml.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+
+class DynamicRoleModelNode;
+
+class DynamicRoleModelNodeMetaObject : public QQmlOpenMetaObject
+{
+public:
+ DynamicRoleModelNodeMetaObject(DynamicRoleModelNode *object);
+ ~DynamicRoleModelNodeMetaObject();
+
+ bool m_enabled;
+
+protected:
+ void propertyWrite(int index);
+ void propertyWritten(int index);
+
+private:
+ DynamicRoleModelNode *m_owner;
+};
+
+class DynamicRoleModelNode : public QObject
+{
+ Q_OBJECT
+public:
+ DynamicRoleModelNode(QQuickListModel *owner, int uid);
+
+ static DynamicRoleModelNode *create(const QVariantMap &obj, QQuickListModel *owner);
+
+ void updateValues(const QVariantMap &object, QList<int> &roles);
+
+ QVariant getValue(const QString &name)
+ {
+ return m_meta->value(name.toUtf8());
+ }
+
+ bool setValue(const QByteArray &name, const QVariant &val)
+ {
+ return m_meta->setValue(name, val);
+ }
+
+ void setNodeUpdatesEnabled(bool enable)
+ {
+ m_meta->m_enabled = enable;
+ }
+
+ int getUid() const
+ {
+ return m_uid;
+ }
+
+ static void sync(DynamicRoleModelNode *src, DynamicRoleModelNode *target, QHash<int, QQuickListModel *> *targetModelHash);
+
+private:
+ QQuickListModel *m_owner;
+ int m_uid;
+ DynamicRoleModelNodeMetaObject *m_meta;
+
+ friend class DynamicRoleModelNodeMetaObject;
+};
+
+class ModelObject;
+
+class ModelNodeMetaObject : public QQmlOpenMetaObject
+{
+public:
+ ModelNodeMetaObject(ModelObject *object);
+ ~ModelNodeMetaObject();
+
+ bool m_enabled;
+
+protected:
+ void propertyWritten(int index);
+
+private:
+
+ ModelObject *m_obj;
+};
+
+class ModelObject : public QObject
+{
+ Q_OBJECT
+public:
+ ModelObject(QQuickListModel *model, int elementIndex);
+
+ void setValue(const QByteArray &name, const QVariant &val, bool force)
+ {
+ if (force) {
+ QVariant existingValue = m_meta->value(name);
+ if (existingValue.isValid()) {
+ (*m_meta)[name] = QVariant();
+ }
+ }
+ m_meta->setValue(name, val);
+ }
+
+ void setNodeUpdatesEnabled(bool enable)
+ {
+ m_meta->m_enabled = enable;
+ }
+
+ void updateValues();
+ void updateValues(const QList<int> &roles);
+
+ QQuickListModel *m_model;
+ int m_elementIndex;
+
+private:
+ ModelNodeMetaObject *m_meta;
+};
+
+class ListLayout
+{
+public:
+ ListLayout() : currentBlock(0), currentBlockOffset(0) {}
+ ListLayout(const ListLayout *other);
+ ~ListLayout();
+
+ class Role
+ {
+ public:
+
+ Role() : type(Invalid), blockIndex(-1), blockOffset(-1), index(-1), subLayout(0) {}
+ explicit Role(const Role *other);
+ ~Role();
+
+ // This enum must be kept in sync with the roleTypeNames variable in qdeclarativelistmodel.cpp
+ enum DataType
+ {
+ Invalid = -1,
+
+ String,
+ Number,
+ Bool,
+ List,
+ QObject,
+ VariantMap,
+
+ MaxDataType
+ };
+
+ QString name;
+ DataType type;
+ int blockIndex;
+ int blockOffset;
+ int index;
+ ListLayout *subLayout;
+ };
+
+ const Role *getRoleOrCreate(const QString &key, const QVariant &data);
+ const Role &getRoleOrCreate(v8::Handle<v8::String> key, Role::DataType type);
+ const Role &getRoleOrCreate(const QString &key, Role::DataType type);
+
+ const Role &getExistingRole(int index) { return *roles.at(index); }
+ const Role *getExistingRole(const QString &key);
+ const Role *getExistingRole(v8::Handle<v8::String> key);
+
+ int roleCount() const { return roles.count(); }
+
+ static void sync(ListLayout *src, ListLayout *target);
+
+private:
+ const Role &createRole(const QString &key, Role::DataType type);
+
+ int currentBlock;
+ int currentBlockOffset;
+ QVector<Role *> roles;
+ QStringHash<Role *> roleHash;
+};
+
+class ListElement
+{
+public:
+
+ ListElement();
+ ListElement(int existingUid);
+ ~ListElement();
+
+ static void sync(ListElement *src, ListLayout *srcLayout, ListElement *target, ListLayout *targetLayout, QHash<int, ListModel *> *targetModelHash);
+
+ enum
+ {
+ BLOCK_SIZE = 64 - sizeof(int) - sizeof(ListElement *) - sizeof(ModelObject *)
+ };
+
+private:
+
+ void destroy(ListLayout *layout);
+
+ int setVariantProperty(const ListLayout::Role &role, const QVariant &d);
+
+ int setJsProperty(const ListLayout::Role &role, v8::Handle<v8::Value> d, QV8Engine *eng);
+
+ int setStringProperty(const ListLayout::Role &role, const QString &s);
+ int setDoubleProperty(const ListLayout::Role &role, double n);
+ int setBoolProperty(const ListLayout::Role &role, bool b);
+ int setListProperty(const ListLayout::Role &role, ListModel *m);
+ int setQObjectProperty(const ListLayout::Role &role, QObject *o);
+ int setVariantMapProperty(const ListLayout::Role &role, v8::Handle<v8::Object> o, QV8Engine *eng);
+ int setVariantMapProperty(const ListLayout::Role &role, QVariantMap *m);
+
+ void setStringPropertyFast(const ListLayout::Role &role, const QString &s);
+ void setDoublePropertyFast(const ListLayout::Role &role, double n);
+ void setBoolPropertyFast(const ListLayout::Role &role, bool b);
+ void setQObjectPropertyFast(const ListLayout::Role &role, QObject *o);
+ void setListPropertyFast(const ListLayout::Role &role, ListModel *m);
+ void setVariantMapFast(const ListLayout::Role &role, v8::Handle<v8::Object> o, QV8Engine *eng);
+
+ void clearProperty(const ListLayout::Role &role);
+
+ QVariant getProperty(const ListLayout::Role &role, const QQuickListModel *owner, QV8Engine *eng);
+ ListModel *getListProperty(const ListLayout::Role &role);
+ QString *getStringProperty(const ListLayout::Role &role);
+ QObject *getQObjectProperty(const ListLayout::Role &role);
+ QQmlGuard<QObject> *getGuardProperty(const ListLayout::Role &role);
+ QVariantMap *getVariantMapProperty(const ListLayout::Role &role);
+
+ inline char *getPropertyMemory(const ListLayout::Role &role);
+
+ int getUid() const { return uid; }
+
+ char data[BLOCK_SIZE];
+ ListElement *next;
+
+ int uid;
+ ModelObject *m_objectCache;
+
+ friend class ListModel;
+};
+
+class ListModel
+{
+public:
+
+ ListModel(ListLayout *layout, QQuickListModel *modelCache, int uid);
+ ~ListModel() {}
+
+ void destroy();
+
+ int setOrCreateProperty(int elementIndex, const QString &key, const QVariant &data);
+ int setExistingProperty(int uid, const QString &key, v8::Handle<v8::Value> data, QV8Engine *eng);
+
+ QVariant getProperty(int elementIndex, int roleIndex, const QQuickListModel *owner, QV8Engine *eng);
+ ListModel *getListProperty(int elementIndex, const ListLayout::Role &role);
+
+ int roleCount() const
+ {
+ return m_layout->roleCount();
+ }
+
+ const ListLayout::Role &getExistingRole(int index)
+ {
+ return m_layout->getExistingRole(index);
+ }
+
+ const ListLayout::Role &getOrCreateListRole(const QString &name)
+ {
+ return m_layout->getRoleOrCreate(name, ListLayout::Role::List);
+ }
+
+ int elementCount() const
+ {
+ return elements.count();
+ }
+
+ void set(int elementIndex, v8::Handle<v8::Object> object, QList<int> *roles, QV8Engine *eng);
+ void set(int elementIndex, v8::Handle<v8::Object> object, QV8Engine *eng);
+
+ int append(v8::Handle<v8::Object> object, QV8Engine *eng);
+ void insert(int elementIndex, v8::Handle<v8::Object> object, QV8Engine *eng);
+
+ void clear();
+ void remove(int index, int count);
+
+ int appendElement();
+ void insertElement(int index);
+
+ void move(int from, int to, int n);
+
+ int getUid() const { return m_uid; }
+
+ static void sync(ListModel *src, ListModel *target, QHash<int, ListModel *> *srcModelHash);
+
+ ModelObject *getOrCreateModelObject(QQuickListModel *model, int elementIndex);
+
+private:
+ QPODVector<ListElement *, 4> elements;
+ ListLayout *m_layout;
+ int m_uid;
+
+ QQuickListModel *m_modelCache;
+
+ struct ElementSync
+ {
+ ElementSync() : src(0), target(0) {}
+
+ ListElement *src;
+ ListElement *target;
+ };
+
+ void newElement(int index);
+
+ void updateCacheIndices();
+
+ friend class ListElement;
+ friend class QQuickListModelWorkerAgent;
+};
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(ListModel *);
+
+QT_END_HEADER
+
+#endif // QQUICKLISTMODEL_P_P_H
+
diff --git a/src/qml/qml/qquicklistmodelworkeragent.cpp b/src/qml/qml/qquicklistmodelworkeragent.cpp
new file mode 100644
index 0000000000..c50b348a4a
--- /dev/null
+++ b/src/qml/qml/qquicklistmodelworkeragent.cpp
@@ -0,0 +1,246 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquicklistmodelworkeragent_p.h"
+#include "qquicklistmodel_p_p.h"
+#include <private/qqmldata_p.h>
+#include <private/qqmlengine_p.h>
+#include <qqmlinfo.h>
+
+#include <QtCore/qcoreevent.h>
+#include <QtCore/qcoreapplication.h>
+#include <QtCore/qdebug.h>
+
+
+QT_BEGIN_NAMESPACE
+
+
+void QQuickListModelWorkerAgent::Data::clearChange(int uid)
+{
+ for (int i=0 ; i < changes.count() ; ++i) {
+ if (changes[i].modelUid == uid) {
+ changes.removeAt(i);
+ --i;
+ }
+ }
+}
+
+void QQuickListModelWorkerAgent::Data::insertChange(int uid, int index, int count)
+{
+ Change c = { uid, Change::Inserted, index, count, 0, QList<int>() };
+ changes << c;
+}
+
+void QQuickListModelWorkerAgent::Data::removeChange(int uid, int index, int count)
+{
+ Change c = { uid, Change::Removed, index, count, 0, QList<int>() };
+ changes << c;
+}
+
+void QQuickListModelWorkerAgent::Data::moveChange(int uid, int index, int count, int to)
+{
+ Change c = { uid, Change::Moved, index, count, to, QList<int>() };
+ changes << c;
+}
+
+void QQuickListModelWorkerAgent::Data::changedChange(int uid, int index, int count, const QList<int> &roles)
+{
+ Change c = { uid, Change::Changed, index, count, 0, roles };
+ changes << c;
+}
+
+QQuickListModelWorkerAgent::QQuickListModelWorkerAgent(QQuickListModel *model)
+: m_ref(1), m_orig(model), m_copy(new QQuickListModel(model, this))
+{
+}
+
+QQuickListModelWorkerAgent::~QQuickListModelWorkerAgent()
+{
+ mutex.lock();
+ syncDone.wakeAll();
+ mutex.unlock();
+}
+
+void QQuickListModelWorkerAgent::setV8Engine(QV8Engine *eng)
+{
+ m_copy->m_engine = eng;
+}
+
+void QQuickListModelWorkerAgent::addref()
+{
+ m_ref.ref();
+}
+
+void QQuickListModelWorkerAgent::release()
+{
+ bool del = !m_ref.deref();
+
+ if (del)
+ deleteLater();
+}
+
+void QQuickListModelWorkerAgent::modelDestroyed()
+{
+ m_orig = 0;
+}
+
+int QQuickListModelWorkerAgent::count() const
+{
+ return m_copy->count();
+}
+
+void QQuickListModelWorkerAgent::clear()
+{
+ m_copy->clear();
+}
+
+void QQuickListModelWorkerAgent::remove(QQmlV8Function *args)
+{
+ m_copy->remove(args);
+}
+
+void QQuickListModelWorkerAgent::append(QQmlV8Function *args)
+{
+ m_copy->append(args);
+}
+
+void QQuickListModelWorkerAgent::insert(QQmlV8Function *args)
+{
+ m_copy->insert(args);
+}
+
+QQmlV8Handle QQuickListModelWorkerAgent::get(int index) const
+{
+ return m_copy->get(index);
+}
+
+void QQuickListModelWorkerAgent::set(int index, const QQmlV8Handle &value)
+{
+ m_copy->set(index, value);
+}
+
+void QQuickListModelWorkerAgent::setProperty(int index, const QString& property, const QVariant& value)
+{
+ m_copy->setProperty(index, property, value);
+}
+
+void QQuickListModelWorkerAgent::move(int from, int to, int count)
+{
+ m_copy->move(from, to, count);
+}
+
+void QQuickListModelWorkerAgent::sync()
+{
+ Sync *s = new Sync;
+ s->data = data;
+ s->list = m_copy;
+ data.changes.clear();
+
+ mutex.lock();
+ QCoreApplication::postEvent(this, s);
+ syncDone.wait(&mutex);
+ mutex.unlock();
+}
+
+bool QQuickListModelWorkerAgent::event(QEvent *e)
+{
+ if (e->type() == QEvent::User) {
+ bool cc = false;
+ QMutexLocker locker(&mutex);
+ if (m_orig) {
+ Sync *s = static_cast<Sync *>(e);
+ const QList<Change> &changes = s->data.changes;
+
+ cc = m_orig->count() != s->list->count();
+
+ QHash<int, QQuickListModel *> targetModelDynamicHash;
+ QHash<int, ListModel *> targetModelStaticHash;
+
+ Q_ASSERT(m_orig->m_dynamicRoles == s->list->m_dynamicRoles);
+ if (m_orig->m_dynamicRoles)
+ QQuickListModel::sync(s->list, m_orig, &targetModelDynamicHash);
+ else
+ ListModel::sync(s->list->m_listModel, m_orig->m_listModel, &targetModelStaticHash);
+
+ for (int ii = 0; ii < changes.count(); ++ii) {
+ const Change &change = changes.at(ii);
+
+ QQuickListModel *model = 0;
+ if (m_orig->m_dynamicRoles) {
+ model = targetModelDynamicHash.value(change.modelUid);
+ } else {
+ ListModel *lm = targetModelStaticHash.value(change.modelUid);
+ if (lm)
+ model = lm->m_modelCache;
+ }
+
+ if (model) {
+ switch (change.type) {
+ case Change::Inserted:
+ emit model->itemsInserted(change.index, change.count);
+ break;
+ case Change::Removed:
+ emit model->itemsRemoved(change.index, change.count);
+ break;
+ case Change::Moved:
+ emit model->itemsMoved(change.index, change.to, change.count);
+ break;
+ case Change::Changed:
+ emit model->itemsChanged(change.index, change.count, change.roles);
+ break;
+ }
+ }
+ }
+ }
+
+ syncDone.wakeAll();
+ locker.unlock();
+
+ if (cc)
+ emit m_orig->countChanged();
+ return true;
+ }
+
+ return QObject::event(e);
+}
+
+QT_END_NAMESPACE
+
diff --git a/src/qml/qml/qquicklistmodelworkeragent_p.h b/src/qml/qml/qquicklistmodelworkeragent_p.h
new file mode 100644
index 0000000000..cf2ef45c16
--- /dev/null
+++ b/src/qml/qml/qquicklistmodelworkeragent_p.h
@@ -0,0 +1,161 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKLISTMODELWORKERAGENT_P_H
+#define QQUICKLISTMODELWORKERAGENT_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <qqml.h>
+
+#include <QtGui/qevent.h>
+#include <QMutex>
+#include <QWaitCondition>
+
+#include <private/qv8engine_p.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+
+class QQuickListModel;
+
+class QQuickListModelWorkerAgent : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(int count READ count)
+
+public:
+ QQuickListModelWorkerAgent(QQuickListModel *);
+ ~QQuickListModelWorkerAgent();
+ void setV8Engine(QV8Engine *eng);
+
+ void addref();
+ void release();
+
+ int count() const;
+
+ Q_INVOKABLE void clear();
+ Q_INVOKABLE void remove(QQmlV8Function *args);
+ Q_INVOKABLE void append(QQmlV8Function *args);
+ Q_INVOKABLE void insert(QQmlV8Function *args);
+ Q_INVOKABLE QQmlV8Handle get(int index) const;
+ Q_INVOKABLE void set(int index, const QQmlV8Handle &);
+ Q_INVOKABLE void setProperty(int index, const QString& property, const QVariant& value);
+ Q_INVOKABLE void move(int from, int to, int count);
+ Q_INVOKABLE void sync();
+
+ struct VariantRef
+ {
+ VariantRef() : a(0) {}
+ VariantRef(const VariantRef &r) : a(r.a) { if (a) a->addref(); }
+ VariantRef(QQuickListModelWorkerAgent *_a) : a(_a) { if (a) a->addref(); }
+ ~VariantRef() { if (a) a->release(); }
+
+ VariantRef &operator=(const VariantRef &o) {
+ if (o.a) o.a->addref();
+ if (a) a->release(); a = o.a;
+ return *this;
+ }
+
+ QQuickListModelWorkerAgent *a;
+ };
+ void modelDestroyed();
+protected:
+ virtual bool event(QEvent *);
+
+private:
+ friend class QQuickWorkerScriptEnginePrivate;
+ friend class QQuickListModel;
+
+ struct Change
+ {
+ int modelUid;
+ enum { Inserted, Removed, Moved, Changed } type;
+ int index; // Inserted/Removed/Moved/Changed
+ int count; // Inserted/Removed/Moved/Changed
+ int to; // Moved
+ QList<int> roles;
+ };
+
+ struct Data
+ {
+ QList<Change> changes;
+
+ void clearChange(int uid);
+ void insertChange(int uid, int index, int count);
+ void removeChange(int uid, int index, int count);
+ void moveChange(int uid, int index, int count, int to);
+ void changedChange(int uid, int index, int count, const QList<int> &roles);
+ };
+ Data data;
+
+ struct Sync : public QEvent {
+ Sync() : QEvent(QEvent::User) {}
+ Data data;
+ QQuickListModel *list;
+ };
+
+ QAtomicInt m_ref;
+ QQuickListModel *m_orig;
+ QQuickListModel *m_copy;
+ QMutex mutex;
+ QWaitCondition syncDone;
+};
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(QQuickListModelWorkerAgent::VariantRef)
+
+QT_END_HEADER
+
+#endif // QQUICKLISTMODELWORKERAGENT_P_H
+
diff --git a/src/qml/qml/qquickworkerscript.cpp b/src/qml/qml/qquickworkerscript.cpp
new file mode 100644
index 0000000000..f91aa28509
--- /dev/null
+++ b/src/qml/qml/qquickworkerscript.cpp
@@ -0,0 +1,730 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickworkerscript_p.h"
+#include "qquicklistmodel_p.h"
+#include "qquicklistmodelworkeragent_p.h"
+#include "qqmlengine_p.h"
+#include "qqmlexpression_p.h"
+
+#include <QtCore/qcoreevent.h>
+#include <QtCore/qcoreapplication.h>
+#include <QtCore/qdebug.h>
+#include <QtQml/qjsengine.h>
+#include <QtCore/qmutex.h>
+#include <QtCore/qwaitcondition.h>
+#include <QtCore/qfile.h>
+#include <QtCore/qdatetime.h>
+#include <QtNetwork/qnetworkaccessmanager.h>
+#include <QtQml/qqmlinfo.h>
+#include "qqmlnetworkaccessmanagerfactory.h"
+
+#include <private/qv8engine_p.h>
+#include <private/qv8worker_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class WorkerDataEvent : public QEvent
+{
+public:
+ enum Type { WorkerData = QEvent::User };
+
+ WorkerDataEvent(int workerId, const QByteArray &data);
+ virtual ~WorkerDataEvent();
+
+ int workerId() const;
+ QByteArray data() const;
+
+private:
+ int m_id;
+ QByteArray m_data;
+};
+
+class WorkerLoadEvent : public QEvent
+{
+public:
+ enum Type { WorkerLoad = WorkerDataEvent::WorkerData + 1 };
+
+ WorkerLoadEvent(int workerId, const QUrl &url);
+
+ int workerId() const;
+ QUrl url() const;
+
+private:
+ int m_id;
+ QUrl m_url;
+};
+
+class WorkerRemoveEvent : public QEvent
+{
+public:
+ enum Type { WorkerRemove = WorkerLoadEvent::WorkerLoad + 1 };
+
+ WorkerRemoveEvent(int workerId);
+
+ int workerId() const;
+
+private:
+ int m_id;
+};
+
+class WorkerErrorEvent : public QEvent
+{
+public:
+ enum Type { WorkerError = WorkerRemoveEvent::WorkerRemove + 1 };
+
+ WorkerErrorEvent(const QQmlError &error);
+
+ QQmlError error() const;
+
+private:
+ QQmlError m_error;
+};
+
+class QQuickWorkerScriptEnginePrivate : public QObject
+{
+ Q_OBJECT
+public:
+ enum WorkerEventTypes {
+ WorkerDestroyEvent = QEvent::User + 100
+ };
+
+ QQuickWorkerScriptEnginePrivate(QQmlEngine *eng);
+
+ class WorkerEngine : public QV8Engine
+ {
+ public:
+ WorkerEngine(QQuickWorkerScriptEnginePrivate *parent);
+ ~WorkerEngine();
+
+ void init();
+ virtual QNetworkAccessManager *networkAccessManager();
+
+ QQuickWorkerScriptEnginePrivate *p;
+
+ v8::Local<v8::Function> sendFunction(int id);
+ void callOnMessage(v8::Handle<v8::Object> object, v8::Handle<v8::Value> arg);
+ private:
+ v8::Persistent<v8::Function> onmessage;
+ v8::Persistent<v8::Function> createsend;
+ QNetworkAccessManager *accessManager;
+ };
+
+ WorkerEngine *workerEngine;
+ static QQuickWorkerScriptEnginePrivate *get(QV8Engine *e) {
+ return static_cast<WorkerEngine *>(e)->p;
+ }
+
+ QQmlEngine *qmlengine;
+
+ QMutex m_lock;
+ QWaitCondition m_wait;
+
+ struct WorkerScript {
+ WorkerScript();
+ ~WorkerScript();
+
+ int id;
+ QUrl source;
+ bool initialized;
+ QQuickWorkerScript *owner;
+ v8::Persistent<v8::Object> object;
+ };
+
+ QHash<int, WorkerScript *> workers;
+ v8::Handle<v8::Object> getWorker(WorkerScript *);
+
+ int m_nextId;
+
+ static v8::Handle<v8::Value> sendMessage(const v8::Arguments &args);
+
+signals:
+ void stopThread();
+
+protected:
+ virtual bool event(QEvent *);
+
+private:
+ void processMessage(int, const QByteArray &);
+ void processLoad(int, const QUrl &);
+ void reportScriptException(WorkerScript *, const QQmlError &error);
+};
+
+QQuickWorkerScriptEnginePrivate::WorkerEngine::WorkerEngine(QQuickWorkerScriptEnginePrivate *parent)
+: QV8Engine(0), p(parent), accessManager(0)
+{
+}
+
+QQuickWorkerScriptEnginePrivate::WorkerEngine::~WorkerEngine()
+{
+ qPersistentDispose(createsend);
+ qPersistentDispose(onmessage);
+ delete accessManager;
+}
+
+void QQuickWorkerScriptEnginePrivate::WorkerEngine::init()
+{
+ initDeclarativeGlobalObject();
+#define CALL_ONMESSAGE_SCRIPT \
+ "(function(object, message) { "\
+ "var isfunction = false; "\
+ "try { "\
+ "isfunction = object.WorkerScript.onMessage instanceof Function; "\
+ "} catch (e) {}" \
+ "if (isfunction) "\
+ "object.WorkerScript.onMessage(message); "\
+ "})"
+
+#define SEND_MESSAGE_CREATE_SCRIPT \
+ "(function(method, engine) { "\
+ "return (function(id) { "\
+ "return (function(message) { "\
+ "if (arguments.length) method(engine, id, message); "\
+ "}); "\
+ "}); "\
+ "})"
+
+ v8::HandleScope handle_scope;
+ v8::Context::Scope scope(context());
+
+ {
+ v8::Local<v8::Script> onmessagescript = v8::Script::New(v8::String::New(CALL_ONMESSAGE_SCRIPT));
+ onmessage = qPersistentNew<v8::Function>(v8::Handle<v8::Function>::Cast(onmessagescript->Run()));
+ }
+ {
+ v8::Local<v8::Script> createsendscript = v8::Script::New(v8::String::New(SEND_MESSAGE_CREATE_SCRIPT));
+ v8::Local<v8::Function> createsendconstructor = v8::Local<v8::Function>::Cast(createsendscript->Run());
+
+ v8::Handle<v8::Value> args[] = {
+ V8FUNCTION(QQuickWorkerScriptEnginePrivate::sendMessage, this)
+ };
+ v8::Local<v8::Value> createsendvalue = createsendconstructor->Call(global(), 1, args);
+
+ createsend = qPersistentNew<v8::Function>(v8::Handle<v8::Function>::Cast(createsendvalue));
+ }
+}
+
+// Requires handle and context scope
+v8::Local<v8::Function> QQuickWorkerScriptEnginePrivate::WorkerEngine::sendFunction(int id)
+{
+ v8::Handle<v8::Value> args[] = { v8::Integer::New(id) };
+ return v8::Local<v8::Function>::Cast(createsend->Call(global(), 1, args));
+}
+
+// Requires handle and context scope
+void QQuickWorkerScriptEnginePrivate::WorkerEngine::callOnMessage(v8::Handle<v8::Object> object,
+ v8::Handle<v8::Value> arg)
+{
+ v8::Handle<v8::Value> args[] = { object, arg };
+ onmessage->Call(global(), 2, args);
+}
+
+QNetworkAccessManager *QQuickWorkerScriptEnginePrivate::WorkerEngine::networkAccessManager()
+{
+ if (!accessManager) {
+ if (p->qmlengine && p->qmlengine->networkAccessManagerFactory()) {
+ accessManager = p->qmlengine->networkAccessManagerFactory()->create(p);
+ } else {
+ accessManager = new QNetworkAccessManager(p);
+ }
+ }
+ return accessManager;
+}
+
+QQuickWorkerScriptEnginePrivate::QQuickWorkerScriptEnginePrivate(QQmlEngine *engine)
+: workerEngine(0), qmlengine(engine), m_nextId(0)
+{
+}
+
+v8::Handle<v8::Value> QQuickWorkerScriptEnginePrivate::sendMessage(const v8::Arguments &args)
+{
+ WorkerEngine *engine = (WorkerEngine*)V8ENGINE();
+
+ int id = args[1]->Int32Value();
+
+ QByteArray data = QV8Worker::serialize(args[2], engine);
+
+ QMutexLocker(&engine->p->m_lock);
+ WorkerScript *script = engine->p->workers.value(id);
+ if (!script)
+ return v8::Undefined();
+
+ if (script->owner)
+ QCoreApplication::postEvent(script->owner, new WorkerDataEvent(0, data));
+
+ return v8::Undefined();
+}
+
+// Requires handle scope and context scope
+v8::Handle<v8::Object> QQuickWorkerScriptEnginePrivate::getWorker(WorkerScript *script)
+{
+ if (!script->initialized) {
+ script->initialized = true;
+
+ script->object = qPersistentNew<v8::Object>(workerEngine->contextWrapper()->urlScope(script->source));
+
+ workerEngine->contextWrapper()->setReadOnly(script->object, false);
+
+ v8::Local<v8::Object> api = v8::Object::New();
+ api->Set(v8::String::New("sendMessage"), workerEngine->sendFunction(script->id));
+
+ script->object->Set(v8::String::New("WorkerScript"), api);
+
+ workerEngine->contextWrapper()->setReadOnly(script->object, true);
+ }
+
+ return script->object;
+}
+
+bool QQuickWorkerScriptEnginePrivate::event(QEvent *event)
+{
+ if (event->type() == (QEvent::Type)WorkerDataEvent::WorkerData) {
+ WorkerDataEvent *workerEvent = static_cast<WorkerDataEvent *>(event);
+ processMessage(workerEvent->workerId(), workerEvent->data());
+ return true;
+ } else if (event->type() == (QEvent::Type)WorkerLoadEvent::WorkerLoad) {
+ WorkerLoadEvent *workerEvent = static_cast<WorkerLoadEvent *>(event);
+ processLoad(workerEvent->workerId(), workerEvent->url());
+ return true;
+ } else if (event->type() == (QEvent::Type)WorkerDestroyEvent) {
+ emit stopThread();
+ return true;
+ } else if (event->type() == (QEvent::Type)WorkerRemoveEvent::WorkerRemove) {
+ WorkerRemoveEvent *workerEvent = static_cast<WorkerRemoveEvent *>(event);
+ workers.remove(workerEvent->workerId());
+ return true;
+ } else {
+ return QObject::event(event);
+ }
+}
+
+void QQuickWorkerScriptEnginePrivate::processMessage(int id, const QByteArray &data)
+{
+ WorkerScript *script = workers.value(id);
+ if (!script)
+ return;
+
+ v8::HandleScope handle_scope;
+ v8::Context::Scope scope(workerEngine->context());
+
+ v8::Handle<v8::Value> value = QV8Worker::deserialize(data, workerEngine);
+
+ v8::TryCatch tc;
+ workerEngine->callOnMessage(script->object, value);
+
+ if (tc.HasCaught()) {
+ QQmlError error;
+ QQmlExpressionPrivate::exceptionToError(tc.Message(), error);
+ reportScriptException(script, error);
+ }
+}
+
+void QQuickWorkerScriptEnginePrivate::processLoad(int id, const QUrl &url)
+{
+ if (url.isRelative())
+ return;
+
+ QString fileName = QQmlEnginePrivate::urlToLocalFileOrQrc(url);
+
+ QFile f(fileName);
+ if (f.open(QIODevice::ReadOnly)) {
+ QByteArray data = f.readAll();
+ QString sourceCode = QString::fromUtf8(data);
+ QQmlScript::Parser::extractPragmas(sourceCode);
+
+ v8::HandleScope handle_scope;
+ v8::Context::Scope scope(workerEngine->context());
+
+ WorkerScript *script = workers.value(id);
+ if (!script)
+ return;
+ script->source = url;
+ v8::Handle<v8::Object> activation = getWorker(script);
+ if (activation.IsEmpty())
+ return;
+
+ // XXX ???
+ // workerEngine->baseUrl = url;
+
+ v8::TryCatch tc;
+ v8::Local<v8::Script> program = workerEngine->qmlModeCompile(sourceCode, url.toString());
+
+ if (!tc.HasCaught())
+ program->Run(activation);
+
+ if (tc.HasCaught()) {
+ QQmlError error;
+ QQmlExpressionPrivate::exceptionToError(tc.Message(), error);
+ reportScriptException(script, error);
+ }
+ } else {
+ qWarning().nospace() << "WorkerScript: Cannot find source file " << url.toString();
+ }
+}
+
+void QQuickWorkerScriptEnginePrivate::reportScriptException(WorkerScript *script,
+ const QQmlError &error)
+{
+ QQuickWorkerScriptEnginePrivate *p = QQuickWorkerScriptEnginePrivate::get(workerEngine);
+
+ QMutexLocker(&p->m_lock);
+ if (script->owner)
+ QCoreApplication::postEvent(script->owner, new WorkerErrorEvent(error));
+}
+
+WorkerDataEvent::WorkerDataEvent(int workerId, const QByteArray &data)
+: QEvent((QEvent::Type)WorkerData), m_id(workerId), m_data(data)
+{
+}
+
+WorkerDataEvent::~WorkerDataEvent()
+{
+}
+
+int WorkerDataEvent::workerId() const
+{
+ return m_id;
+}
+
+QByteArray WorkerDataEvent::data() const
+{
+ return m_data;
+}
+
+WorkerLoadEvent::WorkerLoadEvent(int workerId, const QUrl &url)
+: QEvent((QEvent::Type)WorkerLoad), m_id(workerId), m_url(url)
+{
+}
+
+int WorkerLoadEvent::workerId() const
+{
+ return m_id;
+}
+
+QUrl WorkerLoadEvent::url() const
+{
+ return m_url;
+}
+
+WorkerRemoveEvent::WorkerRemoveEvent(int workerId)
+: QEvent((QEvent::Type)WorkerRemove), m_id(workerId)
+{
+}
+
+int WorkerRemoveEvent::workerId() const
+{
+ return m_id;
+}
+
+WorkerErrorEvent::WorkerErrorEvent(const QQmlError &error)
+: QEvent((QEvent::Type)WorkerError), m_error(error)
+{
+}
+
+QQmlError WorkerErrorEvent::error() const
+{
+ return m_error;
+}
+
+QQuickWorkerScriptEngine::QQuickWorkerScriptEngine(QQmlEngine *parent)
+: QThread(parent), d(new QQuickWorkerScriptEnginePrivate(parent))
+{
+ d->m_lock.lock();
+ connect(d, SIGNAL(stopThread()), this, SLOT(quit()), Qt::DirectConnection);
+ start(QThread::LowestPriority);
+ d->m_wait.wait(&d->m_lock);
+ d->moveToThread(this);
+ d->m_lock.unlock();
+}
+
+QQuickWorkerScriptEngine::~QQuickWorkerScriptEngine()
+{
+ d->m_lock.lock();
+ QCoreApplication::postEvent(d, new QEvent((QEvent::Type)QQuickWorkerScriptEnginePrivate::WorkerDestroyEvent));
+ d->m_lock.unlock();
+
+ //We have to force to cleanup the main thread's event queue here
+ //to make sure the main GUI release all pending locks/wait conditions which
+ //some worker script/agent are waiting for (QQuickListModelWorkerAgent::sync() for example).
+ QCoreApplication::processEvents();
+ wait();
+ d->deleteLater();
+}
+
+QQuickWorkerScriptEnginePrivate::WorkerScript::WorkerScript()
+: id(-1), initialized(false), owner(0)
+{
+}
+
+QQuickWorkerScriptEnginePrivate::WorkerScript::~WorkerScript()
+{
+ qPersistentDispose(object);
+}
+
+int QQuickWorkerScriptEngine::registerWorkerScript(QQuickWorkerScript *owner)
+{
+ typedef QQuickWorkerScriptEnginePrivate::WorkerScript WorkerScript;
+ WorkerScript *script = new WorkerScript;
+
+ script->id = d->m_nextId++;
+ script->owner = owner;
+
+ d->m_lock.lock();
+ d->workers.insert(script->id, script);
+ d->m_lock.unlock();
+
+ return script->id;
+}
+
+void QQuickWorkerScriptEngine::removeWorkerScript(int id)
+{
+ QQuickWorkerScriptEnginePrivate::WorkerScript* script = d->workers.value(id);
+ if (script) {
+ script->owner = 0;
+ QCoreApplication::postEvent(d, new WorkerRemoveEvent(id));
+ }
+}
+
+void QQuickWorkerScriptEngine::executeUrl(int id, const QUrl &url)
+{
+ QCoreApplication::postEvent(d, new WorkerLoadEvent(id, url));
+}
+
+void QQuickWorkerScriptEngine::sendMessage(int id, const QByteArray &data)
+{
+ QCoreApplication::postEvent(d, new WorkerDataEvent(id, data));
+}
+
+void QQuickWorkerScriptEngine::run()
+{
+ d->m_lock.lock();
+
+ d->workerEngine = new QQuickWorkerScriptEnginePrivate::WorkerEngine(d);
+ d->workerEngine->init();
+
+ d->m_wait.wakeAll();
+
+ d->m_lock.unlock();
+
+ exec();
+
+ qDeleteAll(d->workers);
+ d->workers.clear();
+
+ delete d->workerEngine; d->workerEngine = 0;
+}
+
+
+/*!
+ \qmlclass WorkerScript QQuickWorkerScript
+ \ingroup qml-utility-elements
+ \brief The WorkerScript element enables the use of threads in QML.
+
+ Use WorkerScript to run operations in a new thread.
+ This is useful for running operations in the background so
+ that the main GUI thread is not blocked.
+
+ Messages can be passed between the new thread and the parent thread
+ using \l sendMessage() and the \l {WorkerScript::onMessage}{onMessage()} handler.
+
+ An example:
+
+ \snippet doc/src/snippets/qml/workerscript.qml 0
+
+ The above worker script specifies a JavaScript file, "script.js", that handles
+ the operations to be performed in the new thread. Here is \c script.js:
+
+ \quotefile doc/src/snippets/qml/script.js
+
+ When the user clicks anywhere within the rectangle, \c sendMessage() is
+ called, triggering the \tt WorkerScript.onMessage() handler in
+ \tt script.js. This in turn sends a reply message that is then received
+ by the \tt onMessage() handler of \tt myWorker.
+
+
+ \section3 Restrictions
+
+ Since the \c WorkerScript.onMessage() function is run in a separate thread, the
+ JavaScript file is evaluated in a context separate from the main QML engine. This means
+ that unlike an ordinary JavaScript file that is imported into QML, the \c script.js
+ in the above example cannot access the properties, methods or other attributes
+ of the QML item, nor can it access any context properties set on the QML object
+ through QQmlContext.
+
+ Additionally, there are restrictions on the types of values that can be passed to and
+ from the worker script. See the sendMessage() documentation for details.
+
+ \sa {declarative/threading/workerscript}{WorkerScript example},
+ {declarative/threading/threadedlistmodel}{Threaded ListModel example}
+*/
+QQuickWorkerScript::QQuickWorkerScript(QObject *parent)
+: QObject(parent), m_engine(0), m_scriptId(-1), m_componentComplete(true)
+{
+}
+
+QQuickWorkerScript::~QQuickWorkerScript()
+{
+ if (m_scriptId != -1) m_engine->removeWorkerScript(m_scriptId);
+}
+
+/*!
+ \qmlproperty url WorkerScript::source
+
+ This holds the url of the JavaScript file that implements the
+ \tt WorkerScript.onMessage() handler for threaded operations.
+*/
+QUrl QQuickWorkerScript::source() const
+{
+ return m_source;
+}
+
+void QQuickWorkerScript::setSource(const QUrl &source)
+{
+ if (m_source == source)
+ return;
+
+ m_source = source;
+
+ if (engine())
+ m_engine->executeUrl(m_scriptId, m_source);
+
+ emit sourceChanged();
+}
+
+/*!
+ \qmlmethod WorkerScript::sendMessage(jsobject message)
+
+ Sends the given \a message to a worker script handler in another
+ thread. The other worker script handler can receive this message
+ through the onMessage() handler.
+
+ The \c message object may only contain values of the following
+ types:
+
+ \list
+ \o boolean, number, string
+ \o JavaScript objects and arrays
+ \o ListModel objects (any other type of QObject* is not allowed)
+ \endlist
+
+ All objects and arrays are copied to the \c message. With the exception
+ of ListModel objects, any modifications by the other thread to an object
+ passed in \c message will not be reflected in the original object.
+*/
+void QQuickWorkerScript::sendMessage(QQmlV8Function *args)
+{
+ if (!engine()) {
+ qWarning("QQuickWorkerScript: Attempt to send message before WorkerScript establishment");
+ return;
+ }
+
+ v8::Handle<v8::Value> argument = v8::Undefined();
+ if (args->Length() != 0)
+ argument = (*args)[0];
+
+ m_engine->sendMessage(m_scriptId, QV8Worker::serialize(argument, args->engine()));
+}
+
+void QQuickWorkerScript::classBegin()
+{
+ m_componentComplete = false;
+}
+
+QQuickWorkerScriptEngine *QQuickWorkerScript::engine()
+{
+ if (m_engine) return m_engine;
+ if (m_componentComplete) {
+ QQmlEngine *engine = qmlEngine(this);
+ if (!engine) {
+ qWarning("QQuickWorkerScript: engine() called without qmlEngine() set");
+ return 0;
+ }
+
+ m_engine = QQmlEnginePrivate::get(engine)->getWorkerScriptEngine();
+ m_scriptId = m_engine->registerWorkerScript(this);
+
+ if (m_source.isValid())
+ m_engine->executeUrl(m_scriptId, m_source);
+
+ return m_engine;
+ }
+ return 0;
+}
+
+void QQuickWorkerScript::componentComplete()
+{
+ m_componentComplete = true;
+ engine(); // Get it started now.
+}
+
+/*!
+ \qmlsignal WorkerScript::onMessage(jsobject msg)
+
+ This handler is called when a message \a msg is received from a worker
+ script in another thread through a call to sendMessage().
+*/
+
+bool QQuickWorkerScript::event(QEvent *event)
+{
+ if (event->type() == (QEvent::Type)WorkerDataEvent::WorkerData) {
+ QQmlEngine *engine = qmlEngine(this);
+ if (engine) {
+ WorkerDataEvent *workerEvent = static_cast<WorkerDataEvent *>(event);
+ QV8Engine *v8engine = QQmlEnginePrivate::get(engine)->v8engine();
+ v8::HandleScope handle_scope;
+ v8::Context::Scope scope(v8engine->context());
+ v8::Handle<v8::Value> value = QV8Worker::deserialize(workerEvent->data(), v8engine);
+ emit message(QQmlV8Handle::fromHandle(value));
+ }
+ return true;
+ } else if (event->type() == (QEvent::Type)WorkerErrorEvent::WorkerError) {
+ WorkerErrorEvent *workerEvent = static_cast<WorkerErrorEvent *>(event);
+ QQmlEnginePrivate::warning(qmlEngine(this), workerEvent->error());
+ return true;
+ } else {
+ return QObject::event(event);
+ }
+}
+
+QT_END_NAMESPACE
+
+#include <qquickworkerscript.moc>
+
diff --git a/src/qml/qml/qquickworkerscript_p.h b/src/qml/qml/qquickworkerscript_p.h
new file mode 100644
index 0000000000..fd1c3ed690
--- /dev/null
+++ b/src/qml/qml/qquickworkerscript_p.h
@@ -0,0 +1,130 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKWORKERSCRIPT_P_H
+#define QQUICKWORKERSCRIPT_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qqml.h"
+#include "qqmlparserstatus.h"
+
+#include <QtCore/qthread.h>
+#include <QtQml/qjsvalue.h>
+#include <QtCore/qurl.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+
+class QQuickWorkerScript;
+class QQuickWorkerScriptEnginePrivate;
+class QQuickWorkerScriptEngine : public QThread
+{
+Q_OBJECT
+public:
+ QQuickWorkerScriptEngine(QQmlEngine *parent = 0);
+ virtual ~QQuickWorkerScriptEngine();
+
+ int registerWorkerScript(QQuickWorkerScript *);
+ void removeWorkerScript(int);
+ void executeUrl(int, const QUrl &);
+ void sendMessage(int, const QByteArray &);
+
+protected:
+ virtual void run();
+
+private:
+ QQuickWorkerScriptEnginePrivate *d;
+};
+
+class QQmlV8Function;
+class QQmlV8Handle;
+class Q_AUTOTEST_EXPORT QQuickWorkerScript : public QObject, public QQmlParserStatus
+{
+ Q_OBJECT
+ Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged)
+
+ Q_INTERFACES(QQmlParserStatus)
+public:
+ QQuickWorkerScript(QObject *parent = 0);
+ virtual ~QQuickWorkerScript();
+
+ QUrl source() const;
+ void setSource(const QUrl &);
+
+public slots:
+ void sendMessage(QQmlV8Function*);
+
+signals:
+ void sourceChanged();
+ void message(const QQmlV8Handle &messageObject);
+
+protected:
+ virtual void classBegin();
+ virtual void componentComplete();
+ virtual bool event(QEvent *);
+
+private:
+ QQuickWorkerScriptEngine *engine();
+ QQuickWorkerScriptEngine *m_engine;
+ int m_scriptId;
+ QUrl m_source;
+ bool m_componentComplete;
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickWorkerScript)
+
+QT_END_HEADER
+
+#endif // QQUICKWORKERSCRIPT_P_H
diff --git a/src/qml/qml/rewriter/rewriter.pri b/src/qml/qml/rewriter/rewriter.pri
new file mode 100644
index 0000000000..e51ee5ba4e
--- /dev/null
+++ b/src/qml/qml/rewriter/rewriter.pri
@@ -0,0 +1,2 @@
+HEADERS += $$PWD/textwriter_p.h
+SOURCES += $$PWD/textwriter.cpp
diff --git a/src/qml/qml/rewriter/textwriter.cpp b/src/qml/qml/rewriter/textwriter.cpp
new file mode 100644
index 0000000000..f14c4af521
--- /dev/null
+++ b/src/qml/qml/rewriter/textwriter.cpp
@@ -0,0 +1,217 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "textwriter_p.h"
+
+QT_QML_BEGIN_NAMESPACE
+
+using namespace QQmlJS;
+
+TextWriter::TextWriter()
+ :string(0), cursor(0)
+{
+}
+
+static bool overlaps(int posA, int lengthA, int posB, int lengthB) {
+ return (posA < posB + lengthB && posA + lengthA > posB + lengthB)
+ || (posA < posB && posA + lengthA > posB);
+}
+
+bool TextWriter::hasOverlap(int pos, int length)
+{
+ {
+ QListIterator<Replace> i(replaceList);
+ while (i.hasNext()) {
+ const Replace &cmd = i.next();
+ if (overlaps(pos, length, cmd.pos, cmd.length))
+ return true;
+ }
+ }
+ {
+ QListIterator<Move> i(moveList);
+ while (i.hasNext()) {
+ const Move &cmd = i.next();
+ if (overlaps(pos, length, cmd.pos, cmd.length))
+ return true;
+ }
+ return false;
+ }
+}
+
+bool TextWriter::hasMoveInto(int pos, int length)
+{
+ QListIterator<Move> i(moveList);
+ while (i.hasNext()) {
+ const Move &cmd = i.next();
+ if (cmd.to >= pos && cmd.to < pos + length)
+ return true;
+ }
+ return false;
+}
+
+void TextWriter::replace(int pos, int length, const QString &replacement)
+{
+ Q_ASSERT(!hasOverlap(pos, length));
+ Q_ASSERT(!hasMoveInto(pos, length));
+
+ Replace cmd;
+ cmd.pos = pos;
+ cmd.length = length;
+ cmd.replacement = replacement;
+ replaceList += cmd;
+}
+
+void TextWriter::move(int pos, int length, int to)
+{
+ Q_ASSERT(!hasOverlap(pos, length));
+
+ Move cmd;
+ cmd.pos = pos;
+ cmd.length = length;
+ cmd.to = to;
+ moveList += cmd;
+}
+
+void TextWriter::doReplace(const Replace &replace)
+{
+ int diff = replace.replacement.size() - replace.length;
+ {
+ QMutableListIterator<Replace> i(replaceList);
+ while (i.hasNext()) {
+ Replace &c = i.next();
+ if (replace.pos < c.pos)
+ c.pos += diff;
+ else if (replace.pos + replace.length < c.pos + c.length)
+ c.length += diff;
+ }
+ }
+ {
+ QMutableListIterator<Move> i(moveList);
+ while (i.hasNext()) {
+ Move &c = i.next();
+ if (replace.pos < c.pos)
+ c.pos += diff;
+ else if (replace.pos + replace.length < c.pos + c.length)
+ c.length += diff;
+
+ if (replace.pos < c.to)
+ c.to += diff;
+ }
+ }
+
+ if (string) {
+ string->replace(replace.pos, replace.length, replace.replacement);
+ } else if (cursor) {
+ cursor->setPosition(replace.pos);
+ cursor->setPosition(replace.pos + replace.length, QTextCursor::KeepAnchor);
+ cursor->insertText(replace.replacement);
+ }
+}
+
+void TextWriter::doMove(const Move &move)
+{
+ QString text;
+ if (string) {
+ text = string->mid(move.pos, move.length);
+ } else if (cursor) {
+ cursor->setPosition(move.pos);
+ cursor->setPosition(move.pos + move.length, QTextCursor::KeepAnchor);
+ text = cursor->selectedText();
+ }
+
+ Replace cut;
+ cut.pos = move.pos;
+ cut.length = move.length;
+ Replace paste;
+ paste.pos = move.to;
+ paste.length = 0;
+ paste.replacement = text;
+
+ replaceList.append(cut);
+ replaceList.append(paste);
+
+ Replace cmd;
+ while (!replaceList.isEmpty()) {
+ cmd = replaceList.first();
+ replaceList.removeFirst();
+ doReplace(cmd);
+ }
+}
+
+void TextWriter::write(QString *s)
+{
+ string = s;
+ write_helper();
+ string = 0;
+}
+
+void TextWriter::write(QTextCursor *textCursor)
+{
+ cursor = textCursor;
+ write_helper();
+ cursor = 0;
+}
+
+void TextWriter::write_helper()
+{
+ if (cursor)
+ cursor->beginEditBlock();
+ {
+ Replace cmd;
+ while (!replaceList.isEmpty()) {
+ cmd = replaceList.first();
+ replaceList.removeFirst();
+ doReplace(cmd);
+ }
+ }
+ {
+ Move cmd;
+ while (!moveList.isEmpty()) {
+ cmd = moveList.first();
+ moveList.removeFirst();
+ doMove(cmd);
+ }
+ }
+ if (cursor)
+ cursor->endEditBlock();
+}
+
+QT_QML_END_NAMESPACE
diff --git a/src/qml/qml/rewriter/textwriter_p.h b/src/qml/qml/rewriter/textwriter_p.h
new file mode 100644
index 0000000000..94e2d08730
--- /dev/null
+++ b/src/qml/qml/rewriter/textwriter_p.h
@@ -0,0 +1,101 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef TEXTWRITER_H
+#define TEXTWRITER_H
+
+#include <private/qqmljsglobal_p.h>
+
+#include <QtCore/QString>
+#include <QtCore/QList>
+#include <QtGui/QTextCursor>
+
+QT_BEGIN_HEADER
+QT_QML_BEGIN_NAMESPACE
+
+namespace QQmlJS {
+
+class TextWriter
+{
+ QString *string;
+ QTextCursor *cursor;
+
+ struct Replace {
+ int pos;
+ int length;
+ QString replacement;
+ };
+
+ QList<Replace> replaceList;
+
+ struct Move {
+ int pos;
+ int length;
+ int to;
+ };
+
+ QList<Move> moveList;
+
+ bool hasOverlap(int pos, int length);
+ bool hasMoveInto(int pos, int length);
+
+ void doReplace(const Replace &replace);
+ void doMove(const Move &move);
+
+ void write_helper();
+
+public:
+ TextWriter();
+
+ void replace(int pos, int length, const QString &replacement);
+ void move(int pos, int length, int to);
+
+ void write(QString *s);
+ void write(QTextCursor *textCursor);
+
+};
+
+} // end of namespace QQmlJS
+
+QT_QML_END_NAMESPACE
+QT_END_HEADER
+
+#endif // TEXTWRITER_H
diff --git a/src/qml/qml/v4/qv4bindings.cpp b/src/qml/qml/v4/qv4bindings.cpp
new file mode 100644
index 0000000000..c03292d74d
--- /dev/null
+++ b/src/qml/qml/v4/qv4bindings.cpp
@@ -0,0 +1,1538 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// #define REGISTER_CLEANUP_DEBUG
+
+#include "qv4bindings_p.h"
+#include "qv4program_p.h"
+#include "qv4compiler_p.h"
+#include "qv4compiler_p_p.h"
+
+#include <private/qqmlaccessors_p.h>
+#include <private/qqmlprofilerservice_p.h>
+#include <private/qqmlmetatype_p.h>
+#include <private/qqmltrace_p.h>
+
+#include <QtQml/qqmlinfo.h>
+#include <QtCore/qnumeric.h>
+#include <QtCore/qmath.h>
+#include <math.h> // ::fmod
+
+QT_BEGIN_NAMESPACE
+
+using namespace QQmlJS;
+
+namespace {
+struct Register {
+ typedef QQmlRegisterType Type;
+
+ void setUndefined() { dataType = UndefinedType; }
+ void setNaN() { setqreal(qSNaN()); }
+ bool isUndefined() const { return dataType == UndefinedType; }
+
+ void setQObject(QObject *o) { qobjectValue = o; dataType = QObjectStarType; }
+ QObject *getQObject() const { return qobjectValue; }
+
+ void setqreal(qreal v) { qrealValue = v; dataType = QRealType; }
+ qreal getqreal() const { return qrealValue; }
+ qreal &getqrealref() { return qrealValue; }
+
+ void setint(int v) { intValue = v; dataType = IntType; }
+ int getint() const { return intValue; }
+ int &getintref() { return intValue; }
+
+ void setbool(bool v) { boolValue = v; dataType = BoolType; }
+ bool getbool() const { return boolValue; }
+ bool &getboolref() { return boolValue; }
+
+ QVariant *getvariantptr() { return (QVariant *)typeDataPtr(); }
+ QString *getstringptr() { return (QString *)typeDataPtr(); }
+ QUrl *geturlptr() { return (QUrl *)typeDataPtr(); }
+ const QVariant *getvariantptr() const { return (QVariant *)typeDataPtr(); }
+ const QString *getstringptr() const { return (QString *)typeDataPtr(); }
+ const QUrl *geturlptr() const { return (QUrl *)typeDataPtr(); }
+
+ void *typeDataPtr() { return (void *)&data; }
+ void *typeMemory() { return (void *)data; }
+ const void *typeDataPtr() const { return (void *)&data; }
+ const void *typeMemory() const { return (void *)data; }
+
+ Type gettype() const { return dataType; }
+ void settype(Type t) { dataType = t; }
+
+ Type dataType; // Type of data
+ union {
+ QObject *qobjectValue;
+ qreal qrealValue;
+ int intValue;
+ bool boolValue;
+ void *data[sizeof(QVariant)];
+ qint64 q_for_alignment_1;
+ double q_for_alignment_2;
+ };
+
+ inline void cleanup();
+ inline void cleanupString();
+ inline void cleanupUrl();
+ inline void cleanupVariant();
+
+ inline void copy(const Register &other);
+ inline void init(Type type);
+#ifdef REGISTER_CLEANUP_DEBUG
+ Register() {
+ type = 0;
+ }
+
+ ~Register() {
+ if (dataType >= FirstCleanupType)
+ qWarning("Register leaked of type %d", dataType);
+ }
+#endif
+};
+
+void Register::cleanup()
+{
+ if (dataType >= FirstCleanupType) {
+ if (dataType == QStringType) {
+ getstringptr()->~QString();
+ } else if (dataType == QUrlType) {
+ geturlptr()->~QUrl();
+ } else if (dataType == QVariantType) {
+ getvariantptr()->~QVariant();
+ }
+ }
+ setUndefined();
+}
+
+void Register::cleanupString()
+{
+ getstringptr()->~QString();
+ setUndefined();
+}
+
+void Register::cleanupUrl()
+{
+ geturlptr()->~QUrl();
+ setUndefined();
+}
+
+void Register::cleanupVariant()
+{
+ getvariantptr()->~QVariant();
+ setUndefined();
+}
+
+void Register::copy(const Register &other)
+{
+ *this = other;
+ if (other.dataType >= FirstCleanupType) {
+ if (other.dataType == QStringType)
+ new (getstringptr()) QString(*other.getstringptr());
+ else if (other.dataType == QUrlType)
+ new (geturlptr()) QUrl(*other.geturlptr());
+ else if (other.dataType == QVariantType)
+ new (getvariantptr()) QVariant(*other.getvariantptr());
+ }
+}
+
+void Register::init(Type type)
+{
+ dataType = type;
+ if (dataType >= FirstCleanupType) {
+ if (dataType == QStringType)
+ new (getstringptr()) QString();
+ else if (dataType == QUrlType)
+ new (geturlptr()) QUrl();
+ else if (dataType == QVariantType)
+ new (getvariantptr()) QVariant();
+ }
+}
+
+} // end of anonymous namespace
+
+QV4Bindings::QV4Bindings(const char *programData,
+ QQmlContextData *context,
+ QQmlRefCount *ref)
+: subscriptions(0), program(0), dataRef(0), bindings(0)
+{
+ program = (QV4Program *)programData;
+ dataRef = ref;
+ if (dataRef) dataRef->addref();
+
+ if (program) {
+ subscriptions = new Subscription[program->subscriptions];
+ bindings = new Binding[program->bindings];
+
+ QQmlAbstractExpression::setContext(context);
+ }
+}
+
+QV4Bindings::~QV4Bindings()
+{
+ delete [] bindings;
+ delete [] subscriptions; subscriptions = 0;
+ if (dataRef) dataRef->release();
+}
+
+QQmlAbstractBinding *QV4Bindings::configBinding(int index, QObject *target,
+ QObject *scope, int property,
+ int line, int column)
+{
+ Binding *rv = bindings + index;
+
+ rv->index = index;
+ rv->property = property;
+ rv->target = target;
+ rv->scope = scope;
+ rv->line = line;
+ rv->column = column;
+ rv->parent = this;
+
+ addref(); // This is decremented in Binding::destroy()
+
+ return rv;
+}
+
+void QV4Bindings::Binding::setEnabled(bool e, QQmlPropertyPrivate::WriteFlags flags)
+{
+ if (enabled != e) {
+ enabled = e;
+
+ if (e) update(flags);
+ }
+}
+
+void QV4Bindings::Binding::update(QQmlPropertyPrivate::WriteFlags flags)
+{
+ parent->run(this, flags);
+}
+
+void QV4Bindings::Binding::destroy()
+{
+ enabled = false;
+ removeFromObject();
+ clear();
+ removeError();
+ parent->release();
+}
+
+int QV4Bindings::Binding::propertyIndex() const
+{
+ return property;
+}
+
+QObject *QV4Bindings::Binding::object() const
+{
+ return target;
+}
+
+void QV4Bindings::Subscription::subscriptionCallback(QQmlNotifierEndpoint *e)
+{
+ Subscription *s = static_cast<Subscription *>(e);
+ s->bindings->subscriptionNotify(s->method);
+}
+
+void QV4Bindings::subscriptionNotify(int id)
+{
+ QV4Program::BindingReferenceList *list = program->signalTable(id);
+
+ for (quint32 ii = 0; ii < list->count; ++ii) {
+ QV4Program::BindingReference *bindingRef = list->bindings + ii;
+
+ Binding *binding = bindings + bindingRef->binding;
+
+ if (binding->executedBlocks & bindingRef->blockMask) {
+ run(binding, QQmlPropertyPrivate::DontRemoveBinding);
+ }
+ }
+}
+
+void QV4Bindings::run(Binding *binding, QQmlPropertyPrivate::WriteFlags flags)
+{
+ if (!binding->enabled)
+ return;
+
+ QQmlContextData *context = QQmlAbstractExpression::context();
+ if (!context || !context->isValid())
+ return;
+
+ QQmlTrace trace("V4 Binding Update");
+ trace.addDetail("URL", context->url);
+ trace.addDetail("Line", binding->line);
+ trace.addDetail("Column", binding->column);
+
+ QQmlBindingProfiler prof(context->urlString, binding->line, binding->column);
+
+ if (binding->updating) {
+ QString name;
+ if (binding->property & 0xFFFF0000) {
+ QQmlEnginePrivate *ep = QQmlEnginePrivate::get(context->engine);
+
+ QQmlValueType *vt = ep->valueTypes[(binding->property >> 16) & 0xFF];
+ Q_ASSERT(vt);
+
+ name = QLatin1String(binding->target->metaObject()->property(binding->property & 0xFFFF).name());
+ name.append(QLatin1String("."));
+ name.append(QLatin1String(vt->metaObject()->property(binding->property >> 24).name()));
+ } else {
+ name = QLatin1String(binding->target->metaObject()->property(binding->property).name());
+ }
+ qmlInfo(binding->target) << tr("Binding loop detected for property \"%1\"").arg(name);
+ return;
+ }
+
+ binding->updating = true;
+ if (binding->property & 0xFFFF0000) {
+ QQmlEnginePrivate *ep = QQmlEnginePrivate::get(context->engine);
+
+ QQmlValueType *vt = ep->valueTypes[(binding->property >> 16) & 0xFF];
+ Q_ASSERT(vt);
+ vt->read(binding->target, binding->property & 0xFFFF);
+
+ QObject *target = vt;
+ run(binding->index, binding->executedBlocks, context, binding, binding->scope, target, flags);
+
+ vt->write(binding->target, binding->property & 0xFFFF, flags);
+ } else {
+ run(binding->index, binding->executedBlocks, context, binding, binding->scope, binding->target, flags);
+ }
+ binding->updating = false;
+}
+
+
+void QV4Bindings::unsubscribe(int subIndex)
+{
+ Subscription *sub = (subscriptions + subIndex);
+ sub->disconnect();
+}
+
+void QV4Bindings::subscribeId(QQmlContextData *p, int idIndex, int subIndex)
+{
+ unsubscribe(subIndex);
+
+ if (p->idValues[idIndex]) {
+ Subscription *sub = (subscriptions + subIndex);
+ sub->bindings = this;
+ sub->method = subIndex;
+ sub->connect(&p->idValues[idIndex].bindings);
+ }
+}
+
+void QV4Bindings::subscribe(QObject *o, int notifyIndex, int subIndex)
+{
+ Subscription *sub = (subscriptions + subIndex);
+ if (sub->isConnected(o, notifyIndex))
+ return;
+ sub->bindings = this;
+ sub->method = subIndex;
+ if (o)
+ sub->connect(o, notifyIndex);
+ else
+ sub->disconnect();
+}
+
+// Conversion functions - these MUST match the QtScript expression path
+inline static qreal toReal(Register *reg, int type, bool *ok = 0)
+{
+ if (ok) *ok = true;
+
+ if (type == QMetaType::QReal) {
+ return reg->getqreal();
+ } else if (type == qMetaTypeId<QVariant>()) {
+ return reg->getvariantptr()->toReal();
+ } else {
+ if (ok) *ok = false;
+ return 0;
+ }
+}
+
+inline static QString toString(Register *reg, int type, bool *ok = 0)
+{
+ if (ok) *ok = true;
+
+ if (type == QMetaType::QReal) {
+ return QString::number(reg->getqreal());
+ } else if (type == QMetaType::Int) {
+ return QString::number(reg->getint());
+ } else if (type == qMetaTypeId<QVariant>()) {
+ return reg->getvariantptr()->toString();
+ } else if (type == QMetaType::QString) {
+ return *reg->getstringptr();
+ } else {
+ if (ok) *ok = false;
+ return QString();
+ }
+}
+
+inline static bool toBool(Register *reg, int type, bool *ok = 0)
+{
+ if (ok) *ok = true;
+
+ if (type == QMetaType::Bool) {
+ return reg->getbool();
+ } else if (type == qMetaTypeId<QVariant>()) {
+ return reg->getvariantptr()->toBool();
+ } else {
+ if (ok) *ok = false;
+ return false;
+ }
+}
+
+inline static QUrl toUrl(Register *reg, int type, QQmlContextData *context, bool *ok = 0)
+{
+ if (ok) *ok = true;
+
+ QUrl base;
+ if (type == qMetaTypeId<QVariant>()) {
+ QVariant *var = reg->getvariantptr();
+ int vt = var->type();
+ if (vt == QVariant::Url) {
+ base = var->toUrl();
+ } else if (vt == QVariant::ByteArray) {
+ // Preserve any valid percent-encoded octets supplied by the source
+ base.setEncodedUrl(var->toByteArray(), QUrl::TolerantMode);
+ } else if (vt == QVariant::String) {
+ base.setEncodedUrl(var->toString().toUtf8(), QUrl::TolerantMode);
+ } else {
+ if (ok) *ok = false;
+ return QUrl();
+ }
+ } else if (type == QMetaType::QString) {
+ base.setEncodedUrl(reg->getstringptr()->toUtf8(), QUrl::TolerantMode);
+ } else {
+ if (ok) *ok = false;
+ return QUrl();
+ }
+
+ if (!base.isEmpty() && base.isRelative())
+ return context->url.resolved(base);
+ else
+ return base;
+}
+
+static bool testCompareVariants(const QVariant &qtscriptRaw, const QVariant &v4)
+{
+ QVariant qtscript = qtscriptRaw;
+
+ if (qtscript.userType() == v4.userType()) {
+ } else if (qtscript.canConvert((QVariant::Type)v4.userType())) {
+ qtscript.convert((QVariant::Type)v4.userType());
+ } else if (qtscript.userType() == QVariant::Invalid && v4.userType() == QMetaType::QObjectStar) {
+ qtscript = qVariantFromValue<QObject *>(0);
+ } else {
+ return false;
+ }
+
+ int type = qtscript.userType();
+
+ if (type == QQmlMetaType::QQuickAnchorLineMetaTypeId()) {
+ return QQmlMetaType::QQuickAnchorLineCompare(qtscript.constData(), v4.constData());
+ } else if (type == QMetaType::Double) {
+
+ double la = qvariant_cast<double>(qtscript);
+ double lr = qvariant_cast<double>(v4);
+
+ return la == lr || (qIsNaN(la) && qIsNaN(lr));
+
+ } else if (type == QMetaType::Float) {
+
+ float la = qvariant_cast<float>(qtscript);
+ float lr = qvariant_cast<float>(v4);
+
+ return la == lr || (qIsNaN(la) && qIsNaN(lr));
+
+ } else {
+ return qtscript == v4;
+ }
+}
+
+QByteArray testResultToString(const QVariant &result, bool undefined)
+{
+ if (undefined) {
+ return "undefined";
+ } else {
+ QString rv;
+ QDebug d(&rv);
+ d << result;
+ return rv.toUtf8();
+ }
+}
+
+static void testBindingResult(const QString &binding, int line, int column,
+ QQmlContextData *context, QObject *scope,
+ const Register &result, int resultType)
+{
+ QQmlExpression expression(context->asQQmlContext(), scope, binding);
+ bool isUndefined = false;
+ QVariant value = expression.evaluate(&isUndefined);
+
+ bool iserror = false;
+ QByteArray qtscriptResult;
+ QByteArray v4Result;
+
+ if (expression.hasError()) {
+ iserror = true;
+ qtscriptResult = "exception";
+ } else {
+ qtscriptResult = testResultToString(value, isUndefined);
+ }
+
+ if (isUndefined && result.isUndefined()) {
+ return;
+ } else if(isUndefined != result.isUndefined()) {
+ iserror = true;
+ }
+
+ QVariant v4value;
+ if (!result.isUndefined()) {
+ switch (resultType) {
+ case QMetaType::QString:
+ v4value = *result.getstringptr();
+ break;
+ case QMetaType::QUrl:
+ v4value = *result.geturlptr();
+ break;
+ case QMetaType::QObjectStar:
+ v4value = qVariantFromValue<QObject *>(result.getQObject());
+ break;
+ case QMetaType::Bool:
+ v4value = result.getbool();
+ break;
+ case QMetaType::Int:
+ v4value = result.getint();
+ break;
+ case QMetaType::QReal:
+ v4value = result.getqreal();
+ break;
+ default:
+ if (resultType == QQmlMetaType::QQuickAnchorLineMetaTypeId()) {
+ v4value = QVariant(QQmlMetaType::QQuickAnchorLineMetaTypeId(), result.typeDataPtr());
+ } else {
+ iserror = true;
+ v4Result = "Unknown V4 type";
+ }
+ }
+ }
+ if (v4Result.isEmpty())
+ v4Result = testResultToString(v4value, result.isUndefined());
+
+ if (!testCompareVariants(value, v4value))
+ iserror = true;
+
+ if (iserror) {
+ qWarning().nospace() << "QV4: Optimization error @" << context->url.toString().toUtf8().constData() << ":" << line << ":" << column;
+
+ qWarning().nospace() << " Binding: " << binding;
+ qWarning().nospace() << " QtScript: " << qtscriptResult.constData();
+ qWarning().nospace() << " V4: " << v4Result.constData();
+ }
+}
+
+static void testBindingException(const QString &binding, int line, int column,
+ QQmlContextData *context, QObject *scope)
+{
+ QQmlExpression expression(context->asQQmlContext(), scope, binding);
+ bool isUndefined = false;
+ QVariant value = expression.evaluate(&isUndefined);
+
+ if (!expression.hasError()) {
+ QByteArray qtscriptResult = testResultToString(value, isUndefined);
+ qWarning().nospace() << "QV4: Optimization error @" << context->url.toString().toUtf8().constData() << ":" << line << ":" << column;
+ qWarning().nospace() << " Binding: " << binding;
+ qWarning().nospace() << " QtScript: " << qtscriptResult.constData();
+ qWarning().nospace() << " V4: exception";
+ }
+}
+
+static void throwException(int id, QQmlDelayedError *error,
+ QV4Program *program, QQmlContextData *context,
+ const QString &description = QString())
+{
+ error->error.setUrl(context->url);
+ if (description.isEmpty())
+ error->error.setDescription(QLatin1String("TypeError: Result of expression is not an object"));
+ else
+ error->error.setDescription(description);
+ if (id != 0xFF) {
+ quint64 e = *((quint64 *)(program->data() + program->exceptionDataOffset) + id);
+ error->error.setLine((e >> 32) & 0xFFFFFFFF);
+ error->error.setColumn(e & 0xFFFFFFFF);
+ } else {
+ error->error.setLine(-1);
+ error->error.setColumn(-1);
+ }
+ if (!context->engine || !error->addError(QQmlEnginePrivate::get(context->engine)))
+ QQmlEnginePrivate::warning(context->engine, error->error);
+}
+
+const qreal QV4Bindings::D32 = 4294967296.0;
+
+qint32 QV4Bindings::toInt32(qreal n)
+{
+ if (qIsNaN(n) || qIsInf(n) || (n == 0))
+ return 0;
+
+ double sign = (n < 0) ? -1.0 : 1.0;
+ qreal abs_n = fabs(n);
+
+ n = ::fmod(sign * ::floor(abs_n), D32);
+ const double D31 = D32 / 2.0;
+
+ if (sign == -1 && n < -D31)
+ n += D32;
+
+ else if (sign != -1 && n >= D31)
+ n -= D32;
+
+ return qint32 (n);
+}
+
+inline quint32 QV4Bindings::toUint32(qreal n)
+{
+ if (qIsNaN(n) || qIsInf(n) || (n == 0))
+ return 0;
+
+ double sign = (n < 0) ? -1.0 : 1.0;
+ qreal abs_n = fabs(n);
+
+ n = ::fmod(sign * ::floor(abs_n), D32);
+
+ if (n < 0)
+ n += D32;
+
+ return quint32 (n);
+}
+
+#define THROW_EXCEPTION_STR(id, str) { \
+ if (testBinding) testBindingException(*testBindingSource, bindingLine, bindingColumn, context, scope); \
+ throwException((id), error, program, context, (str)); \
+ goto exceptionExit; \
+}
+
+#define THROW_EXCEPTION(id) THROW_EXCEPTION_STR(id, QString())
+
+#define MARK_REGISTER(reg) cleanupRegisterMask |= (1 << (reg))
+#define MARK_CLEAN_REGISTER(reg) cleanupRegisterMask &= ~(1 << (reg))
+
+#define STRING_REGISTER(reg) { \
+ registers[(reg)].settype(QStringType); \
+ MARK_REGISTER(reg); \
+}
+
+#define URL_REGISTER(reg) { \
+ registers[(reg)].settype(QUrlType); \
+ MARK_REGISTER(reg); \
+}
+
+#define VARIANT_REGISTER(reg) { \
+ registers[(reg)].settype(QVariantType); \
+ MARK_REGISTER(reg); \
+}
+
+#ifdef QML_THREADED_INTERPRETER
+void **QV4Bindings::getDecodeInstrTable()
+{
+ static void **decode_instr;
+ if (!decode_instr) {
+ QV4Bindings *dummy = new QV4Bindings(0, 0, 0);
+ quint32 executedBlocks = 0;
+ dummy->run(0, executedBlocks, 0, 0, 0, 0,
+ QQmlPropertyPrivate::BypassInterceptor,
+ &decode_instr);
+ dummy->release();
+ }
+ return decode_instr;
+}
+#endif
+
+void QV4Bindings::run(int instrIndex, quint32 &executedBlocks,
+ QQmlContextData *context, QQmlDelayedError *error,
+ QObject *scope, QObject *output,
+ QQmlPropertyPrivate::WriteFlags storeFlags
+#ifdef QML_THREADED_INTERPRETER
+ ,void ***table
+#endif
+ )
+{
+#ifdef QML_THREADED_INTERPRETER
+ if (table) {
+ static void *decode_instr[] = {
+ FOR_EACH_V4_INSTR(QML_V4_INSTR_ADDR)
+ };
+
+ *table = decode_instr;
+ return;
+ }
+#endif
+
+
+ error->removeError();
+
+ Register registers[32];
+ quint32 cleanupRegisterMask = 0;
+
+ executedBlocks = 0;
+
+ const char *code = program->instructions();
+ code += instrIndex * QML_V4_INSTR_SIZE(Jump, jump);
+ const V4Instr *instr = reinterpret_cast<const V4Instr *>(code);
+
+ const char *data = program->data();
+
+ QString *testBindingSource = 0;
+ bool testBinding = false;
+ int bindingLine = 0;
+ int bindingColumn = 0;
+
+#ifdef QML_THREADED_INTERPRETER
+ goto *instr->common.code;
+#else
+ for (;;) {
+ switch (instr->common.type) {
+#endif
+
+ QML_V4_BEGIN_INSTR(Noop, common)
+ QML_V4_END_INSTR(Noop, common)
+
+ QML_V4_BEGIN_INSTR(BindingId, id)
+ bindingLine = instr->id.line;
+ bindingColumn = instr->id.column;
+ QML_V4_END_INSTR(BindingId, id)
+
+ QML_V4_BEGIN_INSTR(SubscribeId, subscribeop)
+ subscribeId(context, instr->subscribeop.index, instr->subscribeop.offset);
+ QML_V4_END_INSTR(SubscribeId, subscribeop)
+
+ QML_V4_BEGIN_INSTR(Subscribe, subscribeop)
+ {
+ QObject *o = 0;
+ const Register &object = registers[instr->subscribeop.reg];
+ if (!object.isUndefined()) o = object.getQObject();
+ subscribe(o, instr->subscribeop.index, instr->subscribeop.offset);
+ }
+ QML_V4_END_INSTR(Subscribe, subscribeop)
+
+ QML_V4_BEGIN_INSTR(FetchAndSubscribe, fetchAndSubscribe)
+ {
+ Register &reg = registers[instr->fetchAndSubscribe.reg];
+
+ if (reg.isUndefined())
+ THROW_EXCEPTION(instr->fetchAndSubscribe.exceptionId);
+
+ QObject *object = reg.getQObject();
+ if (!object) {
+ reg.setUndefined();
+ } else {
+ int subIdx = instr->fetchAndSubscribe.subscription;
+ Subscription *sub = 0;
+ if (subIdx != -1) {
+ sub = (subscriptions + subIdx);
+ sub->bindings = this;
+ sub->method = subIdx;
+ }
+ reg.init((Register::Type)instr->fetchAndSubscribe.valueType);
+ if (instr->fetchAndSubscribe.valueType >= FirstCleanupType)
+ MARK_REGISTER(instr->fetchAndSubscribe.reg);
+ QQmlAccessors *accessors = instr->fetchAndSubscribe.property.accessors;
+ accessors->read(object, instr->fetchAndSubscribe.property.accessorData,
+ reg.typeDataPtr());
+
+ if (accessors->notifier) {
+ QQmlNotifier *notifier = 0;
+ accessors->notifier(object, instr->fetchAndSubscribe.property.accessorData, &notifier);
+ if (notifier) sub->connect(notifier);
+ } else if (instr->fetchAndSubscribe.property.notifyIndex != -1) {
+ sub->connect(object, instr->fetchAndSubscribe.property.notifyIndex);
+ }
+ }
+ }
+ QML_V4_END_INSTR(FetchAndSubscribe, fetchAndSubscribe)
+
+ QML_V4_BEGIN_INSTR(LoadId, load)
+ registers[instr->load.reg].setQObject(context->idValues[instr->load.index].data());
+ QML_V4_END_INSTR(LoadId, load)
+
+ QML_V4_BEGIN_INSTR(LoadScope, load)
+ registers[instr->load.reg].setQObject(scope);
+ QML_V4_END_INSTR(LoadScope, load)
+
+ QML_V4_BEGIN_INSTR(LoadRoot, load)
+ registers[instr->load.reg].setQObject(context->contextObject);
+ QML_V4_END_INSTR(LoadRoot, load)
+
+ QML_V4_BEGIN_INSTR(LoadAttached, attached)
+ {
+ const Register &input = registers[instr->attached.reg];
+ Register &output = registers[instr->attached.output];
+ if (input.isUndefined())
+ THROW_EXCEPTION(instr->attached.exceptionId);
+
+ QObject *object = registers[instr->attached.reg].getQObject();
+ if (!object) {
+ output.setUndefined();
+ } else {
+ QObject *attached = qmlAttachedPropertiesObjectById(instr->attached.id, input.getQObject(), true);
+ Q_ASSERT(attached);
+ output.setQObject(attached);
+ }
+ }
+ QML_V4_END_INSTR(LoadAttached, attached)
+
+ QML_V4_BEGIN_INSTR(UnaryNot, unaryop)
+ {
+ registers[instr->unaryop.output].setbool(!registers[instr->unaryop.src].getbool());
+ }
+ QML_V4_END_INSTR(UnaryNot, unaryop)
+
+ QML_V4_BEGIN_INSTR(UnaryMinusReal, unaryop)
+ {
+ registers[instr->unaryop.output].setqreal(-registers[instr->unaryop.src].getqreal());
+ }
+ QML_V4_END_INSTR(UnaryMinusReal, unaryop)
+
+ QML_V4_BEGIN_INSTR(UnaryMinusInt, unaryop)
+ {
+ registers[instr->unaryop.output].setint(-registers[instr->unaryop.src].getint());
+ }
+ QML_V4_END_INSTR(UnaryMinusInt, unaryop)
+
+ QML_V4_BEGIN_INSTR(UnaryPlusReal, unaryop)
+ {
+ registers[instr->unaryop.output].setqreal(+registers[instr->unaryop.src].getqreal());
+ }
+ QML_V4_END_INSTR(UnaryPlusReal, unaryop)
+
+ QML_V4_BEGIN_INSTR(UnaryPlusInt, unaryop)
+ {
+ registers[instr->unaryop.output].setint(+registers[instr->unaryop.src].getint());
+ }
+ QML_V4_END_INSTR(UnaryPlusInt, unaryop)
+
+ QML_V4_BEGIN_INSTR(ConvertBoolToInt, unaryop)
+ {
+ const Register &src = registers[instr->unaryop.src];
+ Register &output = registers[instr->unaryop.output];
+ if (src.isUndefined()) output.setUndefined();
+ else output.setint(src.getbool());
+ }
+ QML_V4_END_INSTR(ConvertBoolToInt, unaryop)
+
+ QML_V4_BEGIN_INSTR(ConvertBoolToReal, unaryop)
+ {
+ const Register &src = registers[instr->unaryop.src];
+ Register &output = registers[instr->unaryop.output];
+ if (src.isUndefined()) output.setUndefined();
+ else output.setqreal(src.getbool());
+ }
+ QML_V4_END_INSTR(ConvertBoolToReal, unaryop)
+
+ QML_V4_BEGIN_INSTR(ConvertBoolToString, unaryop)
+ {
+ const Register &src = registers[instr->unaryop.src];
+ Register &output = registers[instr->unaryop.output];
+ if (src.isUndefined()) {
+ output.setUndefined();
+ } else {
+ new (output.getstringptr()) QString(QLatin1String(src.getbool() ? "true" : "false"));
+ STRING_REGISTER(instr->unaryop.output);
+ }
+ }
+ QML_V4_END_INSTR(ConvertBoolToString, unaryop)
+
+ QML_V4_BEGIN_INSTR(ConvertIntToBool, unaryop)
+ {
+ const Register &src = registers[instr->unaryop.src];
+ Register &output = registers[instr->unaryop.output];
+ if (src.isUndefined()) output.setUndefined();
+ else output.setbool(src.getint());
+ }
+ QML_V4_END_INSTR(ConvertIntToBool, unaryop)
+
+ QML_V4_BEGIN_INSTR(ConvertIntToReal, unaryop)
+ {
+ const Register &src = registers[instr->unaryop.src];
+ Register &output = registers[instr->unaryop.output];
+ if (src.isUndefined()) output.setUndefined();
+ else output.setqreal(qreal(src.getint()));
+ }
+ QML_V4_END_INSTR(ConvertIntToReal, unaryop)
+
+ QML_V4_BEGIN_INSTR(ConvertIntToString, unaryop)
+ {
+ const Register &src = registers[instr->unaryop.src];
+ Register &output = registers[instr->unaryop.output];
+ if (src.isUndefined()) {
+ output.setUndefined();
+ } else {
+ new (output.getstringptr()) QString(QString::number(src.getint()));
+ STRING_REGISTER(instr->unaryop.output);
+ }
+ }
+ QML_V4_END_INSTR(ConvertIntToString, unaryop)
+
+ QML_V4_BEGIN_INSTR(ConvertRealToBool, unaryop)
+ {
+ const Register &src = registers[instr->unaryop.src];
+ Register &output = registers[instr->unaryop.output];
+ if (src.isUndefined()) output.setUndefined();
+ else output.setbool(src.getqreal() != 0);
+ }
+ QML_V4_END_INSTR(ConvertRealToBool, unaryop)
+
+ QML_V4_BEGIN_INSTR(ConvertRealToInt, unaryop)
+ {
+ const Register &src = registers[instr->unaryop.src];
+ Register &output = registers[instr->unaryop.output];
+ if (src.isUndefined()) output.setUndefined();
+ else output.setint(toInt32(src.getqreal()));
+ }
+ QML_V4_END_INSTR(ConvertRealToInt, unaryop)
+
+ QML_V4_BEGIN_INSTR(ConvertRealToString, unaryop)
+ {
+ const Register &src = registers[instr->unaryop.src];
+ Register &output = registers[instr->unaryop.output];
+ // ### NaN
+ if (src.isUndefined()) {
+ output.setUndefined();
+ } else {
+ new (output.getstringptr()) QString(QString::number(src.getqreal()));
+ STRING_REGISTER(instr->unaryop.output);
+ }
+ }
+ QML_V4_END_INSTR(ConvertRealToString, unaryop)
+
+ QML_V4_BEGIN_INSTR(ConvertStringToBool, unaryop)
+ {
+ const Register &src = registers[instr->unaryop.src];
+ Register &output = registers[instr->unaryop.output];
+ // ### NaN
+ if (src.isUndefined()) {
+ output.setUndefined();
+ } else {
+ // Delegate the conversion. This is pretty fast and it doesn't require a QScriptEngine.
+ // Ideally we should just call the methods in the QScript namespace directly.
+ QJSValue tmp(*src.getstringptr());
+ if (instr->unaryop.src == instr->unaryop.output) {
+ output.cleanupString();
+ MARK_CLEAN_REGISTER(instr->unaryop.output);
+ }
+ output.setbool(tmp.toBool());
+ }
+ }
+ QML_V4_END_INSTR(ConvertStringToBool, unaryop)
+
+ QML_V4_BEGIN_INSTR(ConvertStringToInt, unaryop)
+ {
+ const Register &src = registers[instr->unaryop.src];
+ Register &output = registers[instr->unaryop.output];
+ // ### NaN
+ if (src.isUndefined()) {
+ output.setUndefined();
+ } else {
+ // Delegate the conversion. This is pretty fast and it doesn't require a QScriptEngine.
+ // Ideally we should just call the methods in the QScript namespace directly.
+ QJSValue tmp(*src.getstringptr());
+ if (instr->unaryop.src == instr->unaryop.output) {
+ output.cleanupString();
+ MARK_CLEAN_REGISTER(instr->unaryop.output);
+ }
+ output.setint(tmp.toInt());
+ }
+ }
+ QML_V4_END_INSTR(ConvertStringToInt, unaryop)
+
+ QML_V4_BEGIN_INSTR(ConvertStringToReal, unaryop)
+ {
+ const Register &src = registers[instr->unaryop.src];
+ Register &output = registers[instr->unaryop.output];
+ // ### NaN
+ if (src.isUndefined()) {
+ output.setUndefined();
+ } else {
+ // Delegate the conversion. This is pretty fast and it doesn't require a QScriptEngine.
+ // Ideally we should just call the methods in the QScript namespace directly.
+ QJSValue tmp(*src.getstringptr());
+ if (instr->unaryop.src == instr->unaryop.output) {
+ output.cleanupString();
+ MARK_CLEAN_REGISTER(instr->unaryop.output);
+ }
+ output.setqreal(tmp.toNumber());
+ }
+ }
+ QML_V4_END_INSTR(ConvertStringToReal, unaryop)
+
+ QML_V4_BEGIN_INSTR(ConvertStringToUrl, unaryop)
+ {
+ const Register &src = registers[instr->unaryop.src];
+ Register &output = registers[instr->unaryop.output];
+ // ### NaN
+ if (src.isUndefined()) {
+ output.setUndefined();
+ } else {
+ const QString tmp(*src.getstringptr());
+ if (instr->unaryop.src == instr->unaryop.output) {
+ output.cleanupString();
+ MARK_CLEAN_REGISTER(instr->unaryop.output);
+ }
+ QUrl *urlPtr = output.geturlptr();
+ new (urlPtr) QUrl();
+ urlPtr->setEncodedUrl(tmp.toUtf8(), QUrl::TolerantMode);
+
+ URL_REGISTER(instr->unaryop.output);
+ }
+ }
+ QML_V4_END_INSTR(ConvertStringToUrl, unaryop)
+
+ QML_V4_BEGIN_INSTR(ConvertUrlToBool, unaryop)
+ {
+ const Register &src = registers[instr->unaryop.src];
+ Register &output = registers[instr->unaryop.output];
+ // ### NaN
+ if (src.isUndefined()) {
+ output.setUndefined();
+ } else {
+ const QUrl tmp(*src.geturlptr());
+ if (instr->unaryop.src == instr->unaryop.output) {
+ output.cleanupUrl();
+ MARK_CLEAN_REGISTER(instr->unaryop.output);
+ }
+ output.setbool(!tmp.isEmpty());
+ }
+ }
+ QML_V4_END_INSTR(ConvertUrlToBool, unaryop)
+
+ QML_V4_BEGIN_INSTR(ConvertUrlToString, unaryop)
+ {
+ const Register &src = registers[instr->unaryop.src];
+ Register &output = registers[instr->unaryop.output];
+ // ### NaN
+ if (src.isUndefined()) {
+ output.setUndefined();
+ } else {
+ const QUrl tmp(*src.geturlptr());
+ if (instr->unaryop.src == instr->unaryop.output) {
+ output.cleanupUrl();
+ MARK_CLEAN_REGISTER(instr->unaryop.output);
+ }
+ new (output.getstringptr()) QString(tmp.toString());
+ STRING_REGISTER(instr->unaryop.output);
+ }
+ }
+ QML_V4_END_INSTR(ConvertUrlToString, unaryop)
+
+ QML_V4_BEGIN_INSTR(ResolveUrl, unaryop)
+ {
+ const Register &src = registers[instr->unaryop.src];
+ Register &output = registers[instr->unaryop.output];
+ if (src.isUndefined()) {
+ output.setUndefined();
+ } else {
+ const QUrl tmp(*src.geturlptr());
+ if (instr->unaryop.src == instr->unaryop.output) {
+ *output.geturlptr() = context->resolvedUrl(tmp);
+ } else {
+ new (output.geturlptr()) QUrl(context->resolvedUrl(tmp));
+ URL_REGISTER(instr->unaryop.output);
+ }
+ }
+ }
+ QML_V4_END_INSTR(ResolveUrl, unaryop)
+
+ QML_V4_BEGIN_INSTR(MathSinReal, unaryop)
+ {
+ const Register &src = registers[instr->unaryop.src];
+ Register &output = registers[instr->unaryop.output];
+ if (src.isUndefined()) output.setUndefined();
+ else output.setqreal(qSin(src.getqreal()));
+ }
+ QML_V4_END_INSTR(MathSinReal, unaryop)
+
+ QML_V4_BEGIN_INSTR(MathCosReal, unaryop)
+ {
+ const Register &src = registers[instr->unaryop.src];
+ Register &output = registers[instr->unaryop.output];
+ if (src.isUndefined()) output.setUndefined();
+ else output.setqreal(qCos(src.getqreal()));
+ }
+ QML_V4_END_INSTR(MathCosReal, unaryop)
+
+ QML_V4_BEGIN_INSTR(MathRoundReal, unaryop)
+ {
+ const Register &src = registers[instr->unaryop.src];
+ Register &output = registers[instr->unaryop.output];
+ if (src.isUndefined()) output.setUndefined();
+ else output.setint(qRound(src.getqreal()));
+ }
+ QML_V4_END_INSTR(MathRoundReal, unaryop)
+
+ QML_V4_BEGIN_INSTR(MathFloorReal, unaryop)
+ {
+ const Register &src = registers[instr->unaryop.src];
+ Register &output = registers[instr->unaryop.output];
+ if (src.isUndefined()) output.setUndefined();
+ else output.setint(qFloor(src.getqreal()));
+ }
+ QML_V4_END_INSTR(MathFloorReal, unaryop)
+
+ QML_V4_BEGIN_INSTR(MathPIReal, unaryop)
+ {
+ static const qreal qmlPI = 2.0 * qAsin(1.0);
+ Register &output = registers[instr->unaryop.output];
+ output.setqreal(qmlPI);
+ }
+ QML_V4_END_INSTR(MathPIReal, unaryop)
+
+ QML_V4_BEGIN_INSTR(LoadReal, real_value)
+ registers[instr->real_value.reg].setqreal(instr->real_value.value);
+ QML_V4_END_INSTR(LoadReal, real_value)
+
+ QML_V4_BEGIN_INSTR(LoadInt, int_value)
+ registers[instr->int_value.reg].setint(instr->int_value.value);
+ QML_V4_END_INSTR(LoadInt, int_value)
+
+ QML_V4_BEGIN_INSTR(LoadBool, bool_value)
+ registers[instr->bool_value.reg].setbool(instr->bool_value.value);
+ QML_V4_END_INSTR(LoadBool, bool_value)
+
+ QML_V4_BEGIN_INSTR(LoadString, string_value)
+ {
+ Register &output = registers[instr->string_value.reg];
+ QChar *string = (QChar *)(data + instr->string_value.offset);
+ new (output.getstringptr()) QString(string, instr->string_value.length);
+ STRING_REGISTER(instr->string_value.reg);
+ }
+ QML_V4_END_INSTR(LoadString, string_value)
+
+ QML_V4_BEGIN_INSTR(EnableV4Test, string_value)
+ {
+ testBindingSource = new QString((QChar *)(data + instr->string_value.offset), instr->string_value.length);
+ testBinding = true;
+ }
+ QML_V4_END_INSTR(String, string_value)
+
+ QML_V4_BEGIN_INSTR(BitAndInt, binaryop)
+ {
+ registers[instr->binaryop.output].setint(registers[instr->binaryop.left].getint() &
+ registers[instr->binaryop.right].getint());
+ }
+ QML_V4_END_INSTR(BitAndInt, binaryop)
+
+ QML_V4_BEGIN_INSTR(BitOrInt, binaryop)
+ {
+ registers[instr->binaryop.output].setint(registers[instr->binaryop.left].getint() |
+ registers[instr->binaryop.right].getint());
+ }
+ QML_V4_END_INSTR(BitAndInt, binaryop)
+
+ QML_V4_BEGIN_INSTR(BitXorInt, binaryop)
+ {
+ registers[instr->binaryop.output].setint(registers[instr->binaryop.left].getint() ^
+ registers[instr->binaryop.right].getint());
+ }
+ QML_V4_END_INSTR(BitXorInt, binaryop)
+
+ QML_V4_BEGIN_INSTR(AddReal, binaryop)
+ {
+ registers[instr->binaryop.output].setqreal(registers[instr->binaryop.left].getqreal() +
+ registers[instr->binaryop.right].getqreal());
+ }
+ QML_V4_END_INSTR(AddReal, binaryop)
+
+ QML_V4_BEGIN_INSTR(AddString, binaryop)
+ {
+ QString &string = *registers[instr->binaryop.output].getstringptr();
+ if (instr->binaryop.output == instr->binaryop.left) {
+ string += registers[instr->binaryop.right].getstringptr();
+ } else {
+ string = *registers[instr->binaryop.left].getstringptr() +
+ *registers[instr->binaryop.right].getstringptr();
+ }
+ }
+ QML_V4_END_INSTR(AddString, binaryop)
+
+ QML_V4_BEGIN_INSTR(SubReal, binaryop)
+ {
+ registers[instr->binaryop.output].setqreal(registers[instr->binaryop.left].getqreal() -
+ registers[instr->binaryop.right].getqreal());
+ }
+ QML_V4_END_INSTR(SubReal, binaryop)
+
+ QML_V4_BEGIN_INSTR(MulReal, binaryop)
+ {
+ registers[instr->binaryop.output].setqreal(registers[instr->binaryop.left].getqreal() *
+ registers[instr->binaryop.right].getqreal());
+ }
+ QML_V4_END_INSTR(MulReal, binaryop)
+
+ QML_V4_BEGIN_INSTR(DivReal, binaryop)
+ {
+ registers[instr->binaryop.output].setqreal(registers[instr->binaryop.left].getqreal() /
+ registers[instr->binaryop.right].getqreal());
+ }
+ QML_V4_END_INSTR(DivReal, binaryop)
+
+ QML_V4_BEGIN_INSTR(ModReal, binaryop)
+ {
+ Register &target = registers[instr->binaryop.output];
+ const Register &left = registers[instr->binaryop.left];
+ const Register &right = registers[instr->binaryop.right];
+ if (QMetaType::QReal == QMetaType::Float)
+ target.setqreal(::fmodf(left.getqreal(), right.getqreal()));
+ else
+ target.setqreal(::fmod(left.getqreal(), right.getqreal()));
+ }
+ QML_V4_END_INSTR(ModInt, binaryop)
+
+ QML_V4_BEGIN_INSTR(LShiftInt, binaryop)
+ {
+ registers[instr->binaryop.output].setint(registers[instr->binaryop.left].getint() <<
+ registers[instr->binaryop.right].getint());
+ }
+ QML_V4_END_INSTR(LShiftInt, binaryop)
+
+ QML_V4_BEGIN_INSTR(RShiftInt, binaryop)
+ {
+ registers[instr->binaryop.output].setint(registers[instr->binaryop.left].getint() >>
+ registers[instr->binaryop.right].getint());
+ }
+ QML_V4_END_INSTR(RShiftInt, binaryop)
+
+ QML_V4_BEGIN_INSTR(URShiftInt, binaryop)
+ {
+ registers[instr->binaryop.output].setint((unsigned)registers[instr->binaryop.left].getint() >>
+ registers[instr->binaryop.right].getint());
+ }
+ QML_V4_END_INSTR(URShiftInt, binaryop)
+
+ QML_V4_BEGIN_INSTR(GtReal, binaryop)
+ {
+ registers[instr->binaryop.output].setbool(registers[instr->binaryop.left].getqreal() >
+ registers[instr->binaryop.right].getqreal());
+ }
+ QML_V4_END_INSTR(GtReal, binaryop)
+
+ QML_V4_BEGIN_INSTR(LtReal, binaryop)
+ {
+ registers[instr->binaryop.output].setbool(registers[instr->binaryop.left].getqreal() <
+ registers[instr->binaryop.right].getqreal());
+ }
+ QML_V4_END_INSTR(LtReal, binaryop)
+
+ QML_V4_BEGIN_INSTR(GeReal, binaryop)
+ {
+ registers[instr->binaryop.output].setbool(registers[instr->binaryop.left].getqreal() >=
+ registers[instr->binaryop.right].getqreal());
+ }
+ QML_V4_END_INSTR(GeReal, binaryop)
+
+ QML_V4_BEGIN_INSTR(LeReal, binaryop)
+ {
+ registers[instr->binaryop.output].setbool(registers[instr->binaryop.left].getqreal() <=
+ registers[instr->binaryop.right].getqreal());
+ }
+ QML_V4_END_INSTR(LeReal, binaryop)
+
+ QML_V4_BEGIN_INSTR(EqualReal, binaryop)
+ {
+ registers[instr->binaryop.output].setbool(registers[instr->binaryop.left].getqreal() ==
+ registers[instr->binaryop.right].getqreal());
+ }
+ QML_V4_END_INSTR(EqualReal, binaryop)
+
+ QML_V4_BEGIN_INSTR(NotEqualReal, binaryop)
+ {
+ registers[instr->binaryop.output].setbool(registers[instr->binaryop.left].getqreal() !=
+ registers[instr->binaryop.right].getqreal());
+ }
+ QML_V4_END_INSTR(NotEqualReal, binaryop)
+
+ QML_V4_BEGIN_INSTR(StrictEqualReal, binaryop)
+ {
+ registers[instr->binaryop.output].setbool(registers[instr->binaryop.left].getqreal() ==
+ registers[instr->binaryop.right].getqreal());
+ }
+ QML_V4_END_INSTR(StrictEqualReal, binaryop)
+
+ QML_V4_BEGIN_INSTR(StrictNotEqualReal, binaryop)
+ {
+ registers[instr->binaryop.output].setbool(registers[instr->binaryop.left].getqreal() !=
+ registers[instr->binaryop.right].getqreal());
+ }
+ QML_V4_END_INSTR(StrictNotEqualReal, binaryop)
+
+ QML_V4_BEGIN_INSTR(GtString, binaryop)
+ {
+ const QString &a = *registers[instr->binaryop.left].getstringptr();
+ const QString &b = *registers[instr->binaryop.right].getstringptr();
+ bool result = a > b;
+ if (instr->binaryop.left == instr->binaryop.output) {
+ registers[instr->binaryop.output].cleanupString();
+ MARK_CLEAN_REGISTER(instr->binaryop.output);
+ }
+ registers[instr->binaryop.output].setbool(result);
+ }
+ QML_V4_END_INSTR(GtString, binaryop)
+
+ QML_V4_BEGIN_INSTR(LtString, binaryop)
+ {
+ const QString &a = *registers[instr->binaryop.left].getstringptr();
+ const QString &b = *registers[instr->binaryop.right].getstringptr();
+ bool result = a < b;
+ if (instr->binaryop.left == instr->binaryop.output) {
+ registers[instr->binaryop.output].cleanupString();
+ MARK_CLEAN_REGISTER(instr->binaryop.output);
+ }
+ registers[instr->binaryop.output].setbool(result);
+ }
+ QML_V4_END_INSTR(LtString, binaryop)
+
+ QML_V4_BEGIN_INSTR(GeString, binaryop)
+ {
+ const QString &a = *registers[instr->binaryop.left].getstringptr();
+ const QString &b = *registers[instr->binaryop.right].getstringptr();
+ bool result = a >= b;
+ if (instr->binaryop.left == instr->binaryop.output) {
+ registers[instr->binaryop.output].cleanupString();
+ MARK_CLEAN_REGISTER(instr->binaryop.output);
+ }
+ registers[instr->binaryop.output].setbool(result);
+ }
+ QML_V4_END_INSTR(GeString, binaryop)
+
+ QML_V4_BEGIN_INSTR(LeString, binaryop)
+ {
+ const QString &a = *registers[instr->binaryop.left].getstringptr();
+ const QString &b = *registers[instr->binaryop.right].getstringptr();
+ bool result = a <= b;
+ if (instr->binaryop.left == instr->binaryop.output) {
+ registers[instr->binaryop.output].cleanupString();
+ MARK_CLEAN_REGISTER(instr->binaryop.output);
+ }
+ registers[instr->binaryop.output].setbool(result);
+ }
+ QML_V4_END_INSTR(LeString, binaryop)
+
+ QML_V4_BEGIN_INSTR(EqualString, binaryop)
+ {
+ const QString &a = *registers[instr->binaryop.left].getstringptr();
+ const QString &b = *registers[instr->binaryop.right].getstringptr();
+ bool result = a == b;
+ if (instr->binaryop.left == instr->binaryop.output) {
+ registers[instr->binaryop.output].cleanupString();
+ MARK_CLEAN_REGISTER(instr->binaryop.output);
+ }
+ registers[instr->binaryop.output].setbool(result);
+ }
+ QML_V4_END_INSTR(EqualString, binaryop)
+
+ QML_V4_BEGIN_INSTR(NotEqualString, binaryop)
+ {
+ const QString &a = *registers[instr->binaryop.left].getstringptr();
+ const QString &b = *registers[instr->binaryop.right].getstringptr();
+ bool result = a != b;
+ if (instr->binaryop.left == instr->binaryop.output) {
+ registers[instr->binaryop.output].cleanupString();
+ MARK_CLEAN_REGISTER(instr->binaryop.output);
+ }
+ registers[instr->binaryop.output].setbool(result);
+ }
+ QML_V4_END_INSTR(NotEqualString, binaryop)
+
+ QML_V4_BEGIN_INSTR(StrictEqualString, binaryop)
+ {
+ const QString &a = *registers[instr->binaryop.left].getstringptr();
+ const QString &b = *registers[instr->binaryop.right].getstringptr();
+ bool result = a == b;
+ if (instr->binaryop.left == instr->binaryop.output) {
+ registers[instr->binaryop.output].cleanupString();
+ MARK_CLEAN_REGISTER(instr->binaryop.output);
+ }
+ registers[instr->binaryop.output].setbool(result);
+ }
+ QML_V4_END_INSTR(StrictEqualString, binaryop)
+
+ QML_V4_BEGIN_INSTR(StrictNotEqualString, binaryop)
+ {
+ const QString &a = *registers[instr->binaryop.left].getstringptr();
+ const QString &b = *registers[instr->binaryop.right].getstringptr();
+ bool result = a != b;
+ if (instr->binaryop.left == instr->binaryop.output) {
+ registers[instr->binaryop.output].cleanupString();
+ MARK_CLEAN_REGISTER(instr->binaryop.output);
+ }
+ registers[instr->binaryop.output].setbool(result);
+ }
+ QML_V4_END_INSTR(StrictNotEqualString, binaryop)
+
+ QML_V4_BEGIN_INSTR(NewString, construct)
+ {
+ Register &output = registers[instr->construct.reg];
+ new (output.getstringptr()) QString;
+ STRING_REGISTER(instr->construct.reg);
+ }
+ QML_V4_END_INSTR(NewString, construct)
+
+ QML_V4_BEGIN_INSTR(NewUrl, construct)
+ {
+ Register &output = registers[instr->construct.reg];
+ new (output.geturlptr()) QUrl;
+ URL_REGISTER(instr->construct.reg);
+ }
+ QML_V4_END_INSTR(NewUrl, construct)
+
+ QML_V4_BEGIN_INSTR(Fetch, fetch)
+ {
+ Register &reg = registers[instr->fetch.reg];
+
+ if (reg.isUndefined())
+ THROW_EXCEPTION(instr->fetch.exceptionId);
+
+ QObject *object = reg.getQObject();
+ if (!object) {
+ THROW_EXCEPTION(instr->fetch.exceptionId);
+ } else {
+ reg.init((Register::Type)instr->fetch.valueType);
+ if (instr->fetch.valueType >= FirstCleanupType)
+ MARK_REGISTER(instr->fetch.reg);
+ void *argv[] = { reg.typeDataPtr(), 0 };
+ QMetaObject::metacall(object, QMetaObject::ReadProperty, instr->fetch.index, argv);
+ }
+ }
+ QML_V4_END_INSTR(Fetch, fetch)
+
+ QML_V4_BEGIN_INSTR(TestV4Store, storetest)
+ {
+ Register &data = registers[instr->storetest.reg];
+ testBindingResult(*testBindingSource, bindingLine, bindingColumn, context,
+ scope, data, instr->storetest.regType);
+ }
+ QML_V4_END_INSTR(TestV4Store, storetest)
+
+ QML_V4_BEGIN_INSTR(Store, store)
+ {
+ Register &data = registers[instr->store.reg];
+
+ if (data.isUndefined())
+ THROW_EXCEPTION_STR(instr->store.exceptionId, QLatin1String("Unable to assign undefined value"));
+
+ int status = -1;
+ void *argv[] = { data.typeDataPtr(), 0, &status, &storeFlags };
+ QMetaObject::metacall(output, QMetaObject::WriteProperty,
+ instr->store.index, argv);
+
+ goto programExit;
+ }
+ QML_V4_END_INSTR(Store, store)
+
+ QML_V4_BEGIN_INSTR(Copy, copy)
+ registers[instr->copy.reg].copy(registers[instr->copy.src]);
+ if (registers[instr->copy.reg].gettype() >= FirstCleanupType)
+ MARK_REGISTER(instr->copy.reg);
+ QML_V4_END_INSTR(Copy, copy)
+
+ QML_V4_BEGIN_INSTR(Jump, jump)
+ if (instr->jump.reg == -1 || !registers[instr->jump.reg].getbool())
+ code += instr->jump.count;
+ QML_V4_END_INSTR(Jump, jump)
+
+ QML_V4_BEGIN_INSTR(BranchTrue, branchop)
+ if (registers[instr->branchop.reg].getbool())
+ code += instr->branchop.offset;
+ QML_V4_END_INSTR(BranchTrue, branchop)
+
+ QML_V4_BEGIN_INSTR(BranchFalse, branchop)
+ if (! registers[instr->branchop.reg].getbool())
+ code += instr->branchop.offset;
+ QML_V4_END_INSTR(BranchFalse, branchop)
+
+ QML_V4_BEGIN_INSTR(Branch, branchop)
+ code += instr->branchop.offset;
+ QML_V4_END_INSTR(Branch, branchop)
+
+ QML_V4_BEGIN_INSTR(Block, blockop)
+ executedBlocks |= instr->blockop.block;
+ QML_V4_END_INSTR(Block, blockop)
+
+ // XXX not applicable in v8
+ QML_V4_BEGIN_INSTR(InitString, initstring)
+// if (!identifiers[instr->initstring.offset].identifier) {
+// quint32 len = *(quint32 *)(data + instr->initstring.dataIdx);
+// QChar *strdata = (QChar *)(data + instr->initstring.dataIdx + sizeof(quint32));
+
+// QString str = QString::fromRawData(strdata, len);
+
+// // identifiers[instr->initstring.offset] = engine->objectClass->createPersistentIdentifier(str);
+// }
+ QML_V4_END_INSTR(InitString, initstring)
+
+ QML_V4_BEGIN_INSTR(CleanupRegister, cleanup)
+ registers[instr->cleanup.reg].cleanup();
+ QML_V4_END_INSTR(CleanupRegister, cleanup)
+
+#ifdef QML_THREADED_INTERPRETER
+ // nothing to do
+#else
+ default:
+ qFatal("QV4: Unknown instruction %d encountered.", instr->common.type);
+ break;
+ } // switch
+
+ } // while
+#endif
+
+ Q_ASSERT(!"Unreachable code reached");
+
+programExit:
+exceptionExit:
+ delete testBindingSource;
+
+ int reg = 0;
+ while (cleanupRegisterMask) {
+ if (cleanupRegisterMask & 0x1)
+ registers[reg].cleanup();
+
+ reg++;
+ cleanupRegisterMask >>= 1;
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/v4/qv4bindings_p.h b/src/qml/qml/v4/qv4bindings_p.h
new file mode 100644
index 0000000000..61d29a6f57
--- /dev/null
+++ b/src/qml/qml/v4/qv4bindings_p.h
@@ -0,0 +1,153 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QV4BINDINGS_P_H
+#define QV4BINDINGS_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "private/qqmlexpression_p.h"
+#include "private/qqmlbinding_p.h"
+#include "private/qv4instruction_p.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+struct QV4Program;
+class QV4Bindings : public QQmlAbstractExpression,
+ public QQmlRefCount
+{
+ Q_DECLARE_TR_FUNCTIONS(QV4Bindings)
+public:
+ QV4Bindings(const char *program, QQmlContextData *context,
+ QQmlRefCount *);
+ virtual ~QV4Bindings();
+
+ QQmlAbstractBinding *configBinding(int index, QObject *target,
+ QObject *scope, int property,
+ int line, int column);
+
+#ifdef QML_THREADED_INTERPRETER
+ static void **getDecodeInstrTable();
+#endif
+
+private:
+ Q_DISABLE_COPY(QV4Bindings)
+
+ struct Binding : public QQmlAbstractBinding, public QQmlDelayedError {
+ Binding() : enabled(false), updating(0), property(0),
+ scope(0), target(0), executedBlocks(0), parent(0) {}
+
+ // Inherited from QQmlAbstractBinding
+ virtual void setEnabled(bool, QQmlPropertyPrivate::WriteFlags flags);
+ virtual void update(QQmlPropertyPrivate::WriteFlags flags);
+ virtual void destroy();
+ virtual int propertyIndex() const;
+ virtual QObject *object() const;
+
+ int index:30;
+ bool enabled:1;
+ bool updating:1;
+ int property;
+ QObject *scope;
+ int line;
+ int column;
+ QObject *target;
+ quint32 executedBlocks;
+
+ QV4Bindings *parent;
+ };
+
+ class Subscription : public QQmlNotifierEndpoint
+ {
+ public:
+ Subscription() : bindings(0), method(-1) { callback = &subscriptionCallback; }
+ static void subscriptionCallback(QQmlNotifierEndpoint *e);
+ QV4Bindings *bindings;
+ int method;
+ };
+ friend class Subscription;
+
+ Subscription *subscriptions;
+
+ void subscriptionNotify(int);
+ void run(Binding *, QQmlPropertyPrivate::WriteFlags flags);
+
+ QV4Program *program;
+ QQmlRefCount *dataRef;
+ Binding *bindings;
+
+ void init();
+ void run(int instr, quint32 &executedBlocks, QQmlContextData *context,
+ QQmlDelayedError *error, QObject *scope, QObject *output,
+ QQmlPropertyPrivate::WriteFlags storeFlags
+#ifdef QML_THREADED_INTERPRETER
+ , void ***decode_instr = 0
+#endif
+ );
+
+
+ inline void unsubscribe(int subIndex);
+ inline void subscribeId(QQmlContextData *p, int idIndex, int subIndex);
+ inline void subscribe(QObject *o, int notifyIndex, int subIndex);
+
+ inline static qint32 toInt32(qreal n);
+ static const qreal D32;
+ static quint32 toUint32(qreal n);
+
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QV4BINDINGS_P_H
+
diff --git a/src/qml/qml/v4/qv4compiler.cpp b/src/qml/qml/v4/qv4compiler.cpp
new file mode 100644
index 0000000000..d61fd580c7
--- /dev/null
+++ b/src/qml/qml/v4/qv4compiler.cpp
@@ -0,0 +1,1399 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qv4compiler_p.h"
+#include "qv4compiler_p_p.h"
+#include "qv4program_p.h"
+#include "qv4ir_p.h"
+#include "qv4irbuilder_p.h"
+
+#include <private/qqmlglobal_p.h>
+#include <private/qqmljsast_p.h>
+#include <private/qqmlaccessors_p.h>
+#include <private/qqmljsengine_p.h>
+
+QT_BEGIN_NAMESPACE
+
+DEFINE_BOOL_CONFIG_OPTION(bindingsDump, QML_BINDINGS_DUMP)
+DEFINE_BOOL_CONFIG_OPTION(qmlDisableOptimizer, QML_DISABLE_OPTIMIZER)
+DEFINE_BOOL_CONFIG_OPTION(qmlExperimental, QML_EXPERIMENTAL)
+DEFINE_BOOL_CONFIG_OPTION(qmlVerboseCompiler, QML_VERBOSE_COMPILER)
+DEFINE_BOOL_CONFIG_OPTION(qmlBindingsTestEnv, QML_BINDINGS_TEST)
+
+static bool qmlBindingsTest = false;
+static bool qmlEnableV4 = true;
+
+using namespace QQmlJS;
+QV4CompilerPrivate::QV4CompilerPrivate()
+: _function(0) , _block(0) , _discarded(false)
+{
+}
+
+//
+// tracing
+//
+void QV4CompilerPrivate::trace(int line, int column)
+{
+ bytecode.clear();
+
+ this->currentReg = _function->tempCount;
+
+ foreach (IR::BasicBlock *bb, _function->basicBlocks) {
+ if (! bb->isTerminated() && (bb->index + 1) < _function->basicBlocks.size())
+ bb->JUMP(_function->basicBlocks.at(bb->index + 1));
+ }
+
+ QVector<IR::BasicBlock *> blocks;
+ trace(&blocks);
+ currentBlockMask = 0x00000001;
+
+
+ for (int i = 0; !_discarded && i < blocks.size(); ++i) {
+ IR::BasicBlock *block = blocks.at(i);
+ IR::BasicBlock *next = i + 1 < blocks.size() ? blocks.at(i + 1) : 0;
+ if (IR::Stmt *terminator = block->terminator()) {
+ if (IR::CJump *cj = terminator->asCJump()) {
+ if (cj->iffalse != next) {
+ IR::Jump *jump = _function->pool->New<IR::Jump>();
+ jump->init(cj->iffalse);
+ block->statements.append(jump);
+ }
+ } else if (IR::Jump *j = terminator->asJump()) {
+ if (j->target == next) {
+ block->statements.resize(block->statements.size() - 1);
+ }
+ }
+ }
+
+ block->offset = bytecode.size();
+
+ if (bytecode.isEmpty()) {
+ if (qmlBindingsTest || bindingsDump()) {
+ Instr::BindingId id;
+ id.column = column;
+ id.line = line;
+ gen(id);
+ }
+
+ if (qmlBindingsTest) {
+ QString str = expression->expression.asScript();
+ QByteArray strdata((const char *)str.constData(), str.length() * sizeof(QChar));
+ int offset = data.count();
+ data += strdata;
+
+ Instr::EnableV4Test test;
+ test.reg = 0;
+ test.offset = offset;
+ test.length = str.length();
+ gen(test);
+ }
+ }
+
+ bool usic = false;
+ int patchesCount = patches.count();
+ qSwap(usedSubscriptionIdsChanged, usic);
+
+ int blockopIndex = bytecode.size();
+ Instr::Block blockop;
+ blockop.block = currentBlockMask;
+ gen(blockop);
+
+ foreach (IR::Stmt *s, block->statements) {
+ if (! _discarded)
+ s->accept(this);
+ }
+
+ qSwap(usedSubscriptionIdsChanged, usic);
+
+ if (usic) {
+ if (currentBlockMask == 0x80000000) {
+ discard();
+ return;
+ }
+ currentBlockMask <<= 1;
+ } else if (! _discarded) {
+ const int adjust = bytecode.remove(blockopIndex);
+ // Correct patches
+ for (int ii = patchesCount; ii < patches.count(); ++ii)
+ patches[ii].offset -= adjust;
+ }
+ }
+
+#ifdef DEBUG_IR_STRUCTURE
+ IR::IRDump dump;
+ for (int i = 0; i < blocks.size(); ++i) {
+ dump.basicblock(blocks.at(i));
+ }
+#endif
+
+
+ if (! _discarded) {
+ // back patching
+ foreach (const Patch &patch, patches) {
+ V4Instr &instr = bytecode[patch.offset];
+ int size = V4Instr::size(instructionType(&instr));
+ instr.branchop.offset = patch.block->offset - patch.offset - size;
+ }
+
+ patches.clear();
+ }
+}
+
+void QV4CompilerPrivate::trace(QVector<IR::BasicBlock *> *blocks)
+{
+ for (int i = 0; i < _function->basicBlocks.size(); ++i) {
+ IR::BasicBlock *block = _function->basicBlocks.at(i);
+
+ while (! blocks->contains(block)) {
+ blocks->append(block);
+
+ if (IR::Stmt *terminator = block->terminator()) {
+ if (IR::CJump *cj = terminator->asCJump())
+ block = cj->iffalse;
+ else if (IR::Jump *j = terminator->asJump())
+ block = j->target;
+ }
+ }
+ }
+}
+
+void QV4CompilerPrivate::traceExpression(IR::Expr *e, quint8 r)
+{
+ if (!e) {
+ discard();
+ } else {
+ qSwap(currentReg, r);
+ e->accept(this);
+ qSwap(currentReg, r);
+ }
+}
+
+//
+// expressions
+//
+void QV4CompilerPrivate::visitConst(IR::Const *e)
+{
+ switch (e->type) {
+ case IR::BoolType: {
+ Instr::LoadBool i;
+ i.reg = currentReg;
+ i.value = e->value;
+ gen(i);
+ } break;
+
+ case IR::IntType: {
+ Instr::LoadInt i;
+ i.reg = currentReg;
+ i.value = e->value;
+ gen(i);
+ } break;
+
+ case IR::RealType: {
+ Instr::LoadReal i;
+ i.reg = currentReg;
+ i.value = e->value;
+ gen(i);
+ } break;
+
+ default:
+ if (qmlVerboseCompiler())
+ qWarning() << Q_FUNC_INFO << "unexpected type";
+ discard();
+ }
+}
+
+void QV4CompilerPrivate::visitString(IR::String *e)
+{
+ registerLiteralString(currentReg, e->value);
+}
+
+void QV4CompilerPrivate::visitName(IR::Name *e)
+{
+ if (e->base) {
+ // fetch the object and store it in reg.
+ traceExpression(e->base, currentReg);
+ } else {
+ _subscribeName.clear();
+ }
+
+ if (e->storage == IR::Name::RootStorage) {
+
+ Instr::LoadRoot instr;
+ instr.reg = currentReg;
+ gen(instr);
+
+ if (e->symbol == IR::Name::IdObject) {
+ // The ID is a reference to the root object
+ return;
+ }
+
+ } else if (e->storage == IR::Name::ScopeStorage) {
+
+ Instr::LoadScope instr;
+ instr.reg = currentReg;
+ gen(instr);
+
+ _subscribeName << contextName();
+
+ } else if (e->storage == IR::Name::IdStorage) {
+
+ Instr::LoadId instr;
+ instr.reg = currentReg;
+ instr.index = e->idObject->idIndex;
+ gen(instr);
+
+ _subscribeName << QLatin1String("$$$ID_") + *e->id;
+
+ if (blockNeedsSubscription(_subscribeName)) {
+ Instr::SubscribeId sub;
+ sub.reg = currentReg;
+ sub.offset = subscriptionIndex(_subscribeName);
+ sub.index = instr.index;
+ gen(sub);
+ }
+
+ return;
+ } else {
+ // No action needed
+ }
+
+ switch (e->symbol) {
+ case IR::Name::Unbound:
+ case IR::Name::IdObject:
+ case IR::Name::Slot:
+ case IR::Name::Object: {
+ Q_ASSERT(!"Unreachable");
+ discard();
+ } break;
+
+ case IR::Name::AttachType: {
+ _subscribeName << *e->id;
+
+ Instr::LoadAttached attached;
+ attached.output = currentReg;
+ attached.reg = currentReg;
+ attached.exceptionId = exceptionId(e->line, e->column);
+ if (e->declarativeType->attachedPropertiesId() == -1)
+ discard();
+ attached.id = e->declarativeType->attachedPropertiesId();
+ gen(attached);
+ } break;
+
+ case IR::Name::Property: {
+ _subscribeName << *e->id;
+
+ if (e->property->coreIndex == -1) {
+ QMetaProperty prop;
+ e->property->load(prop, QQmlEnginePrivate::get(engine));
+ }
+
+ const int propTy = e->property->propType;
+ QQmlRegisterType regType;
+
+ switch (propTy) {
+ case QMetaType::QReal:
+ regType = QRealType;
+ break;
+ case QMetaType::Bool:
+ regType = BoolType;
+ break;
+ case QMetaType::Int:
+ regType = IntType;
+ break;
+ case QMetaType::QString:
+ regType = QStringType;
+ break;
+ case QMetaType::QUrl:
+ regType = QUrlType;
+ break;
+
+ default:
+ if (propTy == QQmlMetaType::QQuickAnchorLineMetaTypeId()) {
+ regType = PODValueType;
+ } else if (QQmlMetaType::isQObject(propTy)) {
+ regType = QObjectStarType;
+ } else {
+ if (qmlVerboseCompiler())
+ qWarning() << "Discard unsupported property type:" << QMetaType::typeName(propTy);
+ discard(); // Unsupported type
+ return;
+ }
+
+ break;
+ } // switch
+
+ if (e->property->hasAccessors()) {
+ Instr::FetchAndSubscribe fetch;
+ fetch.reg = currentReg;
+ fetch.subscription = subscriptionIndex(_subscribeName);
+ fetch.exceptionId = exceptionId(e->line, e->column);
+ fetch.valueType = regType;
+ fetch.property = *e->property;
+ gen(fetch);
+ } else {
+ if (blockNeedsSubscription(_subscribeName) && e->property->notifyIndex != -1) {
+ Instr::Subscribe sub;
+ sub.reg = currentReg;
+ sub.offset = subscriptionIndex(_subscribeName);
+ sub.index = e->property->notifyIndex;
+ gen(sub);
+ }
+
+ Instr::Fetch fetch;
+ fetch.reg = currentReg;
+ fetch.index = e->property->coreIndex;
+ fetch.exceptionId = exceptionId(e->line, e->column);
+ fetch.valueType = regType;
+ gen(fetch);
+ }
+
+ } break;
+ } // switch
+}
+
+void QV4CompilerPrivate::visitTemp(IR::Temp *e)
+{
+ if (currentReg != e->index) {
+ Instr::Copy i;
+ i.reg = currentReg;
+ i.src = e->index;
+ gen(i);
+ }
+}
+
+void QV4CompilerPrivate::visitUnop(IR::Unop *e)
+{
+ quint8 src = currentReg;
+
+ if (IR::Temp *temp = e->expr->asTemp()) {
+ src = temp->index;
+ } else {
+ traceExpression(e->expr, src);
+ }
+
+ switch (e->op) {
+ case IR::OpInvalid:
+ Q_ASSERT(!"unreachable");
+ break;
+
+ case IR::OpIfTrue:
+ convertToBool(e->expr, src);
+ if (src != currentReg) {
+ Instr::Copy i;
+ i.reg = currentReg;
+ i.src = src;
+ gen(i);
+ }
+ break;
+
+ case IR::OpNot: {
+ Instr::UnaryNot i;
+ convertToBool(e->expr, src);
+ i.output = currentReg;
+ i.src = src;
+ gen(i);
+ } break;
+
+ case IR::OpUMinus:
+ if (e->expr->type == IR::RealType) {
+ Instr::UnaryMinusReal i;
+ i.output = currentReg;
+ i.src = src;
+ gen(i);
+ } else if (e->expr->type == IR::IntType) {
+ convertToReal(e->expr, currentReg);
+ Instr::UnaryMinusReal i;
+ i.output = currentReg;
+ i.src = src;
+ gen(i);
+ } else {
+ discard();
+ }
+ break;
+
+ case IR::OpUPlus:
+ if (e->expr->type == IR::RealType) {
+ Instr::UnaryPlusReal i;
+ i.output = currentReg;
+ i.src = src;
+ gen(i);
+ } else if (e->expr->type == IR::IntType) {
+ convertToReal(e->expr, currentReg);
+ Instr::UnaryPlusReal i;
+ i.output = currentReg;
+ i.src = src;
+ gen(i);
+ } else {
+ discard();
+ }
+ break;
+
+ case IR::OpCompl:
+ // TODO
+ discard();
+ break;
+
+ case IR::OpBitAnd:
+ case IR::OpBitOr:
+ case IR::OpBitXor:
+ case IR::OpAdd:
+ case IR::OpSub:
+ case IR::OpMul:
+ case IR::OpDiv:
+ case IR::OpMod:
+ case IR::OpLShift:
+ case IR::OpRShift:
+ case IR::OpURShift:
+ case IR::OpGt:
+ case IR::OpLt:
+ case IR::OpGe:
+ case IR::OpLe:
+ case IR::OpEqual:
+ case IR::OpNotEqual:
+ case IR::OpStrictEqual:
+ case IR::OpStrictNotEqual:
+ case IR::OpAnd:
+ case IR::OpOr:
+ Q_ASSERT(!"unreachable");
+ break;
+ } // switch
+}
+
+void QV4CompilerPrivate::convertToReal(IR::Expr *expr, int reg)
+{
+ if (expr->type == IR::RealType)
+ return;
+
+ switch (expr->type) {
+ case IR::BoolType: {
+ Instr::ConvertBoolToReal i;
+ i.output = i.src = reg;
+ gen(i);
+ } break;
+
+ case IR::IntType: {
+ Instr::ConvertIntToReal i;
+ i.output = i.src = reg;
+ gen(i);
+ } break;
+
+ case IR::RealType:
+ // nothing to do
+ return;
+
+ default:
+ discard();
+ break;
+ } // switch
+}
+
+void QV4CompilerPrivate::convertToInt(IR::Expr *expr, int reg)
+{
+ if (expr->type == IR::IntType)
+ return;
+
+ switch (expr->type) {
+ case IR::BoolType: {
+ Instr::ConvertBoolToInt i;
+ i.output = i.src = reg;
+ gen(i);
+ } break;
+
+ case IR::IntType:
+ // nothing to do
+ return;
+
+ case IR::RealType: {
+ Instr::ConvertRealToInt i;
+ i.output = i.src = reg;
+ gen(i);
+ } break;
+
+ default:
+ discard();
+ break;
+ } // switch
+}
+
+void QV4CompilerPrivate::convertToBool(IR::Expr *expr, int reg)
+{
+ if (expr->type == IR::BoolType)
+ return;
+
+ switch (expr->type) {
+ case IR::BoolType:
+ // nothing to do
+ break;
+
+ case IR::IntType: {
+ Instr::ConvertIntToBool i;
+ i.output = i.src = reg;
+ gen(i);
+ } break;
+
+ case IR::RealType: {
+ Instr::ConvertRealToBool i;
+ i.output = i.src = reg;
+ gen(i);
+ } return;
+
+ case IR::StringType: {
+ Instr::ConvertStringToBool i;
+ i.output = i.src = reg;
+ gen(i);
+ } return;
+
+ default:
+ discard();
+ break;
+ } // switch
+}
+
+quint8 QV4CompilerPrivate::instructionOpcode(IR::Binop *e)
+{
+ switch (e->op) {
+ case IR::OpInvalid:
+ return V4Instr::Noop;
+
+ case IR::OpIfTrue:
+ case IR::OpNot:
+ case IR::OpUMinus:
+ case IR::OpUPlus:
+ case IR::OpCompl:
+ return V4Instr::Noop;
+
+ case IR::OpBitAnd:
+ return V4Instr::BitAndInt;
+
+ case IR::OpBitOr:
+ return V4Instr::BitOrInt;
+
+ case IR::OpBitXor:
+ return V4Instr::BitXorInt;
+
+ case IR::OpAdd:
+ if (e->type == IR::StringType)
+ return V4Instr::AddString;
+ return V4Instr::AddReal;
+
+ case IR::OpSub:
+ return V4Instr::SubReal;
+
+ case IR::OpMul:
+ return V4Instr::MulReal;
+
+ case IR::OpDiv:
+ return V4Instr::DivReal;
+
+ case IR::OpMod:
+ return V4Instr::ModReal;
+
+ case IR::OpLShift:
+ return V4Instr::LShiftInt;
+
+ case IR::OpRShift:
+ return V4Instr::RShiftInt;
+
+ case IR::OpURShift:
+ return V4Instr::URShiftInt;
+
+ case IR::OpGt:
+ if (e->left->type == IR::StringType)
+ return V4Instr::GtString;
+ return V4Instr::GtReal;
+
+ case IR::OpLt:
+ if (e->left->type == IR::StringType)
+ return V4Instr::LtString;
+ return V4Instr::LtReal;
+
+ case IR::OpGe:
+ if (e->left->type == IR::StringType)
+ return V4Instr::GeString;
+ return V4Instr::GeReal;
+
+ case IR::OpLe:
+ if (e->left->type == IR::StringType)
+ return V4Instr::LeString;
+ return V4Instr::LeReal;
+
+ case IR::OpEqual:
+ if (e->left->type == IR::StringType)
+ return V4Instr::EqualString;
+ return V4Instr::EqualReal;
+
+ case IR::OpNotEqual:
+ if (e->left->type == IR::StringType)
+ return V4Instr::NotEqualString;
+ return V4Instr::NotEqualReal;
+
+ case IR::OpStrictEqual:
+ if (e->left->type == IR::StringType)
+ return V4Instr::StrictEqualString;
+ return V4Instr::StrictEqualReal;
+
+ case IR::OpStrictNotEqual:
+ if (e->left->type == IR::StringType)
+ return V4Instr::StrictNotEqualString;
+ return V4Instr::StrictNotEqualReal;
+
+ case IR::OpAnd:
+ case IR::OpOr:
+ return V4Instr::Noop;
+
+ } // switch
+
+ return V4Instr::Noop;
+}
+
+void QV4CompilerPrivate::visitBinop(IR::Binop *e)
+{
+ int left = currentReg;
+ int right = currentReg + 1;
+
+ if (e->left->asTemp() && e->type != IR::StringType) // Not sure if the e->type != String test is needed
+ left = e->left->asTemp()->index;
+ else
+ traceExpression(e->left, left);
+
+ if (IR::Temp *t = e->right->asTemp())
+ right = t->index;
+ else
+ traceExpression(e->right, right);
+
+ if (e->left->type != e->right->type) {
+ if (qmlVerboseCompiler())
+ qWarning().nospace() << "invalid operands to binary operator " << IR::binaryOperator(e->op)
+ << "(`" << IR::binaryOperator(e->left->type)
+ << "' and `"
+ << IR::binaryOperator(e->right->type)
+ << "'";
+ discard();
+ return;
+ }
+
+ switch (e->op) {
+ case IR::OpInvalid:
+ discard();
+ break;
+
+ // unary
+ case IR::OpIfTrue:
+ case IR::OpNot:
+ case IR::OpUMinus:
+ case IR::OpUPlus:
+ case IR::OpCompl:
+ discard();
+ break;
+
+ case IR::OpBitAnd:
+ case IR::OpBitOr:
+ case IR::OpBitXor:
+ case IR::OpLShift:
+ case IR::OpRShift:
+ case IR::OpURShift:
+ convertToInt(e->left, left);
+ convertToInt(e->right, right);
+ break;
+
+ case IR::OpAdd:
+ if (e->type != IR::StringType) {
+ convertToReal(e->left, left);
+ convertToReal(e->right, right);
+ }
+ break;
+
+ case IR::OpSub:
+ case IR::OpMul:
+ case IR::OpDiv:
+ case IR::OpMod:
+ convertToReal(e->left, left);
+ convertToReal(e->right, right);
+ break;
+
+ case IR::OpGt:
+ case IR::OpLt:
+ case IR::OpGe:
+ case IR::OpLe:
+ case IR::OpEqual:
+ case IR::OpNotEqual:
+ case IR::OpStrictEqual:
+ case IR::OpStrictNotEqual:
+ if (e->left->type != IR::StringType) {
+ convertToReal(e->left, left);
+ convertToReal(e->right, right);
+ }
+ break;
+
+ case IR::OpAnd:
+ case IR::OpOr:
+ discard(); // ### unreachable
+ break;
+ } // switch
+
+ const quint8 opcode = instructionOpcode(e);
+ if (opcode != V4Instr::Noop) {
+ V4Instr instr;
+ instr.binaryop.output = currentReg;
+ instr.binaryop.left = left;
+ instr.binaryop.right = right;
+ gen(static_cast<V4Instr::Type>(opcode), instr);
+ }
+}
+
+void QV4CompilerPrivate::visitCall(IR::Call *call)
+{
+ if (IR::Name *name = call->base->asName()) {
+ IR::Expr *arg = call->onlyArgument();
+ if (arg != 0 && arg->type == IR::RealType) {
+ traceExpression(arg, currentReg);
+
+ switch (name->builtin) {
+ case IR::NoBuiltinSymbol:
+ break;
+
+ case IR::MathSinBultinFunction: {
+ Instr::MathSinReal i;
+ i.output = i.src = currentReg;
+ gen(i);
+ } return;
+
+ case IR::MathCosBultinFunction: {
+ Instr::MathCosReal i;
+ i.output = i.src = currentReg;
+ gen(i);
+ } return;
+
+ case IR::MathRoundBultinFunction: {
+ Instr::MathRoundReal i;
+ i.output = i.src = currentReg;
+ gen(i);
+ } return;
+
+ case IR::MathFloorBultinFunction: {
+ Instr::MathFloorReal i;
+ i.output = i.src = currentReg;
+ gen(i);
+ } return;
+
+ case IR::MathPIBuiltinConstant:
+ break;
+ } // switch
+ }
+ }
+
+ if (qmlVerboseCompiler())
+ qWarning() << "TODO:" << Q_FUNC_INFO << __LINE__;
+ discard();
+}
+
+
+//
+// statements
+//
+void QV4CompilerPrivate::visitExp(IR::Exp *s)
+{
+ traceExpression(s->expr, currentReg);
+}
+
+void QV4CompilerPrivate::visitMove(IR::Move *s)
+{
+ IR::Temp *target = s->target->asTemp();
+ Q_ASSERT(target != 0);
+
+ quint8 dest = target->index;
+
+ if (target->type != s->source->type) {
+ quint8 src = dest;
+
+ if (IR::Temp *t = s->source->asTemp())
+ src = t->index;
+ else
+ traceExpression(s->source, dest);
+
+ V4Instr::Type opcode = V4Instr::Noop;
+ IR::Type targetTy = s->target->type;
+ IR::Type sourceTy = s->source->type;
+
+ if (sourceTy == IR::UrlType) {
+ switch (targetTy) {
+ case IR::BoolType:
+ case IR::StringType:
+ // nothing to do. V4 will generate optimized
+ // url-to-xxx conversions.
+ break;
+ default: {
+ // generate a UrlToString conversion and fix
+ // the type of the source expression.
+ V4Instr conv;
+ conv.unaryop.output = V4Instr::ConvertUrlToString;
+ conv.unaryop.src = src;
+ gen(opcode, conv);
+
+ sourceTy = IR::StringType;
+ break;
+ }
+ } // switch
+ }
+
+ if (targetTy == IR::BoolType) {
+ switch (sourceTy) {
+ case IR::IntType: opcode = V4Instr::ConvertIntToBool; break;
+ case IR::RealType: opcode = V4Instr::ConvertRealToBool; break;
+ case IR::StringType: opcode = V4Instr::ConvertStringToBool; break;
+ case IR::UrlType: opcode = V4Instr::ConvertUrlToBool; break;
+ default: break;
+ } // switch
+ } else if (targetTy == IR::IntType) {
+ switch (sourceTy) {
+ case IR::BoolType: opcode = V4Instr::ConvertBoolToInt; break;
+ case IR::RealType: {
+ if (s->isMoveForReturn)
+ opcode = V4Instr::MathRoundReal;
+ else
+ opcode = V4Instr::ConvertRealToInt;
+ break;
+ }
+ case IR::StringType: opcode = V4Instr::ConvertStringToInt; break;
+ default: break;
+ } // switch
+ } else if (targetTy == IR::RealType) {
+ switch (sourceTy) {
+ case IR::BoolType: opcode = V4Instr::ConvertBoolToReal; break;
+ case IR::IntType: opcode = V4Instr::ConvertIntToReal; break;
+ case IR::StringType: opcode = V4Instr::ConvertStringToReal; break;
+ default: break;
+ } // switch
+ } else if (targetTy == IR::StringType) {
+ switch (sourceTy) {
+ case IR::BoolType: opcode = V4Instr::ConvertBoolToString; break;
+ case IR::IntType: opcode = V4Instr::ConvertIntToString; break;
+ case IR::RealType: opcode = V4Instr::ConvertRealToString; break;
+ case IR::UrlType: opcode = V4Instr::ConvertUrlToString; break;
+ default: break;
+ } // switch
+ } else if (targetTy == IR::UrlType) {
+ V4Instr convToString;
+ convToString.unaryop.output = dest;
+ convToString.unaryop.src = src;
+
+ // try to convert the source expression to a string.
+ switch (sourceTy) {
+ case IR::BoolType: gen(V4Instr::ConvertBoolToString, convToString); sourceTy = IR::StringType; break;
+ case IR::IntType: gen(V4Instr::ConvertIntToString, convToString); sourceTy = IR::StringType; break;
+ case IR::RealType: gen(V4Instr::ConvertRealToString, convToString); sourceTy = IR::StringType; break;
+ default: break;
+ } // switch
+
+ if (sourceTy == IR::StringType)
+ opcode = V4Instr::ConvertStringToUrl;
+ }
+ if (opcode != V4Instr::Noop) {
+ V4Instr conv;
+ conv.unaryop.output = dest;
+ conv.unaryop.src = src;
+ gen(opcode, conv);
+
+ if (s->isMoveForReturn && opcode == V4Instr::ConvertStringToUrl) {
+ V4Instr resolveUrl;
+ resolveUrl.unaryop.output = dest;
+ resolveUrl.unaryop.src = dest;
+ gen(V4Instr::ResolveUrl, resolveUrl);
+ }
+ } else {
+ discard();
+ }
+ } else {
+ traceExpression(s->source, dest);
+ }
+}
+
+void QV4CompilerPrivate::visitJump(IR::Jump *s)
+{
+ patches.append(Patch(s->target, bytecode.size()));
+
+ Instr::Branch i;
+ i.offset = 0; // ### backpatch
+ gen(i);
+}
+
+void QV4CompilerPrivate::visitCJump(IR::CJump *s)
+{
+ traceExpression(s->cond, currentReg);
+
+ patches.append(Patch(s->iftrue, bytecode.size()));
+
+ Instr::BranchTrue i;
+ i.reg = currentReg;
+ i.offset = 0; // ### backpatch
+ gen(i);
+}
+
+void QV4CompilerPrivate::visitRet(IR::Ret *s)
+{
+ Q_ASSERT(s->expr != 0);
+
+ int storeReg = currentReg;
+
+ if (IR::Temp *temp = s->expr->asTemp()) {
+ storeReg = temp->index;
+ } else {
+ traceExpression(s->expr, storeReg);
+ }
+
+ if (qmlBindingsTest) {
+ Instr::TestV4Store test;
+ test.reg = storeReg;
+ switch (s->type) {
+ case IR::StringType:
+ test.regType = QMetaType::QString;
+ break;
+ case IR::UrlType:
+ test.regType = QMetaType::QUrl;
+ break;
+ case IR::SGAnchorLineType:
+ test.regType = QQmlMetaType::QQuickAnchorLineMetaTypeId();
+ break;
+ case IR::ObjectType:
+ test.regType = QMetaType::QObjectStar;
+ break;
+ case IR::BoolType:
+ test.regType = QMetaType::Bool;
+ break;
+ case IR::IntType:
+ test.regType = QMetaType::Int;
+ break;
+ case IR::RealType:
+ test.regType = QMetaType::QReal;
+ break;
+ default:
+ discard();
+ return;
+ }
+ gen(test);
+ }
+
+ Instr::Store store;
+ store.output = 0;
+ store.index = expression->property->index;
+ store.reg = storeReg;
+ store.exceptionId = exceptionId(s->line, s->column);
+ gen(store);
+}
+
+void QV4Compiler::dump(const QByteArray &programData)
+{
+ const QV4Program *program = (const QV4Program *)programData.constData();
+
+ qWarning() << "Program.bindings:" << program->bindings;
+ qWarning() << "Program.dataLength:" << program->dataLength;
+ qWarning() << "Program.subscriptions:" << program->subscriptions;
+ qWarning() << "Program.indentifiers:" << program->identifiers;
+
+ const int programSize = program->instructionCount;
+ const char *start = program->instructions();
+ const char *end = start + programSize;
+ Bytecode bc;
+ bc.dump(start, end);
+}
+
+/*!
+Clear the state associated with attempting to compile a specific binding.
+This does not clear the global "committed binding" states.
+*/
+void QV4CompilerPrivate::resetInstanceState()
+{
+ data = committed.data;
+ exceptions = committed.exceptions;
+ usedSubscriptionIds.clear();
+ subscriptionIds = committed.subscriptionIds;
+ registeredStrings = committed.registeredStrings;
+ bytecode.clear();
+ patches.clear();
+ pool.clear();
+ currentReg = 0;
+}
+
+/*!
+Mark the last compile as successful, and add it to the "committed data"
+section.
+
+Returns the index for the committed binding.
+*/
+int QV4CompilerPrivate::commitCompile()
+{
+ int rv = committed.count();
+ committed.offsets << committed.bytecode.count();
+ committed.dependencies << usedSubscriptionIds;
+ committed.bytecode.append(bytecode.constData(), bytecode.size());
+ committed.data = data;
+ committed.exceptions = exceptions;
+ committed.subscriptionIds = subscriptionIds;
+ committed.registeredStrings = registeredStrings;
+ return rv;
+}
+
+bool QV4CompilerPrivate::compile(QQmlJS::AST::Node *node)
+{
+ resetInstanceState();
+
+ if (expression->property->type == -1)
+ return false;
+
+ AST::SourceLocation location;
+ if (AST::ExpressionNode *astExpression = node->expressionCast()) {
+ location = astExpression->firstSourceLocation();
+ } else if (AST::Statement *astStatement = node->statementCast()) {
+ if (AST::Block *block = AST::cast<AST::Block *>(astStatement))
+ location = block->lbraceToken;
+ else if (AST::IfStatement *ifStmt = AST::cast<AST::IfStatement *>(astStatement))
+ location = ifStmt->ifToken;
+ else
+ return false;
+ } else {
+ return false;
+ }
+
+ IR::Function thisFunction(&pool), *function = &thisFunction;
+
+ QV4IRBuilder irBuilder(expression, engine);
+ if (!irBuilder(function, node))
+ return false;
+
+ bool discarded = false;
+ qSwap(_discarded, discarded);
+ qSwap(_function, function);
+ trace(location.startLine, location.startColumn);
+ qSwap(_function, function);
+ qSwap(_discarded, discarded);
+
+ if (qmlVerboseCompiler()) {
+ QTextStream qerr(stderr, QIODevice::WriteOnly);
+ if (discarded)
+ qerr << "======== TODO ====== " << endl;
+ else
+ qerr << "==================== " << endl;
+ qerr << "\tline: " << location.startLine
+ << "\tcolumn: " << location.startColumn
+ << endl;
+ foreach (IR::BasicBlock *bb, function->basicBlocks)
+ bb->dump(qerr);
+ qerr << endl;
+ }
+
+ if (discarded || subscriptionIds.count() > 0xFFFF || registeredStrings.count() > 0xFFFF)
+ return false;
+
+ return true;
+}
+
+// Returns a reg
+int QV4CompilerPrivate::registerLiteralString(quint8 reg, const QStringRef &str)
+{
+ // ### string cleanup
+
+ QByteArray strdata((const char *)str.constData(), str.length() * sizeof(QChar));
+ int offset = data.count();
+ data += strdata;
+
+ Instr::LoadString string;
+ string.reg = reg;
+ string.offset = offset;
+ string.length = str.length();
+ gen(string);
+
+ return reg;
+}
+
+// Returns an identifier offset
+int QV4CompilerPrivate::registerString(const QString &string)
+{
+ Q_ASSERT(!string.isEmpty());
+
+ QPair<int, int> *iter = registeredStrings.value(string);
+
+ if (!iter) {
+ quint32 len = string.length();
+ QByteArray lendata((const char *)&len, sizeof(quint32));
+ QByteArray strdata((const char *)string.constData(), string.length() * sizeof(QChar));
+ strdata.prepend(lendata);
+ int rv = data.count();
+ data += strdata;
+
+ iter = &registeredStrings[string];
+ *iter = qMakePair(registeredStrings.count(), rv);
+ }
+
+ Instr::InitString reg;
+ reg.offset = iter->first;
+ reg.dataIdx = iter->second;
+ gen(reg);
+ return reg.offset;
+}
+
+/*!
+Returns true if the current expression has not already subscribed to \a sub in currentBlockMask.
+*/
+bool QV4CompilerPrivate::blockNeedsSubscription(const QStringList &sub)
+{
+ QString str = sub.join(QLatin1String("."));
+
+ int *iter = subscriptionIds.value(str);
+ if (!iter)
+ return true;
+
+ quint32 *uiter = usedSubscriptionIds.value(*iter);
+ if (!uiter)
+ return true;
+ else
+ return !(*uiter & currentBlockMask);
+}
+
+int QV4CompilerPrivate::subscriptionIndex(const QStringList &sub)
+{
+ QString str = sub.join(QLatin1String("."));
+ int *iter = subscriptionIds.value(str);
+ if (!iter) {
+ int count = subscriptionIds.count();
+ iter = &subscriptionIds[str];
+ *iter = count;
+ }
+ quint32 &u = usedSubscriptionIds[*iter];
+ if (!(u & currentBlockMask)) {
+ u |= currentBlockMask;
+ usedSubscriptionIdsChanged = true;
+ }
+ return *iter;
+}
+
+quint32 QV4CompilerPrivate::subscriptionBlockMask(const QStringList &sub)
+{
+ QString str = sub.join(QLatin1String("."));
+
+ int *iter = subscriptionIds.value(str);
+ Q_ASSERT(iter != 0);
+
+ quint32 *uiter = usedSubscriptionIds.value(*iter);
+ Q_ASSERT(uiter != 0);
+
+ return *uiter;
+}
+
+quint8 QV4CompilerPrivate::exceptionId(quint32 line, quint32 column)
+{
+ quint8 rv = 0xFF;
+ if (exceptions.count() < 0xFF) {
+ rv = (quint8)exceptions.count();
+ quint64 e = line;
+ e <<= 32;
+ e |= column;
+ exceptions.append(e);
+ }
+ return rv;
+}
+
+quint8 QV4CompilerPrivate::exceptionId(QQmlJS::AST::ExpressionNode *n)
+{
+ quint8 rv = 0xFF;
+ if (n && exceptions.count() < 0xFF) {
+ QQmlJS::AST::SourceLocation l = n->firstSourceLocation();
+ rv = exceptionId(l.startLine, l.startColumn);
+ }
+ return rv;
+}
+
+QV4Compiler::QV4Compiler()
+: d(new QV4CompilerPrivate)
+{
+ qmlBindingsTest |= qmlBindingsTestEnv();
+}
+
+QV4Compiler::~QV4Compiler()
+{
+ delete d; d = 0;
+}
+
+/*
+Returns true if any bindings were compiled.
+*/
+bool QV4Compiler::isValid() const
+{
+ return !d->committed.bytecode.isEmpty();
+}
+
+/*
+-1 on failure, otherwise the binding index to use.
+*/
+int QV4Compiler::compile(const Expression &expression, QQmlEnginePrivate *engine)
+{
+ if (!expression.expression.asAST()) return false;
+
+ if (!qmlExperimental() && expression.property->isValueTypeSubProperty)
+ return -1;
+
+ if (qmlDisableOptimizer() || !qmlEnableV4)
+ return -1;
+
+ d->expression = &expression;
+ d->engine = engine;
+
+ if (d->compile(expression.expression.asAST())) {
+ return d->commitCompile();
+ } else {
+ return -1;
+ }
+}
+
+QByteArray QV4CompilerPrivate::buildSignalTable() const
+{
+ QHash<int, QList<QPair<int, quint32> > > table;
+
+ for (int ii = 0; ii < committed.count(); ++ii) {
+ const QQmlAssociationList<int, quint32> &deps = committed.dependencies.at(ii);
+ for (QQmlAssociationList<int, quint32>::const_iterator iter = deps.begin(); iter != deps.end(); ++iter)
+ table[iter->first].append(qMakePair(ii, iter->second));
+ }
+
+ QVector<quint32> header;
+ QVector<quint32> data;
+ for (int ii = 0; ii < committed.subscriptionIds.count(); ++ii) {
+ header.append(committed.subscriptionIds.count() + data.count());
+ const QList<QPair<int, quint32> > &bindings = table[ii];
+ data.append(bindings.count());
+ for (int jj = 0; jj < bindings.count(); ++jj) {
+ data.append(bindings.at(jj).first);
+ data.append(bindings.at(jj).second);
+ }
+ }
+ header << data;
+
+ return QByteArray((const char *)header.constData(), header.count() * sizeof(quint32));
+}
+
+QByteArray QV4CompilerPrivate::buildExceptionData() const
+{
+ QByteArray rv;
+ rv.resize(committed.exceptions.count() * sizeof(quint64));
+ ::memcpy(rv.data(), committed.exceptions.constData(), rv.size());
+ return rv;
+}
+
+/*
+Returns the compiled program.
+*/
+QByteArray QV4Compiler::program() const
+{
+ QByteArray programData;
+
+ if (isValid()) {
+ QV4Program prog;
+ prog.bindings = d->committed.count();
+
+ Bytecode bc;
+ QV4CompilerPrivate::Instr::Jump jump;
+ jump.reg = -1;
+
+ for (int ii = 0; ii < d->committed.count(); ++ii) {
+ jump.count = d->committed.count() - ii - 1;
+ jump.count*= V4InstrMeta<V4Instr::Jump>::Size;
+ jump.count+= d->committed.offsets.at(ii);
+ bc.append(jump);
+ }
+
+
+ QByteArray bytecode;
+ bytecode.reserve(bc.size() + d->committed.bytecode.size());
+ bytecode.append(bc.constData(), bc.size());
+ bytecode.append(d->committed.bytecode.constData(), d->committed.bytecode.size());
+
+ QByteArray data = d->committed.data;
+ while (data.count() % 4) data.append('\0');
+ prog.signalTableOffset = data.count();
+ data += d->buildSignalTable();
+ while (data.count() % 4) data.append('\0');
+ prog.exceptionDataOffset = data.count();
+ data += d->buildExceptionData();
+
+ prog.dataLength = 4 * ((data.size() + 3) / 4);
+ prog.subscriptions = d->committed.subscriptionIds.count();
+ prog.identifiers = d->committed.registeredStrings.count();
+ prog.instructionCount = bytecode.count();
+ int size = sizeof(QV4Program) + bytecode.count();
+ size += prog.dataLength;
+
+ programData.resize(size);
+ memcpy(programData.data(), &prog, sizeof(QV4Program));
+ if (prog.dataLength)
+ memcpy((char *)((QV4Program *)programData.data())->data(), data.constData(),
+ data.size());
+ memcpy((char *)((QV4Program *)programData.data())->instructions(), bytecode.constData(),
+ bytecode.count());
+ }
+
+ if (bindingsDump()) {
+ qWarning().nospace() << "Subscription slots:";
+
+ for (QQmlAssociationList<QString, int>::ConstIterator iter = d->committed.subscriptionIds.begin();
+ iter != d->committed.subscriptionIds.end();
+ ++iter) {
+ qWarning().nospace() << " " << iter->first << "\t-> " << iter->second;
+ }
+
+ QV4Compiler::dump(programData);
+ }
+
+ return programData;
+}
+
+void QV4Compiler::enableBindingsTest(bool e)
+{
+ if (e)
+ qmlBindingsTest = true;
+ else
+ qmlBindingsTest = qmlBindingsTestEnv();
+}
+
+void QV4Compiler::enableV4(bool e)
+{
+ qmlEnableV4 = e;
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/v4/qv4compiler_p.h b/src/qml/qml/v4/qv4compiler_p.h
new file mode 100644
index 0000000000..a93248ad14
--- /dev/null
+++ b/src/qml/qml/v4/qv4compiler_p.h
@@ -0,0 +1,105 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QV4COMPILER_P_H
+#define QV4COMPILER_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qqmlexpression_p.h>
+#include <private/qqmlbinding_p.h>
+#include <private/qqmlcompiler_p.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class QQmlTypeNameCache;
+class QV4CompilerPrivate;
+class Q_AUTOTEST_EXPORT QV4Compiler
+{
+public:
+ QV4Compiler();
+ ~QV4Compiler();
+
+ // Returns true if bindings were compiled
+ bool isValid() const;
+
+ struct Expression
+ {
+ Expression(const QQmlImports &imp) : imports(imp) {}
+ QQmlScript::Object *component;
+ QQmlScript::Object *context;
+ QQmlScript::Property *property;
+ QQmlScript::Variant expression;
+ QQmlCompilerTypes::IdList *ids;
+ QQmlTypeNameCache *importCache;
+ QQmlImports imports;
+ };
+
+ // -1 on failure, otherwise the binding index to use
+ int compile(const Expression &, QQmlEnginePrivate *);
+
+ // Returns the compiled program
+ QByteArray program() const;
+
+ static void dump(const QByteArray &);
+ static void enableBindingsTest(bool);
+ static void enableV4(bool);
+private:
+ QV4CompilerPrivate *d;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QV4COMPILER_P_H
+
diff --git a/src/qml/qml/v4/qv4compiler_p_p.h b/src/qml/qml/v4/qv4compiler_p_p.h
new file mode 100644
index 0000000000..4b74a1d1c5
--- /dev/null
+++ b/src/qml/qml/v4/qv4compiler_p_p.h
@@ -0,0 +1,245 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QV4COMPILER_P_P_H
+#define QV4COMPILER_P_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qv4instruction_p.h"
+#include "qv4ir_p.h"
+#include <private/qqmlscript_p.h>
+#include <private/qqmlimport_p.h>
+#include <private/qqmlengine_p.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+template <typename _Key, typename _Value>
+class QQmlAssociationList
+{
+public:
+ typedef QVarLengthArray<QPair<_Key, _Value>, 8> Container;
+ typedef typename Container::const_iterator const_iterator;
+ typedef typename Container::const_iterator ConstIterator;
+
+ const_iterator begin() const { return _container.begin(); }
+ const_iterator end() const { return _container.end(); }
+ int count() const { return _container.count(); }
+ void clear() { _container.clear(); }
+
+ _Value *value(const _Key &key) {
+ for (int i = 0; i < _container.size(); ++i) {
+ QPair<_Key, _Value> &p = _container[i];
+ if (p.first == key)
+ return &p.second;
+ }
+ return 0;
+ }
+
+ _Value &operator[](const _Key &key) {
+ for (int i = 0; i < _container.size(); ++i) {
+ QPair<_Key, _Value> &p = _container[i];
+ if (p.first == key)
+ return p.second;
+ }
+ int index = _container.size();
+ _container.append(qMakePair(key, _Value()));
+ return _container[index].second;
+ }
+
+ void insert(const _Key &key, _Value &value) {
+ for (int i = 0; i < _container.size(); ++i) {
+ QPair<_Key, _Value> &p = _container[i];
+ if (p.first == key) {
+ p.second = value;
+ return;
+ }
+ }
+ _container.append(qMakePair(key, value));
+ }
+
+private:
+ Container _container;
+};
+
+class QV4CompilerPrivate: protected QQmlJS::IR::ExprVisitor,
+ protected QQmlJS::IR::StmtVisitor
+{
+public:
+ QV4CompilerPrivate();
+
+ void resetInstanceState();
+ int commitCompile();
+
+ const QV4Compiler::Expression *expression;
+ QQmlEnginePrivate *engine;
+
+ QString contextName() const { return QLatin1String("$$$SCOPE_") + QString::number((quintptr)expression->context, 16); }
+
+ bool compile(QQmlJS::AST::Node *);
+
+ int registerLiteralString(quint8 reg, const QStringRef &);
+ int registerString(const QString &);
+ QQmlAssociationList<QString, QPair<int, int> > registeredStrings;
+ QByteArray data;
+
+ bool blockNeedsSubscription(const QStringList &);
+ int subscriptionIndex(const QStringList &);
+ quint32 subscriptionBlockMask(const QStringList &);
+
+ quint8 exceptionId(quint32 line, quint32 column);
+ quint8 exceptionId(QQmlJS::AST::ExpressionNode *);
+ QVector<quint64> exceptions;
+
+ QQmlAssociationList<int, quint32> usedSubscriptionIds;
+
+ QQmlAssociationList<QString, int> subscriptionIds;
+ QQmlJS::Bytecode bytecode;
+
+ // back patching
+ struct Patch {
+ QQmlJS::IR::BasicBlock *block; // the basic block
+ int offset; // the index of the instruction to patch
+ Patch(QQmlJS::IR::BasicBlock *block = 0, int index = -1)
+ : block(block), offset(index) {}
+ };
+ QVector<Patch> patches;
+ QQmlPool pool;
+
+ // Committed binding data
+ struct {
+ QList<int> offsets;
+ QList<QQmlAssociationList<int, quint32> > dependencies;
+
+ //QQmlJS::Bytecode bytecode;
+ QByteArray bytecode;
+ QByteArray data;
+ QQmlAssociationList<QString, int> subscriptionIds;
+ QVector<quint64> exceptions;
+
+ QQmlAssociationList<QString, QPair<int, int> > registeredStrings;
+
+ int count() const { return offsets.count(); }
+ } committed;
+
+ QByteArray buildSignalTable() const;
+ QByteArray buildExceptionData() const;
+
+ void convertToReal(QQmlJS::IR::Expr *expr, int reg);
+ void convertToInt(QQmlJS::IR::Expr *expr, int reg);
+ void convertToBool(QQmlJS::IR::Expr *expr, int reg);
+ quint8 instructionOpcode(QQmlJS::IR::Binop *e);
+
+ struct Instr {
+#define QML_V4_INSTR_DATA_TYPEDEF(I, FMT) typedef QQmlJS::V4InstrData<QQmlJS::V4Instr::I> I;
+ FOR_EACH_V4_INSTR(QML_V4_INSTR_DATA_TYPEDEF)
+#undef QML_v4_INSTR_DATA_TYPEDEF
+ private:
+ Instr();
+ };
+
+protected:
+ //
+ // tracing
+ //
+ void trace(int line, int column);
+ void trace(QVector<QQmlJS::IR::BasicBlock *> *blocks);
+ void traceExpression(QQmlJS::IR::Expr *e, quint8 r);
+
+ template <int Instr>
+ inline void gen(const QQmlJS::V4InstrData<Instr> &i)
+ { bytecode.append(i); }
+ inline void gen(QQmlJS::V4Instr::Type type, QQmlJS::V4Instr &instr)
+ { bytecode.append(type, instr); }
+
+ inline QQmlJS::V4Instr::Type instructionType(const QQmlJS::V4Instr *i) const
+ { return bytecode.instructionType(i); }
+
+ //
+ // expressions
+ //
+ virtual void visitConst(QQmlJS::IR::Const *e);
+ virtual void visitString(QQmlJS::IR::String *e);
+ virtual void visitName(QQmlJS::IR::Name *e);
+ virtual void visitTemp(QQmlJS::IR::Temp *e);
+ virtual void visitUnop(QQmlJS::IR::Unop *e);
+ virtual void visitBinop(QQmlJS::IR::Binop *e);
+ virtual void visitCall(QQmlJS::IR::Call *e);
+
+ //
+ // statements
+ //
+ virtual void visitExp(QQmlJS::IR::Exp *s);
+ virtual void visitMove(QQmlJS::IR::Move *s);
+ virtual void visitJump(QQmlJS::IR::Jump *s);
+ virtual void visitCJump(QQmlJS::IR::CJump *s);
+ virtual void visitRet(QQmlJS::IR::Ret *s);
+
+private:
+ QStringList _subscribeName;
+ QQmlJS::IR::Function *_function;
+ QQmlJS::IR::BasicBlock *_block;
+ void discard() { _discarded = true; }
+ bool _discarded;
+ quint8 currentReg;
+
+ bool usedSubscriptionIdsChanged;
+ quint32 currentBlockMask;
+};
+
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QV4COMPILER_P_P_H
+
diff --git a/src/qml/qml/v4/qv4instruction.cpp b/src/qml/qml/v4/qv4instruction.cpp
new file mode 100644
index 0000000000..08b2570747
--- /dev/null
+++ b/src/qml/qml/v4/qv4instruction.cpp
@@ -0,0 +1,412 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qv4instruction_p.h"
+#include "qv4bindings_p.h"
+
+#include <QtCore/qdebug.h>
+#include <private/qqmlglobal_p.h>
+
+// Define this to do a test dump of all the instructions at startup. This is
+// helpful to test that each instruction's Instr::dump() case uses the correct
+// number of tabs etc and otherwise looks correct.
+// #define DEBUG_INSTR_DUMP
+
+QT_BEGIN_NAMESPACE
+
+namespace QQmlJS {
+
+#ifdef DEBUG_INSTR_DUMP
+static struct DumpInstrAtStartup {
+ DumpInstrAtStartup() {
+ Bytecode bc;
+#define DUMP_INSTR_AT_STARTUP(I, FMT) { V4InstrData<V4Instr::I> i; bc.append(i); }
+ FOR_EACH_V4_INSTR(DUMP_INSTR_AT_STARTUP);
+#undef DUMP_INSTR_AT_STARTUP
+ const char *start = bc.constData();
+ const char *end = start + bc.size();
+ bc.dump(start, end);
+ }
+} dump_instr_at_startup;
+#endif
+
+int V4Instr::size(Type type)
+{
+#define V4_RETURN_INSTR_SIZE(I, FMT) case I: return QML_V4_INSTR_SIZE(I, FMT);
+ switch (type) {
+ FOR_EACH_V4_INSTR(V4_RETURN_INSTR_SIZE)
+ }
+#undef V4_RETURN_INSTR_SIZE
+ return 0;
+}
+
+void Bytecode::dump(const V4Instr *i, int address) const
+{
+ QByteArray leading;
+ if (address != -1) {
+ leading = QByteArray::number(address);
+ leading.prepend(QByteArray(8 - leading.count(), ' '));
+ leading.append("\t");
+ }
+
+#define INSTR_DUMP qWarning().nospace() << leading.constData()
+
+ switch (instructionType(i)) {
+ case V4Instr::Noop:
+ INSTR_DUMP << "\t" << "Noop";
+ break;
+ case V4Instr::BindingId:
+ INSTR_DUMP << i->id.line << ":" << i->id.column << ":";
+ break;
+ case V4Instr::Subscribe:
+ INSTR_DUMP << "\t" << "Subscribe" << "\t\t" << "Object_Reg(" << i->subscribeop.reg << ") Notify_Signal(" << i->subscribeop.index << ") -> Subscribe_Slot(" << i->subscribeop.offset << ")";
+ break;
+ case V4Instr::SubscribeId:
+ INSTR_DUMP << "\t" << "SubscribeId" << "\t\t" << "Id_Offset(" << i->subscribeop.index << ") -> Subscribe_Slot(" << i->subscribeop.offset << ")";
+ break;
+ case V4Instr::FetchAndSubscribe:
+ INSTR_DUMP << "\t" << "FetchAndSubscribe" << "\t" << "Object_Reg(" << i->fetchAndSubscribe.reg << ") Fast_Accessor(" << i->fetchAndSubscribe.property.accessors << ") -> Output_Reg(" << i->fetchAndSubscribe.reg << ") Subscription_Slot(" << i->fetchAndSubscribe.subscription << ")";
+ break;
+ case V4Instr::LoadId:
+ INSTR_DUMP << "\t" << "LoadId" << "\t\t\t" << "Id_Offset(" << i->load.index << ") -> Output_Reg(" << i->load.reg << ")";
+ break;
+ case V4Instr::LoadScope:
+ INSTR_DUMP << "\t" << "LoadScope" << "\t\t" << "-> Output_Reg(" << i->load.reg << ")";
+ break;
+ case V4Instr::LoadRoot:
+ INSTR_DUMP << "\t" << "LoadRoot" << "\t\t" << "-> Output_Reg(" << i->load.reg << ")";
+ break;
+ case V4Instr::LoadAttached:
+ INSTR_DUMP << "\t" << "LoadAttached" << "\t\t" << "Object_Reg(" << i->attached.reg << ") Attached_Index(" << i->attached.id << ") -> Output_Reg(" << i->attached.output << ")";
+ break;
+ case V4Instr::UnaryNot:
+ INSTR_DUMP << "\t" << "UnaryNot" << "\t\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")";
+ break;
+ case V4Instr::UnaryMinusReal:
+ INSTR_DUMP << "\t" << "UnaryMinusReal" << "\t\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")";
+ break;
+ case V4Instr::UnaryMinusInt:
+ INSTR_DUMP << "\t" << "UnaryMinusInt" << "\t\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")";
+ break;
+ case V4Instr::UnaryPlusReal:
+ INSTR_DUMP << "\t" << "UnaryPlusReal" << "\t\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")";
+ break;
+ case V4Instr::UnaryPlusInt:
+ INSTR_DUMP << "\t" << "UnaryPlusInt" << "\t\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")";
+ break;
+ case V4Instr::ConvertBoolToInt:
+ INSTR_DUMP << "\t" << "ConvertBoolToInt" << "\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")";
+ break;
+ case V4Instr::ConvertBoolToReal:
+ INSTR_DUMP << "\t" << "ConvertBoolToReal" << "\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")";
+ break;
+ case V4Instr::ConvertBoolToString:
+ INSTR_DUMP << "\t" << "ConvertBoolToString" << "\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")";
+ break;
+ case V4Instr::ConvertIntToBool:
+ INSTR_DUMP << "\t" << "ConvertIntToBool" << "\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")";
+ break;
+ case V4Instr::ConvertIntToReal:
+ INSTR_DUMP << "\t" << "ConvertIntToReal" << "\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")";
+ break;
+ case V4Instr::ConvertIntToString:
+ INSTR_DUMP << "\t" << "ConvertIntToString" << "\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")";
+ break;
+ case V4Instr::ConvertRealToBool:
+ INSTR_DUMP << "\t" << "ConvertRealToBool" << "\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")";
+ break;
+ case V4Instr::ConvertRealToInt:
+ INSTR_DUMP << "\t" << "ConvertRealToInt" << "\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")";
+ break;
+ case V4Instr::ConvertRealToString:
+ INSTR_DUMP << "\t" << "ConvertRealToString" << "\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")";
+ break;
+ case V4Instr::ConvertStringToBool:
+ INSTR_DUMP << "\t" << "ConvertStringToBool" << "\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")";
+ break;
+ case V4Instr::ConvertStringToInt:
+ INSTR_DUMP << "\t" << "ConvertStringToInt" << "\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")";
+ break;
+ case V4Instr::ConvertStringToReal:
+ INSTR_DUMP << "\t" << "ConvertStringToReal" << "\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")";
+ break;
+ case V4Instr::ConvertStringToUrl:
+ INSTR_DUMP << "\t" << "ConvertStringToUrl" << "\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")";
+ break;
+ case V4Instr::ConvertUrlToBool:
+ INSTR_DUMP << "\t" << "ConvertUrlToBool" << "\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")";
+ break;
+ case V4Instr::ConvertUrlToString:
+ INSTR_DUMP << "\t" << "ConvertUrlToString" << "\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")";
+ break;
+ case V4Instr::ResolveUrl:
+ INSTR_DUMP << "\t" << "ResolveUrl" << "\t\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")";
+ break;
+ case V4Instr::MathSinReal:
+ INSTR_DUMP << "\t" << "MathSinReal" << "\t\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")";
+ break;
+ case V4Instr::MathCosReal:
+ INSTR_DUMP << "\t" << "MathCosReal" << "\t\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")";
+ break;
+ case V4Instr::MathRoundReal:
+ INSTR_DUMP << "\t" << "MathRoundReal" << "\t\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")";
+ break;
+ case V4Instr::MathFloorReal:
+ INSTR_DUMP << "\t" << "MathFloorReal" << "\t\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")";
+ break;
+ case V4Instr::MathPIReal:
+ INSTR_DUMP << "\t" << "MathPIReal" << "\t\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")";
+ break;
+ case V4Instr::LoadReal:
+ INSTR_DUMP << "\t" << "LoadReal" << "\t\t" << "Constant(" << i->real_value.value << ") -> Output_Reg(" << i->real_value.reg << ")";
+ break;
+ case V4Instr::LoadInt:
+ INSTR_DUMP << "\t" << "LoadInt" << "\t\t\t" << "Constant(" << i->int_value.value << ") -> Output_Reg(" << i->int_value.reg << ")";
+ break;
+ case V4Instr::LoadBool:
+ INSTR_DUMP << "\t" << "LoadBool" << "\t\t" << "Constant(" << i->bool_value.value << ") -> Output_Reg(" << i->bool_value.reg << ")";
+ break;
+ case V4Instr::LoadString:
+ INSTR_DUMP << "\t" << "LoadString" << "\t\t" << "String_DataIndex(" << i->string_value.offset << ") String_Length(" << i->string_value.length << ") -> Output_Register(" << i->string_value.reg << ")";
+ break;
+ case V4Instr::EnableV4Test:
+ INSTR_DUMP << "\t" << "EnableV4Test" << "\t\t" << "String_DataIndex(" << i->string_value.offset << ") String_Length(" << i->string_value.length << ")";
+ break;
+ case V4Instr::TestV4Store:
+ INSTR_DUMP << "\t" << "TestV4Store" << "\t\t" << "Input_Reg(" << i->storetest.reg << ") Reg_Type(" << i->storetest.regType << ")";
+ break;
+ case V4Instr::BitAndInt:
+ INSTR_DUMP << "\t" << "BitAndInt" << "\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")";
+ break;
+ case V4Instr::BitOrInt:
+ INSTR_DUMP << "\t" << "BitOrInt" << "\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")";
+ break;
+ case V4Instr::BitXorInt:
+ INSTR_DUMP << "\t" << "BitXorInt" << "\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")";
+ break;
+ case V4Instr::AddReal:
+ INSTR_DUMP << "\t" << "AddReal" << "\t\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")";
+ break;
+ case V4Instr::AddString:
+ INSTR_DUMP << "\t" << "AddString" << "\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")";
+ break;
+ case V4Instr::SubReal:
+ INSTR_DUMP << "\t" << "SubReal" << "\t\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")";
+ break;
+ case V4Instr::MulReal:
+ INSTR_DUMP << "\t" << "MulReal" << "\t\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")";
+ break;
+ case V4Instr::DivReal:
+ INSTR_DUMP << "\t" << "DivReal" << "\t\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")";
+ break;
+ case V4Instr::ModReal:
+ INSTR_DUMP << "\t" << "ModReal" << "\t\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")";
+ break;
+ case V4Instr::LShiftInt:
+ INSTR_DUMP << "\t" << "LShiftInt" << "\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")";
+ break;
+ case V4Instr::RShiftInt:
+ INSTR_DUMP << "\t" << "RShiftInt" << "\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")";
+ break;
+ case V4Instr::URShiftInt:
+ INSTR_DUMP << "\t" << "URShiftInt" << "\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")";
+ break;
+ case V4Instr::GtReal:
+ INSTR_DUMP << "\t" << "GtReal" << "\t\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")";
+ break;
+ case V4Instr::LtReal:
+ INSTR_DUMP << "\t" << "LtReal" << "\t\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")";
+ break;
+ case V4Instr::GeReal:
+ INSTR_DUMP << "\t" << "GeReal" << "\t\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")";
+ break;
+ case V4Instr::LeReal:
+ INSTR_DUMP << "\t" << "LeReal" << "\t\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")";
+ break;
+ case V4Instr::EqualReal:
+ INSTR_DUMP << "\t" << "EqualReal" << "\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")";
+ break;
+ case V4Instr::NotEqualReal:
+ INSTR_DUMP << "\t" << "NotEqualReal" << "\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")";
+ break;
+ case V4Instr::StrictEqualReal:
+ INSTR_DUMP << "\t" << "StrictEqualReal" << "\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")";
+ break;
+ case V4Instr::StrictNotEqualReal:
+ INSTR_DUMP << "\t" << "StrictNotEqualReal" << "\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")";
+ break;
+ case V4Instr::GtString:
+ INSTR_DUMP << "\t" << "GtString" << "\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")";
+ break;
+ case V4Instr::LtString:
+ INSTR_DUMP << "\t" << "LtString" << "\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")";
+ break;
+ case V4Instr::GeString:
+ INSTR_DUMP << "\t" << "GeString" << "\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")";
+ break;
+ case V4Instr::LeString:
+ INSTR_DUMP << "\t" << "LeString" << "\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")";
+ break;
+ case V4Instr::EqualString:
+ INSTR_DUMP << "\t" << "EqualString" << "\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")";
+ break;
+ case V4Instr::NotEqualString:
+ INSTR_DUMP << "\t" << "NotEqualString" << "\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")";
+ break;
+ case V4Instr::StrictEqualString:
+ INSTR_DUMP << "\t" << "StrictEqualString" << "\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")";
+ break;
+ case V4Instr::StrictNotEqualString:
+ INSTR_DUMP << "\t" << "StrictNotEqualString" << "\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")";
+ break;
+ case V4Instr::NewString:
+ INSTR_DUMP << "\t" << "NewString" << "\t\t" << "Register(" << i->construct.reg << ")";
+ break;
+ case V4Instr::NewUrl:
+ INSTR_DUMP << "\t" << "NewUrl" << "\t\t\t" << "Register(" << i->construct.reg << ")";
+ break;
+ case V4Instr::CleanupRegister:
+ INSTR_DUMP << "\t" << "CleanupRegister" << "\t\t" << "Register(" << i->cleanup.reg << ")";
+ break;
+ case V4Instr::Fetch:
+ INSTR_DUMP << "\t" << "Fetch" << "\t\t\t" << "Object_Reg(" << i->fetch.reg << ") Property_Index(" << i->fetch.index << ") -> Output_Reg(" << i->fetch.reg << ")";
+ break;
+ case V4Instr::Store:
+ INSTR_DUMP << "\t" << "Store" << "\t\t\t" << "Input_Reg(" << i->store.reg << ") -> Object_Reg(" << i->store.output << ") Property_Index(" << i->store.index << ")";
+ break;
+ case V4Instr::Copy:
+ INSTR_DUMP << "\t" << "Copy" << "\t\t\t" << "Input_Reg(" << i->copy.src << ") -> Output_Reg(" << i->copy.reg << ")";
+ break;
+ case V4Instr::Jump:
+ if (i->jump.reg != -1) {
+ INSTR_DUMP << "\t" << "Jump" << "\t\t\t" << "Address(" << (address + size() + i->jump.count) << ") [if false == Input_Reg(" << i->jump.reg << ")]";
+ } else {
+ INSTR_DUMP << "\t" << "Jump" << "\t\t\t" << "Address(" << (address + size() + i->jump.count) << ")";
+ }
+ break;
+ case V4Instr::BranchFalse:
+ INSTR_DUMP << "\t" << "BranchFalse" << "\t\t" << "Address(" << (address + size() + i->branchop.offset) << ") [if false == Input_Reg(" << i->branchop.reg << ")]";
+ break;
+ case V4Instr::BranchTrue:
+ INSTR_DUMP << "\t" << "BranchTrue" << "\t\t" << "Address(" << (address + size() + i->branchop.offset) << ") [if true == Input_Reg(" << i->branchop.reg << ")]";
+ break;
+ case V4Instr::Branch:
+ INSTR_DUMP << "\t" << "Branch" << "\t\t\t" << "Address(" << (address + size() + i->branchop.offset) << ")";
+ break;
+ case V4Instr::InitString:
+ INSTR_DUMP << "\t" << "InitString" << "\t\t" << "String_DataIndex(" << i->initstring.dataIdx << ") -> String_Slot(" << i->initstring.offset << ")";
+ break;
+ case V4Instr::Block:
+ INSTR_DUMP << "\t" << "Block" << "\t\t\t" << "Mask(" << QByteArray::number(i->blockop.block, 16).constData() << ")";
+ break;
+ default:
+ INSTR_DUMP << "\t" << "Unknown";
+ break;
+ }
+}
+
+void Bytecode::dump(const char *start, const char *end) const
+{
+ const char *code = start;
+ while (code < end) {
+ const V4Instr *instr = reinterpret_cast<const V4Instr *>(code);
+ dump(instr, code - start);
+ code += V4Instr::size(instructionType(instr));
+ }
+}
+
+Bytecode::Bytecode()
+{
+#ifdef QML_THREADED_INTERPRETER
+ decodeInstr = QV4Bindings::getDecodeInstrTable();
+#endif
+}
+
+V4Instr::Type Bytecode::instructionType(const V4Instr *instr) const
+{
+#ifdef QML_THREADED_INTERPRETER
+ void *code = instr->common.code;
+
+# define CHECK_V4_INSTR_CODE(I, FMT) \
+ if (decodeInstr[static_cast<int>(V4Instr::I)] == code) \
+ return V4Instr::I;
+
+ FOR_EACH_V4_INSTR(CHECK_V4_INSTR_CODE)
+ Q_ASSERT_X(false, Q_FUNC_INFO, "Invalid instruction address");
+ return static_cast<V4Instr::Type>(0);
+# undef CHECK_V4_INSTR_CODE
+#else
+ return static_cast<V4Instr::Type>(instr->common.type);
+#endif
+
+}
+
+void Bytecode::append(V4Instr::Type type, V4Instr &instr)
+{
+#ifdef QML_THREADED_INTERPRETER
+ instr.common.code = decodeInstr[static_cast<int>(type)];
+#else
+ instr.common.type = type;
+#endif
+ d.append(reinterpret_cast<const char *>(&instr), V4Instr::size(type));
+}
+
+int Bytecode::remove(int offset)
+{
+ const V4Instr *instr = reinterpret_cast<const V4Instr *>(d.begin() + offset);
+ const int instrSize = V4Instr::size(instructionType(instr));
+ d.remove(offset, instrSize);
+ return instrSize;
+}
+
+const V4Instr &Bytecode::operator[](int offset) const
+{
+ return *(reinterpret_cast<const V4Instr *>(d.begin() + offset));
+}
+
+V4Instr &Bytecode::operator[](int offset)
+{
+ return *(reinterpret_cast<V4Instr *>(d.begin() + offset));
+}
+
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/v4/qv4instruction_p.h b/src/qml/qml/v4/qv4instruction_p.h
new file mode 100644
index 0000000000..8150eedf54
--- /dev/null
+++ b/src/qml/qml/v4/qv4instruction_p.h
@@ -0,0 +1,432 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QV4INSTRUCTION_P_H
+#define QV4INSTRUCTION_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qglobal.h>
+#include <QtCore/qbytearray.h>
+#include <QtCore/qvector.h>
+#include <QtCore/qvarlengtharray.h>
+
+#include <private/qqmlpropertycache_p.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+#define FOR_EACH_V4_INSTR(F) \
+ F(Noop, common) \
+ F(BindingId, id) \
+ F(Subscribe, subscribeop) \
+ F(SubscribeId, subscribeop) \
+ F(FetchAndSubscribe, fetchAndSubscribe) \
+ F(LoadId, load) \
+ F(LoadScope, load) \
+ F(LoadRoot, load) \
+ F(LoadAttached, attached) \
+ F(UnaryNot, unaryop) \
+ F(UnaryMinusReal, unaryop) \
+ F(UnaryMinusInt, unaryop) \
+ F(UnaryPlusReal, unaryop) \
+ F(UnaryPlusInt, unaryop) \
+ F(ConvertBoolToInt, unaryop) \
+ F(ConvertBoolToReal, unaryop) \
+ F(ConvertBoolToString, unaryop) \
+ F(ConvertIntToBool, unaryop) \
+ F(ConvertIntToReal, unaryop) \
+ F(ConvertIntToString, unaryop) \
+ F(ConvertRealToBool, unaryop) \
+ F(ConvertRealToInt, unaryop) \
+ F(ConvertRealToString, unaryop) \
+ F(ConvertStringToBool, unaryop) \
+ F(ConvertStringToInt, unaryop) \
+ F(ConvertStringToReal, unaryop) \
+ F(ConvertStringToUrl, unaryop) \
+ F(ConvertUrlToBool, unaryop) \
+ F(ConvertUrlToString, unaryop) \
+ F(ResolveUrl, unaryop) \
+ F(MathSinReal, unaryop) \
+ F(MathCosReal, unaryop) \
+ F(MathRoundReal, unaryop) \
+ F(MathFloorReal, unaryop) \
+ F(MathPIReal, unaryop) \
+ F(LoadReal, real_value) \
+ F(LoadInt, int_value) \
+ F(LoadBool, bool_value) \
+ F(LoadString, string_value) \
+ F(EnableV4Test, string_value) \
+ F(TestV4Store, storetest) \
+ F(BitAndInt, binaryop) \
+ F(BitOrInt, binaryop) \
+ F(BitXorInt, binaryop) \
+ F(AddReal, binaryop) \
+ F(AddString, binaryop) \
+ F(SubReal, binaryop) \
+ F(MulReal, binaryop) \
+ F(DivReal, binaryop) \
+ F(ModReal, binaryop) \
+ F(LShiftInt, binaryop) \
+ F(RShiftInt, binaryop) \
+ F(URShiftInt, binaryop) \
+ F(GtReal, binaryop) \
+ F(LtReal, binaryop) \
+ F(GeReal, binaryop) \
+ F(LeReal, binaryop) \
+ F(EqualReal, binaryop) \
+ F(NotEqualReal, binaryop) \
+ F(StrictEqualReal, binaryop) \
+ F(StrictNotEqualReal, binaryop) \
+ F(GtString, binaryop) \
+ F(LtString, binaryop) \
+ F(GeString, binaryop) \
+ F(LeString, binaryop) \
+ F(EqualString, binaryop) \
+ F(NotEqualString, binaryop) \
+ F(StrictEqualString, binaryop) \
+ F(StrictNotEqualString, binaryop) \
+ F(NewString, construct) \
+ F(NewUrl, construct) \
+ F(CleanupRegister, cleanup) \
+ F(Copy, copy) \
+ F(Fetch, fetch) \
+ F(Store, store) \
+ F(Jump, jump) \
+ F(BranchTrue, branchop) \
+ F(BranchFalse, branchop) \
+ F(Branch, branchop) \
+ F(Block, blockop) \
+ /* Speculative property resolution */ \
+ F(InitString, initstring)
+
+#if defined(Q_CC_GNU) && (!defined(Q_CC_INTEL) || __INTEL_COMPILER >= 1200)
+# define QML_THREADED_INTERPRETER
+#endif
+
+#ifdef Q_ALIGNOF
+# define QML_V4_INSTR_ALIGN_MASK (Q_ALIGNOF(V4Instr) - 1)
+#else
+# define QML_V4_INSTR_ALIGN_MASK (sizeof(void *) - 1)
+#endif
+
+#define QML_V4_INSTR_ENUM(I, FMT) I,
+#define QML_V4_INSTR_ADDR(I, FMT) &&op_##I,
+#define QML_V4_INSTR_SIZE(I, FMT) ((sizeof(V4Instr::instr_##FMT) + QML_V4_INSTR_ALIGN_MASK) & ~QML_V4_INSTR_ALIGN_MASK)
+
+#ifdef QML_THREADED_INTERPRETER
+# define QML_V4_BEGIN_INSTR(I,FMT) op_##I:
+# define QML_V4_END_INSTR(I,FMT) code += QML_V4_INSTR_SIZE(I, FMT); instr = (const V4Instr *) code; goto *instr->common.code;
+# define QML_V4_INSTR_HEADER void *code;
+#else
+# define QML_V4_BEGIN_INSTR(I,FMT) case V4Instr::I:
+# define QML_V4_END_INSTR(I,FMT) code += QML_V4_INSTR_SIZE(I, FMT); instr = (const V4Instr *) code; break;
+# define QML_V4_INSTR_HEADER quint8 type;
+#endif
+
+class QObject;
+class QQmlNotifier;
+
+namespace QQmlJS {
+
+union V4Instr {
+ enum Type {
+ FOR_EACH_V4_INSTR(QML_V4_INSTR_ENUM)
+ };
+
+ static int size(Type type);
+
+ struct instr_common {
+ QML_V4_INSTR_HEADER
+ };
+
+ struct instr_id {
+ QML_V4_INSTR_HEADER
+ quint16 column;
+ quint32 line;
+ };
+
+ struct instr_init {
+ QML_V4_INSTR_HEADER
+ quint16 subscriptions;
+ quint16 identifiers;
+ };
+
+ struct instr_subscribeop {
+ QML_V4_INSTR_HEADER
+ qint8 reg;
+ quint16 offset;
+ quint32 index;
+ };
+
+ struct instr_load {
+ QML_V4_INSTR_HEADER
+ qint8 reg;
+ quint32 index;
+ };
+
+ struct instr_attached {
+ QML_V4_INSTR_HEADER
+ qint8 output;
+ qint8 reg;
+ quint8 exceptionId;
+ quint32 id;
+ };
+
+ struct instr_store {
+ QML_V4_INSTR_HEADER
+ qint8 output;
+ qint8 reg;
+ quint8 exceptionId;
+ quint32 index;
+ };
+
+ struct instr_storetest {
+ QML_V4_INSTR_HEADER
+ qint8 reg;
+ qint32 regType;
+ };
+
+ struct instr_fetchAndSubscribe {
+ QML_V4_INSTR_HEADER
+ qint8 reg;
+ quint8 exceptionId;
+ quint8 valueType;
+ quint16 subscription;
+ QQmlPropertyRawData property;
+ };
+
+ struct instr_fetch{
+ QML_V4_INSTR_HEADER
+ qint8 reg;
+ quint8 exceptionId;
+ quint8 valueType;
+ quint32 index;
+ };
+
+ struct instr_copy {
+ QML_V4_INSTR_HEADER
+ qint8 reg;
+ qint8 src;
+ };
+
+ struct instr_construct {
+ QML_V4_INSTR_HEADER
+ qint8 reg;
+ };
+
+ struct instr_real_value {
+ QML_V4_INSTR_HEADER
+ qint8 reg;
+ qreal value; // XXX Makes the instruction 12 bytes
+ };
+
+ struct instr_int_value {
+ QML_V4_INSTR_HEADER
+ qint8 reg;
+ int value;
+ };
+
+ struct instr_bool_value {
+ QML_V4_INSTR_HEADER
+ qint8 reg;
+ bool value;
+ };
+
+ struct instr_string_value {
+ QML_V4_INSTR_HEADER
+ qint8 reg;
+ quint16 length;
+ quint32 offset;
+ };
+
+ struct instr_binaryop {
+ QML_V4_INSTR_HEADER
+ qint8 output;
+ qint8 left;
+ qint8 right;
+ };
+
+ struct instr_unaryop {
+ QML_V4_INSTR_HEADER
+ qint8 output;
+ qint8 src;
+ };
+
+ struct instr_jump {
+ QML_V4_INSTR_HEADER
+ qint8 reg;
+ quint32 count;
+ };
+
+ struct instr_find {
+ QML_V4_INSTR_HEADER
+ qint8 reg;
+ qint8 src;
+ quint8 exceptionId;
+ quint16 name;
+ quint16 subscribeIndex;
+ };
+
+ struct instr_cleanup {
+ QML_V4_INSTR_HEADER
+ qint8 reg;
+ };
+
+ struct instr_initstring {
+ QML_V4_INSTR_HEADER
+ quint16 offset;
+ quint32 dataIdx;
+ };
+
+ struct instr_branchop {
+ QML_V4_INSTR_HEADER
+ quint8 reg;
+ qint16 offset;
+ };
+
+ struct instr_blockop {
+ QML_V4_INSTR_HEADER
+ quint32 block;
+ };
+
+ instr_common common;
+ instr_id id;
+ instr_init init;
+ instr_subscribeop subscribeop;
+ instr_load load;
+ instr_attached attached;
+ instr_store store;
+ instr_storetest storetest;
+ instr_fetchAndSubscribe fetchAndSubscribe;
+ instr_fetch fetch;
+ instr_copy copy;
+ instr_construct construct;
+ instr_real_value real_value;
+ instr_int_value int_value;
+ instr_bool_value bool_value;
+ instr_string_value string_value;
+ instr_binaryop binaryop;
+ instr_unaryop unaryop;
+ instr_jump jump;
+ instr_find find;
+ instr_cleanup cleanup;
+ instr_initstring initstring;
+ instr_branchop branchop;
+ instr_blockop blockop;
+};
+
+template<int N>
+struct V4InstrMeta {
+};
+
+#define QML_V4_INSTR_META_TEMPLATE(I, FMT) \
+ template<> struct V4InstrMeta<(int)V4Instr::I> { \
+ enum { Size = QML_V4_INSTR_SIZE(I, FMT) }; \
+ typedef V4Instr::instr_##FMT DataType; \
+ static const DataType &data(const V4Instr &instr) { return instr.FMT; } \
+ static void setData(V4Instr &instr, const DataType &v) { instr.FMT = v; } \
+ };
+FOR_EACH_V4_INSTR(QML_V4_INSTR_META_TEMPLATE);
+#undef QML_V4_INSTR_META_TEMPLATE
+
+template<int Instr>
+class V4InstrData : public V4InstrMeta<Instr>::DataType
+{
+};
+
+class Bytecode
+{
+ Q_DISABLE_COPY(Bytecode)
+
+public:
+ Bytecode();
+
+ const char *constData() const { return d.constData(); }
+ int size() const { return d.size(); }
+ int count() const { return d.count(); }
+ void clear() { d.clear(); }
+ bool isEmpty() const { return d.isEmpty(); }
+ V4Instr::Type instructionType(const V4Instr *instr) const;
+
+ template <int Instr>
+ void append(const V4InstrData<Instr> &data)
+ {
+ V4Instr genericInstr;
+ V4InstrMeta<Instr>::setData(genericInstr, data);
+ return append(static_cast<V4Instr::Type>(Instr), genericInstr);
+ }
+ void append(V4Instr::Type type, V4Instr &instr);
+
+ int remove(int index);
+
+ const V4Instr &operator[](int offset) const;
+ V4Instr &operator[](int offset);
+
+ void dump(const char *start, const char *end) const;
+
+private:
+ void dump(const V4Instr *instr, int = -1) const;
+
+ QVarLengthArray<char, 4 * 1024> d;
+#ifdef QML_THREADED_INTERPRETER
+ void **decodeInstr;
+#endif
+};
+
+}
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QV4INSTRUCTION_P_H
+
diff --git a/src/qml/qml/v4/qv4ir.cpp b/src/qml/qml/v4/qv4ir.cpp
new file mode 100644
index 0000000000..be822145a4
--- /dev/null
+++ b/src/qml/qml/v4/qv4ir.cpp
@@ -0,0 +1,882 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qv4ir_p.h"
+
+#include <QtCore/qtextstream.h>
+#include <QtCore/qdebug.h>
+#include <math.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace QQmlJS {
+namespace IR {
+
+inline const char *typeName(Type t)
+{
+ switch (t) {
+ case InvalidType: return "invalid";
+ case UndefinedType: return "undefined";
+ case NullType: return "null";
+ case VoidType: return "void";
+ case StringType: return "string";
+ case UrlType: return "url";
+ case SGAnchorLineType: return "SGAnchorLine";
+ case AttachType: return "AttachType";
+ case ObjectType: return "object";
+ case BoolType: return "bool";
+ case IntType: return "int";
+ case RealType: return "qreal";
+ case RealNaNType: return "NaN";
+ default: return "invalid";
+ }
+}
+
+inline bool isNumberType(IR::Type ty)
+{
+ return ty >= IR::FirstNumberType;
+}
+
+inline bool isStringType(IR::Type ty)
+{
+ return ty == IR::StringType || ty == IR::UrlType;
+}
+
+IR::Type maxType(IR::Type left, IR::Type right)
+{
+ if (isStringType(left) && isStringType(right)) {
+ // String promotions (url to string) are more specific than
+ // identity conversions (AKA left == right). That's because
+ // we want to ensure we convert urls to strings in binary
+ // expressions.
+ return IR::StringType;
+ } else if (left == right)
+ return left;
+ else if (isNumberType(left) && isNumberType(right))
+ return qMax(left, right);
+ else if ((isNumberType(left) && isStringType(right)) ||
+ (isNumberType(right) && isStringType(left)))
+ return IR::StringType;
+ else
+ return IR::InvalidType;
+}
+
+
+const char *opname(AluOp op)
+{
+ switch (op) {
+ case OpInvalid: return "?";
+
+ case OpIfTrue: return "(bool)";
+ case OpNot: return "!";
+ case OpUMinus: return "-";
+ case OpUPlus: return "+";
+ case OpCompl: return "~";
+
+ case OpBitAnd: return "&";
+ case OpBitOr: return "|";
+ case OpBitXor: return "^";
+
+ case OpAdd: return "+";
+ case OpSub: return "-";
+ case OpMul: return "*";
+ case OpDiv: return "/";
+ case OpMod: return "%";
+
+ case OpLShift: return "<<";
+ case OpRShift: return ">>";
+ case OpURShift: return ">>>";
+
+ case OpGt: return ">";
+ case OpLt: return "<";
+ case OpGe: return ">=";
+ case OpLe: return "<=";
+ case OpEqual: return "==";
+ case OpNotEqual: return "!=";
+ case OpStrictEqual: return "===";
+ case OpStrictNotEqual: return "!==";
+
+ case OpAnd: return "&&";
+ case OpOr: return "||";
+
+ default: return "?";
+
+ } // switch
+}
+
+AluOp binaryOperator(int op)
+{
+ switch (static_cast<QSOperator::Op>(op)) {
+ case QSOperator::Add: return OpAdd;
+ case QSOperator::And: return OpAnd;
+ case QSOperator::BitAnd: return OpBitAnd;
+ case QSOperator::BitOr: return OpBitOr;
+ case QSOperator::BitXor: return OpBitXor;
+ case QSOperator::Div: return OpDiv;
+ case QSOperator::Equal: return OpEqual;
+ case QSOperator::Ge: return OpGe;
+ case QSOperator::Gt: return OpGt;
+ case QSOperator::Le: return OpLe;
+ case QSOperator::LShift: return OpLShift;
+ case QSOperator::Lt: return OpLt;
+ case QSOperator::Mod: return OpMod;
+ case QSOperator::Mul: return OpMul;
+ case QSOperator::NotEqual: return OpNotEqual;
+ case QSOperator::Or: return OpOr;
+ case QSOperator::RShift: return OpRShift;
+ case QSOperator::StrictEqual: return OpStrictEqual;
+ case QSOperator::StrictNotEqual: return OpStrictNotEqual;
+ case QSOperator::Sub: return OpSub;
+ case QSOperator::URShift: return OpURShift;
+ default: return OpInvalid;
+ }
+}
+
+void Const::dump(QTextStream &out)
+{
+ out << value;
+}
+
+void String::dump(QTextStream &out)
+{
+ out << '"' << escape(value) << '"';
+}
+
+QString String::escape(const QStringRef &s)
+{
+ QString r;
+ for (int i = 0; i < s.length(); ++i) {
+ const QChar ch = s.at(i);
+ if (ch == QLatin1Char('\n'))
+ r += QLatin1String("\\n");
+ else if (ch == QLatin1Char('\r'))
+ r += QLatin1String("\\r");
+ else if (ch == QLatin1Char('\\'))
+ r += QLatin1String("\\\\");
+ else if (ch == QLatin1Char('"'))
+ r += QLatin1String("\\\"");
+ else if (ch == QLatin1Char('\''))
+ r += QLatin1String("\\'");
+ else
+ r += ch;
+ }
+ return r;
+}
+
+void Name::init(Name *base, Type type, const QString *id, Symbol symbol, quint32 line, quint32 column)
+{
+ this->type = type;
+ this->base = base;
+ this->id = id;
+ this->symbol = symbol;
+ this->ptr = 0;
+ this->property = 0;
+ this->storage = MemberStorage;
+ this->builtin = NoBuiltinSymbol;
+ this->line = line;
+ this->column = column;
+
+ if (id->length() == 8 && *id == QLatin1String("Math.sin")) {
+ builtin = MathSinBultinFunction;
+ } else if (id->length() == 8 && *id == QLatin1String("Math.cos")) {
+ builtin = MathCosBultinFunction;
+ } else if (id->length() == 10 && *id == QLatin1String("Math.round")) {
+ builtin = MathRoundBultinFunction;
+ } else if (id->length() == 10 && *id == QLatin1String("Math.floor)")) {
+ builtin = MathFloorBultinFunction;
+ } else if (id->length() == 7 && *id == QLatin1String("Math.PI")) {
+ builtin = MathPIBuiltinConstant;
+ this->type = RealType;
+ }
+}
+
+void Name::dump(QTextStream &out)
+{
+ if (base) {
+ base->dump(out);
+ out << '.';
+ }
+
+ out << *id;
+}
+
+void Temp::dump(QTextStream &out)
+{
+ out << 't' << index;
+}
+
+void Unop::dump(QTextStream &out)
+{
+ out << opname(op);
+ expr->dump(out);
+}
+
+Type Unop::typeForOp(AluOp op, Expr *expr)
+{
+ switch (op) {
+ case OpIfTrue: return BoolType;
+ case OpNot: return BoolType;
+
+ case OpUMinus:
+ case OpUPlus:
+ case OpCompl:
+ return maxType(expr->type, RealType);
+
+ default:
+ break;
+ }
+
+ return InvalidType;
+}
+
+void Binop::dump(QTextStream &out)
+{
+ left->dump(out);
+ out << ' ' << opname(op) << ' ';
+ right->dump(out);
+}
+
+Type Binop::typeForOp(AluOp op, Expr *left, Expr *right)
+{
+ if (! (left && right))
+ return InvalidType;
+
+ switch (op) {
+ case OpInvalid:
+ return InvalidType;
+
+ // unary operators
+ case OpIfTrue:
+ case OpNot:
+ case OpUMinus:
+ case OpUPlus:
+ case OpCompl:
+ return InvalidType;
+
+ // bit fields
+ case OpBitAnd:
+ case OpBitOr:
+ case OpBitXor:
+ return IntType;
+
+ case OpAdd:
+ if (left->type == StringType)
+ return StringType;
+ return RealType;
+
+ case OpSub:
+ case OpMul:
+ case OpDiv:
+ case OpMod:
+ return RealType;
+
+ case OpLShift:
+ case OpRShift:
+ case OpURShift:
+ return IntType;
+
+ case OpAnd:
+ case OpOr:
+ return BoolType;
+
+ case OpGt:
+ case OpLt:
+ case OpGe:
+ case OpLe:
+ case OpEqual:
+ case OpNotEqual:
+ case OpStrictEqual:
+ case OpStrictNotEqual:
+ return BoolType;
+ } // switch
+
+ return InvalidType;
+}
+
+void Call::dump(QTextStream &out)
+{
+ base->dump(out);
+ out << '(';
+ for (ExprList *it = args; it; it = it->next) {
+ if (it != args)
+ out << ", ";
+ it->expr->dump(out);
+ }
+ out << ')';
+}
+
+Type Call::typeForFunction(Expr *base)
+{
+ if (! base)
+ return InvalidType;
+
+ if (Name *name = base->asName()) {
+ switch (name->builtin) {
+ case MathSinBultinFunction:
+ case MathCosBultinFunction:
+ return RealType;
+
+ case MathRoundBultinFunction:
+ case MathFloorBultinFunction:
+ return IntType;
+
+ case NoBuiltinSymbol:
+ case MathPIBuiltinConstant:
+ break;
+ }
+ } // switch
+
+ return InvalidType;
+}
+
+void Exp::dump(QTextStream &out, Mode)
+{
+ out << "(void) ";
+ expr->dump(out);
+ out << ';';
+}
+
+void Move::dump(QTextStream &out, Mode)
+{
+ target->dump(out);
+ out << " = ";
+ if (source->type != target->type)
+ out << typeName(source->type) << "_to_" << typeName(target->type) << '(';
+ source->dump(out);
+ if (source->type != target->type)
+ out << ')';
+ out << ';';
+}
+
+void Jump::dump(QTextStream &out, Mode mode)
+{
+ Q_UNUSED(mode);
+ out << "goto " << 'L' << target << ';';
+}
+
+void CJump::dump(QTextStream &out, Mode mode)
+{
+ Q_UNUSED(mode);
+ out << "if (";
+ cond->dump(out);
+ out << ") goto " << 'L' << iftrue << "; else goto " << 'L' << iffalse << ';';
+}
+
+void Ret::dump(QTextStream &out, Mode)
+{
+ out << "return";
+ if (expr) {
+ out << ' ';
+ expr->dump(out);
+ }
+ out << ';';
+}
+
+Function::~Function()
+{
+ qDeleteAll(basicBlocks);
+}
+
+QString *Function::newString(const QString &text)
+{
+ return pool->NewString(text);
+}
+
+BasicBlock *Function::newBasicBlock()
+{
+ const int index = basicBlocks.size();
+ return i(new BasicBlock(this, index));
+}
+
+void Function::dump(QTextStream &out)
+{
+ out << "function () {" << endl;
+ foreach (BasicBlock *bb, basicBlocks) {
+ bb->dump(out);
+ }
+ out << '}' << endl;
+}
+
+Temp *BasicBlock::TEMP(Type type, int index)
+{
+ Temp *e = function->pool->New<Temp>();
+ e->init(type, index);
+ return e;
+}
+
+Temp *BasicBlock::TEMP(Type type)
+{
+ return TEMP(type, function->tempCount++);
+}
+
+Expr *BasicBlock::CONST(double value)
+{
+ return CONST(IR::RealType, value);
+}
+
+Expr *BasicBlock::CONST(Type type, double value)
+{
+ Const *e = function->pool->New<Const>();
+ e->init(type, value);
+ return e;
+}
+
+Expr *BasicBlock::STRING(const QStringRef &value)
+{
+ String *e = function->pool->New<String>();
+ e->init(value);
+ return e;
+}
+
+Name *BasicBlock::NAME(const QString &id, quint32 line, quint32 column)
+{
+ return NAME(0, id, line, column);
+}
+
+Name *BasicBlock::NAME(Name *base, const QString &id, quint32 line, quint32 column)
+{
+ Name *e = function->pool->New<Name>();
+ e->init(base, InvalidType,
+ function->newString(id),
+ Name::Unbound, line, column);
+ return e;
+}
+
+Name *BasicBlock::SYMBOL(Type type, const QString &id, const QMetaObject *meta, QQmlPropertyData *property, Name::Storage storage,
+ quint32 line, quint32 column)
+{
+ Name *name = SYMBOL(/*base = */ 0, type, id, meta, property, line, column);
+ name->storage = storage;
+ return name;
+}
+
+Name *BasicBlock::SYMBOL(Name *base, Type type, const QString &id, const QMetaObject *meta, QQmlPropertyData *property, Name::Storage storage,
+ quint32 line, quint32 column)
+{
+ Name *name = function->pool->New<Name>();
+ name->init(base, type, function->newString(id),
+ Name::Property, line, column);
+ name->meta = meta;
+ name->property = property;
+ name->storage = storage;
+ return name;
+}
+
+Name *BasicBlock::SYMBOL(Name *base, Type type, const QString &id, const QMetaObject *meta, QQmlPropertyData *property,
+ quint32 line, quint32 column)
+{
+ Name *name = function->pool->New<Name>();
+ name->init(base, type, function->newString(id),
+ Name::Property, line, column);
+ name->meta = meta;
+ name->property = property;
+ return name;
+}
+
+Name *BasicBlock::ID_OBJECT(const QString &id, const QQmlScript::Object *object, quint32 line, quint32 column)
+{
+ Name *name = function->pool->New<Name>();
+ name->init(/*base = */ 0, IR::ObjectType,
+ function->newString(id),
+ Name::IdObject, line, column);
+ name->idObject = object;
+ name->property = 0;
+ name->storage = Name::IdStorage;
+ return name;
+}
+
+Name *BasicBlock::ATTACH_TYPE(const QString &id, const QQmlType *attachType, Name::Storage storage,
+ quint32 line, quint32 column)
+{
+ Name *name = function->pool->New<Name>();
+ name->init(/*base = */ 0, IR::AttachType,
+ function->newString(id),
+ Name::AttachType, line, column);
+ name->declarativeType = attachType;
+ name->storage = storage;
+ return name;
+}
+
+
+Expr *BasicBlock::UNOP(AluOp op, Expr *expr)
+{
+ Unop *e = function->pool->New<Unop>();
+ e->init(op, expr);
+ return e;
+}
+
+Expr *BasicBlock::BINOP(AluOp op, Expr *left, Expr *right)
+{
+ if (left && right) {
+ if (Const *c1 = left->asConst()) {
+ if (Const *c2 = right->asConst()) {
+ switch (op) {
+ case OpAdd: return CONST(c1->value + c2->value);
+ case OpAnd: return CONST(c1->value ? c2->value : 0);
+ case OpBitAnd: return CONST(int(c1->value) & int(c2->value));
+ case OpBitOr: return CONST(int(c1->value) | int(c2->value));
+ case OpBitXor: return CONST(int(c1->value) ^ int(c2->value));
+ case OpDiv: return CONST(c1->value / c2->value);
+ case OpEqual: return CONST(c1->value == c2->value);
+ case OpGe: return CONST(c1->value >= c2->value);
+ case OpGt: return CONST(c1->value > c2->value);
+ case OpLe: return CONST(c1->value <= c2->value);
+ case OpLShift: return CONST(int(c1->value) << int(c2->value));
+ case OpLt: return CONST(c1->value < c2->value);
+ case OpMod: return CONST(::fmod(c1->value, c2->value));
+ case OpMul: return CONST(c1->value * c2->value);
+ case OpNotEqual: return CONST(c1->value != c2->value);
+ case OpOr: return CONST(c1->value ? c1->value : c2->value);
+ case OpRShift: return CONST(int(c1->value) >> int(c2->value));
+ case OpStrictEqual: return CONST(c1->value == c2->value);
+ case OpStrictNotEqual: return CONST(c1->value != c2->value);
+ case OpSub: return CONST(c1->value - c2->value);
+ case OpURShift: return CONST(unsigned(c1->value) >> int(c2->value));
+
+ case OpIfTrue: // unary ops
+ case OpNot:
+ case OpUMinus:
+ case OpUPlus:
+ case OpCompl:
+ case OpInvalid:
+ break;
+ }
+ }
+ }
+ }
+
+ Binop *e = function->pool->New<Binop>();
+ e->init(op, left, right);
+ return e;
+}
+
+Expr *BasicBlock::CALL(Expr *base, ExprList *args)
+{
+ Call *e = function->pool->New<Call>();
+ e->init(base, args);
+ return e;
+}
+
+Stmt *BasicBlock::EXP(Expr *expr)
+{
+ Exp *s = function->pool->New<Exp>();
+ s->init(expr);
+ statements.append(s);
+ return s;
+}
+
+Stmt *BasicBlock::MOVE(Expr *target, Expr *source, bool isMoveForReturn)
+{
+ Move *s = function->pool->New<Move>();
+ s->init(target, source, isMoveForReturn);
+ statements.append(s);
+ return s;
+}
+
+Stmt *BasicBlock::JUMP(BasicBlock *target)
+{
+ if (isTerminated())
+ return 0;
+
+ Jump *s = function->pool->New<Jump>();
+ s->init(target);
+ statements.append(s);
+ return s;
+}
+
+Stmt *BasicBlock::CJUMP(Expr *cond, BasicBlock *iftrue, BasicBlock *iffalse)
+{
+ if (isTerminated())
+ return 0;
+
+ CJump *s = function->pool->New<CJump>();
+ s->init(cond, iftrue, iffalse);
+ statements.append(s);
+ return s;
+}
+
+Stmt *BasicBlock::RET(Expr *expr, Type type, quint32 line, quint32 column)
+{
+ if (isTerminated())
+ return 0;
+
+ Ret *s = function->pool->New<Ret>();
+ s->init(expr, type, line, column);
+ statements.append(s);
+ return s;
+}
+
+void BasicBlock::dump(QTextStream &out)
+{
+ out << 'L' << this << ':' << endl;
+ foreach (Stmt *s, statements) {
+ out << '\t';
+ s->dump(out);
+ out << endl;
+ }
+}
+
+#ifdef DEBUG_IR_STRUCTURE
+
+static const char *symbolname(Name::Symbol s)
+{
+ switch (s) {
+ case Name::Unbound:
+ return "Unbound";
+ case Name::IdObject:
+ return "IdObject";
+ case Name::AttachType:
+ return "AttachType";
+ case Name::Object:
+ return "Object";
+ case Name::Property:
+ return "Property";
+ case Name::Slot:
+ return "Slot";
+ default:
+ Q_ASSERT(!"Unreachable");
+ return "Unknown";
+ }
+}
+
+static const char *storagename(Name::Storage s)
+{
+ switch (s) {
+ case Name::MemberStorage:
+ return "MemberStorage";
+ case Name::IdStorage:
+ return "IdStorage";
+ case Name::RootStorage:
+ return "RootStorage";
+ case Name::ScopeStorage:
+ return "ScopeStorage";
+ default:
+ Q_ASSERT(!"Unreachable");
+ return "UnknownStorage";
+ }
+}
+
+IRDump::IRDump()
+: indentSize(0)
+{
+}
+
+void IRDump::inc()
+{
+ indentSize++;
+ indentData = QByteArray(indentSize * 4, ' ');
+}
+
+void IRDump::dec()
+{
+ indentSize--;
+ indentData = QByteArray(indentSize * 4, ' ');
+}
+
+void IRDump::dec();
+
+void IRDump::expression(QQmlJS::IR::Expr *e)
+{
+ inc();
+
+ e->accept(this);
+
+ dec();
+}
+
+void IRDump::basicblock(QQmlJS::IR::BasicBlock *b)
+{
+ inc();
+
+ qWarning().nospace() << indent() << "BasicBlock " << b << " {";
+ for (int ii = 0; ii < b->statements.count(); ++ii) {
+ statement(b->statements.at(ii));
+ if (ii != (b->statements.count() - 1))
+ qWarning();
+ }
+ qWarning().nospace() << indent() << "}";
+
+ dec();
+}
+
+void IRDump::statement(QQmlJS::IR::Stmt *s)
+{
+ inc();
+
+ s->accept(this);
+
+ dec();
+}
+
+void IRDump::function(QQmlJS::IR::Function *f)
+{
+ inc();
+
+ qWarning().nospace() << indent() << "Function {";
+ for (int ii = 0; ii < f->basicBlocks.count(); ++ii) {
+ basicblock(f->basicBlocks.at(ii));
+ }
+ qWarning().nospace() << indent() << "}";
+
+ dec();
+}
+
+const char *IRDump::indent()
+{
+ return indentData.constData();
+}
+
+void IRDump::visitConst(QQmlJS::IR::Const *e)
+{
+ qWarning().nospace() << indent() << "Const:Expr { type: " << typeName(e->type) << ", value: " << e->value << "}";
+}
+
+void IRDump::visitString(QQmlJS::IR::String *e)
+{
+ qWarning().nospace() << indent() << "String:Expr { type: " << typeName(e->type) << ", value: " << e->value << "}";
+}
+
+static void namedumprecur(QQmlJS::IR::Name *e, const char *indent)
+{
+ if (e->base) namedumprecur(e->base, indent);
+ qWarning().nospace() << indent << " { type: " << typeName(e->type) << ", symbol: " << symbolname(e->symbol) << ", storage: " << storagename(e->storage) << ", id: " << e->id << "}";
+}
+
+void IRDump::visitName(QQmlJS::IR::Name *e)
+{
+ qWarning().nospace() << indent() << "Name:Expr {";
+ namedumprecur(e, indent());
+ qWarning().nospace() << indent() << "}";
+}
+
+void IRDump::visitTemp(QQmlJS::IR::Temp *e)
+{
+ qWarning().nospace() << indent() << "Temp:Expr { type: " << typeName(e->type) << ", index: " << e->index << " }";
+}
+
+void IRDump::visitUnop(QQmlJS::IR::Unop *e)
+{
+ qWarning().nospace() << indent() << "Unop:Expr { ";
+ qWarning().nospace() << indent() << " type: " << typeName(e->type) << ", op: " << opname(e->op);
+ qWarning().nospace() << indent() << " expr: {";
+ expression(e->expr);
+ qWarning().nospace() << indent() << " }";
+ qWarning().nospace() << indent() << "}";
+}
+
+void IRDump::visitBinop(QQmlJS::IR::Binop *e)
+{
+ qWarning().nospace() << indent() << "Binop:Expr { ";
+ qWarning().nospace() << indent() << " type: " << typeName(e->type) << ", op: " << opname(e->op);
+ qWarning().nospace() << indent() << " left: {";
+ inc();
+ expression(e->left);
+ dec();
+ qWarning().nospace() << indent() << " },";
+ qWarning().nospace() << indent() << " right: {";
+ inc();
+ expression(e->right);
+ dec();
+ qWarning().nospace() << indent() << " }";
+ qWarning().nospace() << indent() << "}";
+}
+
+void IRDump::visitCall(QQmlJS::IR::Call *e)
+{
+ Q_UNUSED(e);
+ qWarning().nospace() << indent() << "Exp::Call { }";
+}
+
+void IRDump::visitExp(QQmlJS::IR::Exp *s)
+{
+ qWarning().nospace() << indent() << "Exp:Stmt {";
+ expression(s->expr);
+ qWarning().nospace() << indent() << "}";
+}
+
+void IRDump::visitMove(QQmlJS::IR::Move *s)
+{
+ qWarning().nospace() << indent() << "Move:Stmt {";
+ qWarning().nospace() << indent() << " isMoveForReturn: " << s->isMoveForReturn;
+ qWarning().nospace() << indent() << " target: {";
+ inc();
+ expression(s->target);
+ dec();
+ qWarning().nospace() << indent() << " },";
+ qWarning().nospace() << indent() << " source: {";
+ inc();
+ expression(s->source);
+ dec();
+ qWarning().nospace() << indent() << " }";
+ qWarning().nospace() << indent() << "}";
+}
+
+void IRDump::visitJump(QQmlJS::IR::Jump *s)
+{
+ qWarning().nospace() << indent() << "Jump:Stmt { BasicBlock(" << s->target << ") }";
+}
+
+void IRDump::visitCJump(QQmlJS::IR::CJump *s)
+{
+ qWarning().nospace() << indent() << "CJump:Stmt {";
+ qWarning().nospace() << indent() << " cond: {";
+ inc();
+ expression(s->cond);
+ dec();
+ qWarning().nospace() << indent() << " }";
+ qWarning().nospace() << indent() << " iftrue: BasicBlock(" << s->iftrue << ")";
+ qWarning().nospace() << indent() << " iffalse: BasicBlock(" << s->iffalse << ")";
+ qWarning().nospace() << indent() << "}";
+}
+
+void IRDump::visitRet(QQmlJS::IR::Ret *s)
+{
+ qWarning().nospace() << indent() << "Ret:Stmt {";
+ qWarning().nospace() << indent() << " type: " << typeName(s->type);
+ expression(s->expr);
+ qWarning().nospace() << indent() << "}";
+}
+#endif
+
+} // end of namespace IR
+} // end of namespace QQmlJS
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/v4/qv4ir_p.h b/src/qml/qml/v4/qv4ir_p.h
new file mode 100644
index 0000000000..48a08adf9f
--- /dev/null
+++ b/src/qml/qml/v4/qv4ir_p.h
@@ -0,0 +1,604 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QV4IR_P_H
+#define QV4IR_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qqmljsast_p.h>
+#include <private/qqmljsengine_p.h>
+#include <private/qqmlscript_p.h>
+#include <private/qqmlimport_p.h>
+#include <private/qqmlengine_p.h>
+#include <private/qv4compiler_p.h>
+
+#include <private/qqmlpool_p.h>
+#include <QtCore/qvarlengtharray.h>
+
+// #define DEBUG_IR_STRUCTURE
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class QTextStream;
+class QQmlType;
+
+namespace QQmlJS {
+
+namespace IR {
+
+struct BasicBlock;
+struct Function;
+
+struct Stmt;
+struct Expr;
+
+// expressions
+struct Const;
+struct String;
+struct Name;
+struct Temp;
+struct Unop;
+struct Binop;
+struct Call;
+
+// statements
+struct Exp;
+struct Move;
+struct Jump;
+struct CJump;
+struct Ret;
+
+enum AluOp {
+ OpInvalid = 0,
+
+ OpIfTrue,
+ OpNot,
+ OpUMinus,
+ OpUPlus,
+ OpCompl,
+
+ OpBitAnd,
+ OpBitOr,
+ OpBitXor,
+
+ OpAdd,
+ OpSub,
+ OpMul,
+ OpDiv,
+ OpMod,
+
+ OpLShift,
+ OpRShift,
+ OpURShift,
+
+ OpGt,
+ OpLt,
+ OpGe,
+ OpLe,
+ OpEqual,
+ OpNotEqual,
+ OpStrictEqual,
+ OpStrictNotEqual,
+
+ OpAnd,
+ OpOr
+};
+AluOp binaryOperator(int op);
+
+enum Type {
+ InvalidType,
+ UndefinedType,
+ NullType,
+ VoidType,
+ StringType,
+ UrlType,
+ SGAnchorLineType,
+ AttachType,
+ ObjectType,
+
+ FirstNumberType,
+ BoolType = FirstNumberType,
+ IntType,
+ RealType,
+ RealNaNType
+};
+Type maxType(IR::Type left, IR::Type right);
+
+struct ExprVisitor {
+ virtual ~ExprVisitor() {}
+ virtual void visitConst(Const *) {}
+ virtual void visitString(String *) {}
+ virtual void visitName(Name *) {}
+ virtual void visitTemp(Temp *) {}
+ virtual void visitUnop(Unop *) {}
+ virtual void visitBinop(Binop *) {}
+ virtual void visitCall(Call *) {}
+};
+
+struct StmtVisitor {
+ virtual ~StmtVisitor() {}
+ virtual void visitExp(Exp *) {}
+ virtual void visitMove(Move *) {}
+ virtual void visitJump(Jump *) {}
+ virtual void visitCJump(CJump *) {}
+ virtual void visitRet(Ret *) {}
+};
+
+struct Expr: QQmlPool::POD {
+ Type type;
+
+ Expr(): type(InvalidType) {}
+ virtual ~Expr() {}
+ virtual void accept(ExprVisitor *) = 0;
+ virtual Const *asConst() { return 0; }
+ virtual String *asString() { return 0; }
+ virtual Name *asName() { return 0; }
+ virtual Temp *asTemp() { return 0; }
+ virtual Unop *asUnop() { return 0; }
+ virtual Binop *asBinop() { return 0; }
+ virtual Call *asCall() { return 0; }
+ virtual void dump(QTextStream &out) = 0;
+};
+
+struct ExprList: QQmlPool::POD {
+ Expr *expr;
+ ExprList *next;
+
+ void init(Expr *expr, ExprList *next = 0)
+ {
+ this->expr = expr;
+ this->next = next;
+ }
+};
+
+struct Const: Expr {
+ double value;
+
+ void init(Type type, double value)
+ {
+ this->type = type;
+ this->value = value;
+ }
+
+ virtual void accept(ExprVisitor *v) { v->visitConst(this); }
+ virtual Const *asConst() { return this; }
+
+ virtual void dump(QTextStream &out);
+};
+
+struct String: Expr {
+ QStringRef value;
+
+ void init(const QStringRef &value)
+ {
+ this->type = StringType;
+ this->value = value;
+ }
+
+ virtual void accept(ExprVisitor *v) { v->visitString(this); }
+ virtual String *asString() { return this; }
+
+ virtual void dump(QTextStream &out);
+ static QString escape(const QStringRef &s);
+};
+
+enum BuiltinSymbol {
+ NoBuiltinSymbol,
+ MathSinBultinFunction,
+ MathCosBultinFunction,
+ MathRoundBultinFunction,
+ MathFloorBultinFunction,
+
+ MathPIBuiltinConstant
+};
+
+struct Name: Expr {
+ enum Symbol {
+ Unbound,
+ IdObject, // This is a load of a id object. Storage will always be IdStorage
+ AttachType, // This is a load of an attached object
+ Object, // XXX what is this for?
+ Property, // This is a load of a regular property
+ Slot // XXX what is this for?
+ };
+
+ enum Storage {
+ MemberStorage, // This is a property of a previously fetched object
+ IdStorage, // This is a load of a id object. Symbol will always be IdObject
+ RootStorage, // This is a property of the root object
+ ScopeStorage // This is a property of the scope object
+ };
+
+ Name *base;
+ const QString *id;
+ Symbol symbol;
+ union {
+ void *ptr;
+ const QMetaObject *meta;
+ const QQmlType *declarativeType;
+ const QQmlScript::Object *idObject;
+ };
+ QQmlPropertyData *property;
+ Storage storage;
+ BuiltinSymbol builtin;
+ quint32 line;
+ quint32 column;
+
+ void init(Name *base, Type type, const QString *id, Symbol symbol, quint32 line, quint32 column);
+
+ inline bool is(Symbol s) const { return s == symbol; }
+ inline bool isNot(Symbol s) const { return s != symbol; }
+
+ virtual void accept(ExprVisitor *v) { v->visitName(this); }
+ virtual Name *asName() { return this; }
+
+ virtual void dump(QTextStream &out);
+};
+
+struct Temp: Expr {
+ int index;
+
+ void init(Type type, int index)
+ {
+ this->type = type;
+ this->index = index;
+ }
+
+ virtual void accept(ExprVisitor *v) { v->visitTemp(this); }
+ virtual Temp *asTemp() { return this; }
+
+ virtual void dump(QTextStream &out);
+};
+
+struct Unop: Expr {
+ AluOp op;
+ Expr *expr;
+
+ void init(AluOp op, Expr *expr)
+ {
+ this->type = this->typeForOp(op, expr);
+ this->op = op;
+ this->expr = expr;
+ }
+
+ virtual void accept(ExprVisitor *v) { v->visitUnop(this); }
+ virtual Unop *asUnop() { return this; }
+
+ virtual void dump(QTextStream &out);
+
+private:
+ static Type typeForOp(AluOp op, Expr *expr);
+};
+
+struct Binop: Expr {
+ AluOp op;
+ Expr *left;
+ Expr *right;
+
+ void init(AluOp op, Expr *left, Expr *right)
+ {
+ this->type = typeForOp(op, left, right);
+ this->op = op;
+ this->left = left;
+ this->right = right;
+ }
+
+ virtual void accept(ExprVisitor *v) { v->visitBinop(this); }
+ virtual Binop *asBinop() { return this; }
+
+ virtual void dump(QTextStream &out);
+
+private:
+ static Type typeForOp(AluOp op, Expr *left, Expr *right);
+};
+
+struct Call: Expr {
+ Expr *base;
+ ExprList *args;
+
+ void init(Expr *base, ExprList *args)
+ {
+ this->type = typeForFunction(base);
+ this->base = base;
+ this->args = args;
+ }
+
+ Expr *onlyArgument() const {
+ if (args && ! args->next)
+ return args->expr;
+ return 0;
+ }
+
+ virtual void accept(ExprVisitor *v) { v->visitCall(this); }
+ virtual Call *asCall() { return this; }
+
+ virtual void dump(QTextStream &out);
+
+private:
+ static Type typeForFunction(Expr *base);
+};
+
+struct Stmt: QQmlPool::POD {
+ enum Mode {
+ HIR,
+ MIR
+ };
+
+ virtual ~Stmt() {}
+ virtual Stmt *asTerminator() { return 0; }
+
+ virtual void accept(StmtVisitor *) = 0;
+ virtual Exp *asExp() { return 0; }
+ virtual Move *asMove() { return 0; }
+ virtual Jump *asJump() { return 0; }
+ virtual CJump *asCJump() { return 0; }
+ virtual Ret *asRet() { return 0; }
+ virtual void dump(QTextStream &out, Mode mode = HIR) = 0;
+};
+
+struct Exp: Stmt {
+ Expr *expr;
+
+ void init(Expr *expr)
+ {
+ this->expr = expr;
+ }
+
+ virtual void accept(StmtVisitor *v) { v->visitExp(this); }
+ virtual Exp *asExp() { return this; }
+
+ virtual void dump(QTextStream &out, Mode);
+};
+
+struct Move: Stmt {
+ Expr *target;
+ Expr *source;
+ bool isMoveForReturn;
+
+ void init(Expr *target, Expr *source, bool isMoveForReturn)
+ {
+ this->target = target;
+ this->source = source;
+ this->isMoveForReturn = isMoveForReturn;
+ }
+
+ virtual void accept(StmtVisitor *v) { v->visitMove(this); }
+ virtual Move *asMove() { return this; }
+
+ virtual void dump(QTextStream &out, Mode);
+};
+
+struct Jump: Stmt {
+ BasicBlock *target;
+
+ void init(BasicBlock *target)
+ {
+ this->target = target;
+ }
+
+ virtual Stmt *asTerminator() { return this; }
+
+ virtual void accept(StmtVisitor *v) { v->visitJump(this); }
+ virtual Jump *asJump() { return this; }
+
+ virtual void dump(QTextStream &out, Mode mode);
+};
+
+struct CJump: Stmt {
+ Expr *cond;
+ BasicBlock *iftrue;
+ BasicBlock *iffalse;
+
+ void init(Expr *cond, BasicBlock *iftrue, BasicBlock *iffalse)
+ {
+ this->cond = cond;
+ this->iftrue = iftrue;
+ this->iffalse = iffalse;
+ }
+
+ virtual Stmt *asTerminator() { return this; }
+
+ virtual void accept(StmtVisitor *v) { v->visitCJump(this); }
+ virtual CJump *asCJump() { return this; }
+
+ virtual void dump(QTextStream &out, Mode mode);
+};
+
+struct Ret: Stmt {
+ Expr *expr;
+ Type type;
+ quint32 line;
+ quint32 column;
+
+ void init(Expr *expr, Type type, quint32 line, quint32 column)
+ {
+ this->expr = expr;
+ this->type = type;
+ this->line = line;
+ this->column = column;
+ }
+
+ virtual Stmt *asTerminator() { return this; }
+
+ virtual void accept(StmtVisitor *v) { v->visitRet(this); }
+ virtual Ret *asRet() { return this; }
+
+ virtual void dump(QTextStream &out, Mode);
+};
+
+struct Function {
+ QQmlPool *pool;
+ QVarLengthArray<BasicBlock *, 8> basicBlocks;
+ int tempCount;
+
+ Function(QQmlPool *pool)
+ : pool(pool), tempCount(0) {}
+
+ ~Function();
+
+ BasicBlock *newBasicBlock();
+ QString *newString(const QString &text);
+
+ inline BasicBlock *i(BasicBlock *block) { basicBlocks.append(block); return block; }
+
+ virtual void dump(QTextStream &out);
+};
+
+struct BasicBlock {
+ Function *function;
+ int index;
+ int offset;
+ QVarLengthArray<Stmt *, 32> statements;
+
+ BasicBlock(Function *function, int index): function(function), index(index), offset(-1) {}
+ ~BasicBlock() {}
+
+ template <typename Instr> inline Instr i(Instr i) { statements.append(i); return i; }
+
+ inline bool isEmpty() const {
+ return statements.isEmpty();
+ }
+
+ inline Stmt *terminator() const {
+ if (! statements.isEmpty() && statements.at(statements.size() - 1)->asTerminator() != 0)
+ return statements.at(statements.size() - 1);
+ return 0;
+ }
+
+ inline bool isTerminated() const {
+ if (terminator() != 0)
+ return true;
+ return false;
+ }
+
+ Temp *TEMP(Type type, int index);
+ Temp *TEMP(Type type);
+
+ Expr *CONST(double value);
+ Expr *CONST(Type type, double value);
+ Expr *STRING(const QStringRef &value);
+
+ Name *NAME(const QString &id, quint32 line, quint32 column);
+ Name *NAME(Name *base, const QString &id, quint32 line, quint32 column);
+ Name *SYMBOL(Type type, const QString &id, const QMetaObject *meta, QQmlPropertyData *property, Name::Storage storage, quint32 line, quint32 column);
+ Name *SYMBOL(Name *base, Type type, const QString &id, const QMetaObject *meta, QQmlPropertyData *property, quint32 line, quint32 column);
+ Name *SYMBOL(Name *base, Type type, const QString &id, const QMetaObject *meta, QQmlPropertyData *property, Name::Storage storage, quint32 line, quint32 column);
+ Name *ID_OBJECT(const QString &id, const QQmlScript::Object *object, quint32 line, quint32 column);
+ Name *ATTACH_TYPE(const QString &id, const QQmlType *attachType, Name::Storage storage, quint32 line, quint32 column);
+
+ Expr *UNOP(AluOp op, Expr *expr);
+ Expr *BINOP(AluOp op, Expr *left, Expr *right);
+ Expr *CALL(Expr *base, ExprList *args);
+
+ Stmt *EXP(Expr *expr);
+ Stmt *MOVE(Expr *target, Expr *source, bool = false);
+
+ Stmt *JUMP(BasicBlock *target);
+ Stmt *CJUMP(Expr *cond, BasicBlock *iftrue, BasicBlock *iffalse);
+ Stmt *RET(Expr *expr, Type type, quint32 line, quint32 column);
+
+ virtual void dump(QTextStream &out);
+};
+
+#ifdef DEBUG_IR_STRUCTURE
+struct IRDump : public ExprVisitor,
+ public StmtVisitor
+{
+public:
+ IRDump();
+
+ void expression(QQmlJS::IR::Expr *);
+ void basicblock(QQmlJS::IR::BasicBlock *);
+ void statement(QQmlJS::IR::Stmt *);
+ void function(QQmlJS::IR::Function *);
+protected:
+
+ const char *indent();
+
+ //
+ // expressions
+ //
+ virtual void visitConst(QQmlJS::IR::Const *e);
+ virtual void visitString(QQmlJS::IR::String *e);
+ virtual void visitName(QQmlJS::IR::Name *e);
+ virtual void visitTemp(QQmlJS::IR::Temp *e);
+ virtual void visitUnop(QQmlJS::IR::Unop *e);
+ virtual void visitBinop(QQmlJS::IR::Binop *e);
+ virtual void visitCall(QQmlJS::IR::Call *e);
+
+ //
+ // statements
+ //
+ virtual void visitExp(QQmlJS::IR::Exp *s);
+ virtual void visitMove(QQmlJS::IR::Move *s);
+ virtual void visitJump(QQmlJS::IR::Jump *s);
+ virtual void visitCJump(QQmlJS::IR::CJump *s);
+ virtual void visitRet(QQmlJS::IR::Ret *s);
+
+private:
+ int indentSize;
+ QByteArray indentData;
+ void inc();
+ void dec();
+};
+#endif
+
+} // end of namespace IR
+
+} // end of namespace QQmlJS
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QV4IR_P_H
diff --git a/src/qml/qml/v4/qv4irbuilder.cpp b/src/qml/qml/v4/qv4irbuilder.cpp
new file mode 100644
index 0000000000..1956be8e72
--- /dev/null
+++ b/src/qml/qml/v4/qv4irbuilder.cpp
@@ -0,0 +1,1303 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qv4irbuilder_p.h"
+#include "qv4compiler_p_p.h"
+
+#include <private/qqmlglobal_p.h>
+#include <private/qqmlmetatype_p.h>
+#include <private/qqmltypenamecache_p.h>
+
+DEFINE_BOOL_CONFIG_OPTION(qmlVerboseCompiler, QML_VERBOSE_COMPILER)
+
+QT_BEGIN_NAMESPACE
+
+using namespace QQmlJS;
+
+static IR::Type irTypeFromVariantType(int t, QQmlEnginePrivate *engine, const QMetaObject * /* meta */)
+{
+ switch (t) {
+ case QMetaType::Bool:
+ return IR::BoolType;
+
+ case QMetaType::Int:
+ return IR::IntType;
+
+ case QMetaType::QReal:
+ return IR::RealType;
+
+ case QMetaType::QString:
+ return IR::StringType;
+
+ case QMetaType::QUrl:
+ return IR::UrlType;
+
+ default:
+ if (t == QQmlMetaType::QQuickAnchorLineMetaTypeId()) {
+ return IR::SGAnchorLineType;
+ } else if (engine->metaObjectForType(t)) {
+ return IR::ObjectType;
+ }
+
+ return IR::InvalidType;
+ }
+}
+
+QV4IRBuilder::QV4IRBuilder(const QV4Compiler::Expression *expr,
+ QQmlEnginePrivate *engine)
+: m_expression(expr), m_engine(engine), _function(0), _block(0), _discard(false)
+{
+}
+
+bool QV4IRBuilder::operator()(QQmlJS::IR::Function *function,
+ QQmlJS::AST::Node *ast)
+{
+ bool discarded = false;
+
+ IR::BasicBlock *block = function->newBasicBlock();
+
+ qSwap(_discard, discarded);
+ qSwap(_function, function);
+ qSwap(_block, block);
+
+ ExprResult r;
+ AST::SourceLocation location;
+ if (AST::ExpressionNode *asExpr = ast->expressionCast()) {
+ r = expression(asExpr);
+ location = asExpr->firstSourceLocation();
+ } else if (AST::Statement *asStmt = ast->statementCast()) {
+ r = statement(asStmt);
+ location = asStmt->firstSourceLocation();
+ }
+
+ //_block->MOVE(_block->TEMP(IR::InvalidType), r.code);
+ if (r.code) {
+ const QMetaObject *m = 0;
+ const IR::Type targetType = irTypeFromVariantType(m_expression->property->type, m_engine, m);
+ if (targetType != r.type()) {
+ IR::Expr *x = _block->TEMP(targetType);
+ _block->MOVE(x, r, true);
+ r.code = x;
+ }
+ _block->RET(r.code, targetType, location.startLine, location.startColumn);
+ }
+
+ qSwap(_block, block);
+ qSwap(_function, function);
+ qSwap(_discard, discarded);
+
+ return !discarded;
+}
+
+bool QV4IRBuilder::buildName(QList<QStringRef> &name,
+ AST::Node *node,
+ QList<AST::ExpressionNode *> *nodes)
+{
+ if (node->kind == AST::Node::Kind_IdentifierExpression) {
+ name << static_cast<AST::IdentifierExpression*>(node)->name;
+ if (nodes) *nodes << static_cast<AST::IdentifierExpression*>(node);
+ } else if (node->kind == AST::Node::Kind_FieldMemberExpression) {
+ AST::FieldMemberExpression *expr =
+ static_cast<AST::FieldMemberExpression *>(node);
+
+ if (!buildName(name, expr->base, nodes))
+ return false;
+
+ name << expr->name;
+ if (nodes) *nodes << expr;
+ } else {
+ return false;
+ }
+
+ return true;
+}
+
+void QV4IRBuilder::discard()
+{
+ _discard = true;
+}
+
+QV4IRBuilder::ExprResult
+QV4IRBuilder::expression(AST::ExpressionNode *ast)
+{
+ ExprResult r;
+ if (ast) {
+ qSwap(_expr, r);
+ accept(ast);
+ qSwap(_expr, r);
+
+ if (r.is(IR::InvalidType))
+ discard();
+ else {
+ Q_ASSERT(r.hint == r.format);
+ }
+ }
+
+ return r;
+}
+
+void QV4IRBuilder::condition(AST::ExpressionNode *ast, IR::BasicBlock *iftrue, IR::BasicBlock *iffalse)
+{
+ if (! ast)
+ return;
+ ExprResult r(iftrue, iffalse);
+ qSwap(_expr, r);
+ accept(ast);
+ qSwap(_expr, r);
+
+ if (r.format != ExprResult::cx) {
+ if (! r.code)
+ discard();
+
+ Q_ASSERT(r.hint == ExprResult::cx);
+ Q_ASSERT(r.format == ExprResult::ex);
+
+ if (r.type() != IR::BoolType) {
+ IR::Temp *t = _block->TEMP(IR::BoolType);
+ _block->MOVE(t, r);
+ r = t;
+ }
+
+ _block->CJUMP(_block->UNOP(IR::OpIfTrue, r), iftrue, iffalse);
+ }
+}
+
+QV4IRBuilder::ExprResult
+QV4IRBuilder::statement(AST::Statement *ast)
+{
+ ExprResult r;
+ if (ast) {
+ qSwap(_expr, r);
+ accept(ast);
+ qSwap(_expr, r);
+
+ if (r.is(IR::InvalidType))
+ discard();
+ else {
+ Q_ASSERT(r.hint == r.format);
+ }
+ }
+
+ return r;
+}
+
+void QV4IRBuilder::sourceElement(AST::SourceElement *ast)
+{
+ accept(ast);
+}
+
+void QV4IRBuilder::implicitCvt(ExprResult &expr, IR::Type type)
+{
+ if (expr.type() == type)
+ return; // nothing to do
+
+ IR::Expr *x = _block->TEMP(type);
+ _block->MOVE(x, expr.code);
+ expr.code = x;
+}
+
+// QML
+bool QV4IRBuilder::visit(AST::UiProgram *)
+{
+ Q_ASSERT(!"unreachable");
+ return false;
+}
+
+bool QV4IRBuilder::visit(AST::UiImportList *)
+{
+ Q_ASSERT(!"unreachable");
+ return false;
+}
+
+bool QV4IRBuilder::visit(AST::UiImport *)
+{
+ Q_ASSERT(!"unreachable");
+ return false;
+}
+
+bool QV4IRBuilder::visit(AST::UiPublicMember *)
+{
+ Q_ASSERT(!"unreachable");
+ return false;
+}
+
+bool QV4IRBuilder::visit(AST::UiSourceElement *)
+{
+ Q_ASSERT(!"unreachable");
+ return false;
+}
+
+bool QV4IRBuilder::visit(AST::UiObjectDefinition *)
+{
+ Q_ASSERT(!"unreachable");
+ return false;
+}
+
+bool QV4IRBuilder::visit(AST::UiObjectInitializer *)
+{
+ Q_ASSERT(!"unreachable");
+ return false;
+}
+
+bool QV4IRBuilder::visit(AST::UiObjectBinding *)
+{
+ Q_ASSERT(!"unreachable");
+ return false;
+}
+
+bool QV4IRBuilder::visit(AST::UiScriptBinding *)
+{
+ Q_ASSERT(!"unreachable");
+ return false;
+}
+
+bool QV4IRBuilder::visit(AST::UiArrayBinding *)
+{
+ Q_ASSERT(!"unreachable");
+ return false;
+}
+
+bool QV4IRBuilder::visit(AST::UiObjectMemberList *)
+{
+ Q_ASSERT(!"unreachable");
+ return false;
+}
+
+bool QV4IRBuilder::visit(AST::UiArrayMemberList *)
+{
+ Q_ASSERT(!"unreachable");
+ return false;
+}
+
+bool QV4IRBuilder::visit(AST::UiQualifiedId *)
+{
+ Q_ASSERT(!"unreachable");
+ return false;
+}
+
+
+// JS
+bool QV4IRBuilder::visit(AST::Program *)
+{
+ Q_ASSERT(!"unreachable");
+ return false;
+}
+
+bool QV4IRBuilder::visit(AST::SourceElements *)
+{
+ Q_ASSERT(!"unreachable");
+ return false;
+}
+
+bool QV4IRBuilder::visit(AST::FunctionSourceElement *)
+{
+ Q_ASSERT(!"unreachable");
+ return false;
+}
+
+bool QV4IRBuilder::visit(AST::StatementSourceElement *)
+{
+ Q_ASSERT(!"unreachable");
+ return false;
+}
+
+// object literals
+bool QV4IRBuilder::visit(AST::PropertyNameAndValueList *)
+{
+ Q_ASSERT(!"unreachable");
+ return false;
+}
+
+bool QV4IRBuilder::visit(AST::IdentifierPropertyName *)
+{
+ Q_ASSERT(!"unreachable");
+ return false;
+}
+
+bool QV4IRBuilder::visit(AST::StringLiteralPropertyName *)
+{
+ Q_ASSERT(!"unreachable");
+ return false;
+}
+
+bool QV4IRBuilder::visit(AST::NumericLiteralPropertyName *)
+{
+ Q_ASSERT(!"unreachable");
+ return false;
+}
+
+
+// array literals
+bool QV4IRBuilder::visit(AST::ElementList *)
+{
+ Q_ASSERT(!"unreachable");
+ return false;
+}
+
+bool QV4IRBuilder::visit(AST::Elision *)
+{
+ Q_ASSERT(!"unreachable");
+ return false;
+}
+
+
+// function calls
+bool QV4IRBuilder::visit(AST::ArgumentList *)
+{
+ Q_ASSERT(!"unreachable");
+ return false;
+}
+
+// expressions
+bool QV4IRBuilder::visit(AST::ObjectLiteral *)
+{
+ return false;
+}
+
+bool QV4IRBuilder::visit(AST::ArrayLiteral *)
+{
+ return false;
+}
+
+bool QV4IRBuilder::visit(AST::ThisExpression *)
+{
+ return false;
+}
+
+bool QV4IRBuilder::visit(AST::IdentifierExpression *ast)
+{
+ const quint32 line = ast->identifierToken.startLine;
+ const quint32 column = ast->identifierToken.startColumn;
+
+ const QString name = ast->name.toString();
+
+ if (name.at(0) == QLatin1Char('u') && name.length() == 9 && name == QLatin1String("undefined")) {
+ _expr.code = _block->CONST(IR::UndefinedType, 0); // ### undefined value
+ } else if (m_engine->v8engine()->illegalNames().contains(name) ) {
+ if (qmlVerboseCompiler()) qWarning() << "*** illegal symbol:" << name;
+ return false;
+ } else if (const QQmlScript::Object *obj = m_expression->ids->value(name)) {
+ IR::Name *code = _block->ID_OBJECT(name, obj, line, column);
+ if (obj == m_expression->component)
+ code->storage = IR::Name::RootStorage;
+ _expr.code = code;
+ } else {
+
+ QQmlTypeNameCache::Result r = m_expression->importCache->query(name);
+ if (r.isValid()) {
+ if (r.type) {
+ _expr.code = _block->ATTACH_TYPE(name, r.type, IR::Name::ScopeStorage, line, column);
+ }
+ // We don't support anything else
+ } else {
+ bool found = false;
+
+ if (m_expression->context != m_expression->component) {
+ // RootStorage is more efficient than ScopeStorage, so prefer that if they are the same
+ QQmlPropertyCache *cache = m_expression->context->synthCache;
+ const QMetaObject *metaObject = m_expression->context->metaObject();
+ if (!cache) cache = m_engine->cache(metaObject);
+
+ QQmlPropertyData *data = cache->property(name);
+
+ if (data && data->revision != 0) {
+ if (qmlVerboseCompiler())
+ qWarning() << "*** versioned symbol:" << name;
+ discard();
+ return false;
+ }
+
+ if (data && !data->isFunction()) {
+ IR::Type irType = irTypeFromVariantType(data->propType, m_engine, metaObject);
+ _expr.code = _block->SYMBOL(irType, name, metaObject, data, IR::Name::ScopeStorage, line, column);
+ found = true;
+ }
+ }
+
+ if (!found) {
+ QQmlPropertyCache *cache = m_expression->component->synthCache;
+ const QMetaObject *metaObject = m_expression->component->metaObject();
+ if (!cache) cache = m_engine->cache(metaObject);
+
+ QQmlPropertyData *data = cache->property(name);
+
+ if (data && data->revision != 0) {
+ if (qmlVerboseCompiler())
+ qWarning() << "*** versioned symbol:" << name;
+ discard();
+ return false;
+ }
+
+ if (data && !data->isFunction()) {
+ IR::Type irType = irTypeFromVariantType(data->propType, m_engine, metaObject);
+ _expr.code = _block->SYMBOL(irType, name, metaObject, data, IR::Name::RootStorage, line, column);
+ found = true;
+ }
+ }
+
+ if (!found && qmlVerboseCompiler())
+ qWarning() << "*** unknown symbol:" << name;
+ }
+ }
+
+ if (_expr.code && _expr.hint == ExprResult::cx) {
+ _expr.format = ExprResult::cx;
+
+ if (_expr.type() != IR::BoolType) {
+ IR::Temp *t = _block->TEMP(IR::BoolType);
+ _block->MOVE(t, _expr);
+ _expr.code = t;
+ }
+
+ _block->CJUMP(_expr.code, _expr.iftrue, _expr.iffalse);
+ _expr.code = 0;
+ }
+
+ return false;
+}
+
+bool QV4IRBuilder::visit(AST::NullExpression *)
+{
+ // ### TODO: cx format
+ _expr.code = _block->CONST(IR::NullType, 0);
+ return false;
+}
+
+bool QV4IRBuilder::visit(AST::TrueLiteral *)
+{
+ // ### TODO: cx format
+ _expr.code = _block->CONST(IR::BoolType, 1);
+ return false;
+}
+
+bool QV4IRBuilder::visit(AST::FalseLiteral *)
+{
+ // ### TODO: cx format
+ _expr.code = _block->CONST(IR::BoolType, 0);
+ return false;
+}
+
+bool QV4IRBuilder::visit(AST::StringLiteral *ast)
+{
+ // ### TODO: cx format
+ _expr.code = _block->STRING(ast->value);
+ return false;
+}
+
+bool QV4IRBuilder::visit(AST::NumericLiteral *ast)
+{
+ if (_expr.hint == ExprResult::cx) {
+ _expr.format = ExprResult::cx;
+ _block->JUMP(ast->value ? _expr.iftrue : _expr.iffalse);
+ } else {
+ _expr.code = _block->CONST(ast->value);
+ }
+ return false;
+}
+
+bool QV4IRBuilder::visit(AST::RegExpLiteral *)
+{
+ return false;
+}
+
+bool QV4IRBuilder::visit(AST::NestedExpression *)
+{
+ return true; // the value of the nested expression
+}
+
+bool QV4IRBuilder::visit(AST::ArrayMemberExpression *)
+{
+ return false;
+}
+
+bool QV4IRBuilder::visit(AST::FieldMemberExpression *ast)
+{
+ if (IR::Expr *left = expression(ast->base)) {
+ if (IR::Name *baseName = left->asName()) {
+ const quint32 line = ast->identifierToken.startLine;
+ const quint32 column = ast->identifierToken.startColumn;
+
+ QString name = ast->name.toString();
+
+ switch(baseName->symbol) {
+ case IR::Name::Unbound:
+ break;
+
+ case IR::Name::AttachType:
+ if (name.at(0).isUpper()) {
+ QByteArray utf8Name = name.toUtf8();
+ const char *enumName = utf8Name.constData();
+
+ const QMetaObject *meta = baseName->declarativeType->metaObject();
+ bool found = false;
+ for (int ii = 0; !found && ii < meta->enumeratorCount(); ++ii) {
+ QMetaEnum e = meta->enumerator(ii);
+ for (int jj = 0; !found && jj < e.keyCount(); ++jj) {
+ if (0 == strcmp(e.key(jj), enumName)) {
+ found = true;
+ _expr.code = _block->CONST(IR::IntType, e.value(jj));
+ }
+ }
+ }
+
+ if (!found && qmlVerboseCompiler())
+ qWarning() << "*** unresolved enum:"
+ << (*baseName->id + QLatin1String(".") + ast->name.toString());
+ } else if(const QMetaObject *attachedMeta = baseName->declarativeType->attachedPropertiesType()) {
+ QQmlPropertyCache *cache = m_engine->cache(attachedMeta);
+ QQmlPropertyData *data = cache->property(name);
+
+ if (!data || data->isFunction())
+ return false; // Don't support methods (or non-existing properties ;)
+
+ if(!data->isFinal()) {
+ if (qmlVerboseCompiler())
+ qWarning() << "*** non-final attached property:"
+ << (*baseName->id + QLatin1String(".") + ast->name.toString());
+ return false; // We don't know enough about this property
+ }
+
+ IR::Type irType = irTypeFromVariantType(data->propType, m_engine, attachedMeta);
+ _expr.code = _block->SYMBOL(baseName, irType, name, attachedMeta, data, line, column);
+ }
+ break;
+
+ case IR::Name::IdObject: {
+ const QQmlScript::Object *idObject = baseName->idObject;
+ QQmlPropertyCache *cache =
+ idObject->synthCache?idObject->synthCache:m_engine->cache(idObject->metaObject());
+
+ QQmlPropertyData *data = cache->property(name);
+
+ if (!data || data->isFunction())
+ return false; // Don't support methods (or non-existing properties ;)
+
+ if (data->revision != 0) {
+ if (qmlVerboseCompiler())
+ qWarning() << "*** versioned symbol:" << name;
+ discard();
+ return false;
+ }
+
+ IR::Type irType = irTypeFromVariantType(data->propType, m_engine, idObject->metaObject());
+ _expr.code = _block->SYMBOL(baseName, irType, name,
+ idObject->metaObject(), data, line, column);
+ }
+ break;
+
+ case IR::Name::Property:
+ if (baseName->type == IR::ObjectType && baseName->meta && baseName->property->isFinal()) {
+ QQmlPropertyCache *cache = m_engine->cache(baseName->meta);
+ if (!cache)
+ return false;
+
+ if (QQmlPropertyData *data = cache->property(name)) {
+ if (!data->isFinal()) {
+ if (qmlVerboseCompiler())
+ qWarning() << "*** non-final property access:"
+ << (*baseName->id + QLatin1String(".") + ast->name.toString());
+ return false; // We don't know enough about this property
+ }
+
+ IR::Type irType = irTypeFromVariantType(data->propType, m_engine, baseName->meta);
+ _expr.code = _block->SYMBOL(baseName, irType, name,
+ baseName->meta, data, line, column);
+ }
+ }
+ break;
+
+ case IR::Name::Object:
+ case IR::Name::Slot:
+ break;
+ }
+ }
+ }
+
+ return false;
+}
+
+bool QV4IRBuilder::preVisit(AST::Node *)
+{
+ return ! _discard;
+}
+
+bool QV4IRBuilder::visit(AST::NewMemberExpression *)
+{
+ return false;
+}
+
+bool QV4IRBuilder::visit(AST::NewExpression *)
+{
+ return false;
+}
+
+bool QV4IRBuilder::visit(AST::CallExpression *ast)
+{
+ QList<QStringRef> names;
+ QList<AST::ExpressionNode *> nameNodes;
+
+ names.reserve(4);
+ nameNodes.reserve(4);
+
+ if (buildName(names, ast->base, &nameNodes)) {
+ //ExprResult base = expression(ast->base);
+ QString id;
+ for (int i = 0; i < names.size(); ++i) {
+ if (! i)
+ id += QLatin1Char('.');
+ id += names.at(i);
+ }
+ const AST::SourceLocation loc = nameNodes.last()->firstSourceLocation();
+ IR::Expr *base = _block->NAME(id, loc.startLine, loc.startColumn);
+
+ IR::ExprList *args = 0, **argsInserter = &args;
+ for (AST::ArgumentList *it = ast->arguments; it; it = it->next) {
+ IR::Expr *arg = expression(it->expression);
+ *argsInserter = _function->pool->New<IR::ExprList>();
+ (*argsInserter)->init(arg);
+ argsInserter = &(*argsInserter)->next;
+ }
+
+ IR::Temp *r = _block->TEMP(IR::InvalidType);
+ IR::Expr *call = _block->CALL(base, args);
+ _block->MOVE(r, call);
+ r->type = call->type;
+ _expr.code = r;
+ }
+
+ return false;
+}
+
+bool QV4IRBuilder::visit(AST::PostIncrementExpression *)
+{
+ return false;
+}
+
+bool QV4IRBuilder::visit(AST::PostDecrementExpression *)
+{
+ return false;
+}
+
+bool QV4IRBuilder::visit(AST::DeleteExpression *)
+{
+ return false;
+}
+
+bool QV4IRBuilder::visit(AST::VoidExpression *)
+{
+ return false;
+}
+
+bool QV4IRBuilder::visit(AST::TypeOfExpression *)
+{
+ return false;
+}
+
+bool QV4IRBuilder::visit(AST::PreIncrementExpression *)
+{
+ return false;
+}
+
+bool QV4IRBuilder::visit(AST::PreDecrementExpression *)
+{
+ return false;
+}
+
+bool QV4IRBuilder::visit(AST::UnaryPlusExpression *ast)
+{
+ ExprResult expr = expression(ast->expression);
+ if (expr.isNot(IR::InvalidType)) {
+ if (expr.code->asConst() != 0) {
+ _expr = expr;
+ return false;
+ }
+
+ IR::Expr *code = _block->UNOP(IR::OpUPlus, expr);
+ _expr.code = _block->TEMP(code->type);
+ _block->MOVE(_expr, code);
+ }
+
+ return false;
+}
+
+bool QV4IRBuilder::visit(AST::UnaryMinusExpression *ast)
+{
+ ExprResult expr = expression(ast->expression);
+ if (expr.isNot(IR::InvalidType)) {
+ if (IR::Const *c = expr.code->asConst()) {
+ _expr = expr;
+ _expr.code = _block->CONST(-c->value);
+ return false;
+ }
+
+ IR::Expr *code = _block->UNOP(IR::OpUMinus, expr);
+ _expr.code = _block->TEMP(code->type);
+ _block->MOVE(_expr, code);
+ }
+
+ return false;
+}
+
+bool QV4IRBuilder::visit(AST::TildeExpression *ast)
+{
+ ExprResult expr = expression(ast->expression);
+ if (expr.isNot(IR::InvalidType)) {
+ if (IR::Const *c = expr.code->asConst()) {
+ _expr = expr;
+ _expr.code = _block->CONST(~int(c->value));
+ return false;
+ }
+ IR::Expr *code = _block->UNOP(IR::OpCompl, expr);
+ _expr.code = _block->TEMP(code->type);
+ _block->MOVE(_expr, code);
+ }
+
+ return false;
+}
+
+bool QV4IRBuilder::visit(AST::NotExpression *ast)
+{
+ ExprResult expr = expression(ast->expression);
+
+ if (expr.isNot(IR::InvalidType)) {
+ if (IR::Const *c = expr.code->asConst()) {
+ _expr = expr;
+ _expr.code = _block->CONST(!c->value);
+ return false;
+ }
+
+ IR::Expr *code = _block->UNOP(IR::OpNot, expr);
+ _expr.code = _block->TEMP(code->type);
+ _block->MOVE(_expr, code);
+
+ } else if (expr.hint == ExprResult::cx) {
+ expr.format = ExprResult::cx;
+ _block->CJUMP(_block->UNOP(IR::OpNot, expr), _expr.iftrue, _expr.iffalse);
+ return false;
+ }
+
+ return false;
+}
+
+void QV4IRBuilder::binop(AST::BinaryExpression *ast, ExprResult left, ExprResult right)
+{
+ if (IR::Type t = maxType(left.type(), right.type())) {
+ implicitCvt(left, t);
+ implicitCvt(right, t);
+
+ if (_expr.hint == ExprResult::cx) {
+ _expr.format = ExprResult::cx;
+ _block->CJUMP(_block->BINOP(IR::binaryOperator(ast->op), left, right), _expr.iftrue, _expr.iffalse);
+ } else {
+ IR::Expr *code = _block->BINOP(IR::binaryOperator(ast->op), left, right);
+ _expr.code = _block->TEMP(code->type);
+ _block->MOVE(_expr.code, code);
+ }
+ }
+}
+
+bool QV4IRBuilder::visit(AST::BinaryExpression *ast)
+{
+ switch (ast->op) {
+ case QSOperator::And: {
+ if (_expr.hint == ExprResult::cx) {
+ _expr.format = ExprResult::cx;
+
+ Q_ASSERT(_expr.iffalse != 0);
+ Q_ASSERT(_expr.iftrue != 0);
+
+ IR::BasicBlock *iftrue = _function->newBasicBlock();
+ condition(ast->left, iftrue, _expr.iffalse);
+
+ _block = iftrue;
+ condition(ast->right, _expr.iftrue, _expr.iffalse);
+ } else {
+ IR::BasicBlock *iftrue = _function->newBasicBlock();
+ IR::BasicBlock *iffalse = _function->newBasicBlock();
+ IR::BasicBlock *endif = _function->newBasicBlock();
+
+ condition(ast->left, iftrue, iffalse);
+
+ IR::Temp *r = _block->TEMP(IR::InvalidType);
+
+ _block = iffalse;
+ _block->MOVE(r, _block->CONST(0)); // ### use the right null value
+ _block->JUMP(endif);
+
+ _block = iftrue;
+ ExprResult right = expression(ast->right);
+ _block->MOVE(r, right);
+ _block->JUMP(endif);
+
+ _block = endif;
+
+ r->type = right.type(); // ### not exactly, it can be IR::BoolType.
+ _expr.code = r;
+ }
+ } break;
+
+ case QSOperator::Or: {
+ IR::BasicBlock *iftrue = _function->newBasicBlock();
+ IR::BasicBlock *endif = _function->newBasicBlock();
+
+ ExprResult left = expression(ast->left);
+ IR::Temp *r = _block->TEMP(left.type());
+ _block->MOVE(r, left);
+
+ IR::Expr *cond = r;
+ if (r->type != IR::BoolType) {
+ cond = _block->TEMP(IR::BoolType);
+ _block->MOVE(cond, r);
+ }
+
+ _block->CJUMP(_block->UNOP(IR::OpNot, cond), iftrue, endif);
+
+ _block = iftrue;
+ ExprResult right = expression(ast->right);
+ _block->MOVE(r, right);
+ _block->JUMP(endif);
+
+ if (left.type() != right.type())
+ discard();
+
+ _expr.code = r;
+
+ _block = endif;
+ } break;
+
+ case QSOperator::Lt:
+ case QSOperator::Gt:
+ case QSOperator::Le:
+ case QSOperator::Ge: {
+ ExprResult left = expression(ast->left);
+ ExprResult right = expression(ast->right);
+ if (left.type() == IR::StringType && right.type() == IR::StringType) {
+ binop(ast, left, right);
+ } else if (left.isValid() && right.isValid()) {
+ implicitCvt(left, IR::RealType);
+ implicitCvt(right, IR::RealType);
+ binop(ast, left, right);
+ }
+ } break;
+
+ case QSOperator::NotEqual:
+ case QSOperator::Equal: {
+ ExprResult left = expression(ast->left);
+ ExprResult right = expression(ast->right);
+ if ((left.type() == IR::NullType || left.type() == IR::UndefinedType) &&
+ (right.type() == IR::NullType || right.type() == IR::UndefinedType)) {
+ const bool isEq = ast->op == QSOperator::Equal;
+ if (_expr.hint == ExprResult::cx) {
+ _expr.format = ExprResult::cx;
+ _block->JUMP(isEq ? _expr.iftrue : _expr.iffalse);
+ } else {
+ _expr.code = _block->CONST(IR::BoolType, isEq ? 1 : 0);
+ }
+ } else if ((left.type() == IR::StringType && right.type() >= IR::FirstNumberType) ||
+ (left.type() >= IR::FirstNumberType && right.type() == IR::StringType)) {
+ implicitCvt(left, IR::RealType);
+ implicitCvt(right, IR::RealType);
+ binop(ast, left, right);
+ } else if (left.type() == IR::BoolType || right.type() == IR::BoolType) {
+ implicitCvt(left, IR::BoolType);
+ implicitCvt(right, IR::BoolType);
+ } else if (left.isValid() && right.isValid()) {
+ binop(ast, left, right);
+ }
+ } break;
+
+ case QSOperator::StrictEqual:
+ case QSOperator::StrictNotEqual: {
+ ExprResult left = expression(ast->left);
+ ExprResult right = expression(ast->right);
+ if (left.type() == right.type()) {
+ binop(ast, left, right);
+ } else if (left.type() >= IR::BoolType && right.type() >= IR::BoolType) {
+ // left and right have numeric type (int or real)
+ binop(ast, left, right);
+ } else if (left.isValid() && right.isValid()) {
+ const bool isEq = ast->op == QSOperator::StrictEqual;
+ if (_expr.hint == ExprResult::cx) {
+ _expr.format = ExprResult::cx;
+ _block->JUMP(isEq ? _expr.iftrue : _expr.iffalse);
+ } else {
+ _expr.code = _block->CONST(IR::BoolType, isEq ? 1 : 0);
+ }
+ }
+ } break;
+
+ case QSOperator::BitAnd:
+ case QSOperator::BitOr:
+ case QSOperator::BitXor:
+ case QSOperator::LShift:
+ case QSOperator::RShift:
+ case QSOperator::URShift: {
+ ExprResult left = expression(ast->left);
+ if (left.is(IR::InvalidType))
+ return false;
+
+ ExprResult right = expression(ast->right);
+ if (right.is(IR::InvalidType))
+ return false;
+
+ implicitCvt(left, IR::IntType);
+ implicitCvt(right, IR::IntType);
+
+ IR::Expr *code = _block->BINOP(IR::binaryOperator(ast->op), left, right);
+ _expr.code = _block->TEMP(code->type);
+ _block->MOVE(_expr.code, code);
+
+ } break;
+
+ case QSOperator::Add: {
+ ExprResult left = expression(ast->left);
+ if (left.is(IR::InvalidType))
+ return false;
+
+ ExprResult right = expression(ast->right);
+ if (right.is(IR::InvalidType))
+ return false;
+
+ if (left.isPrimitive() && right.isPrimitive()) {
+ if (left.type() == IR::StringType || right.type() == IR::StringType) {
+ implicitCvt(left, IR::StringType);
+ implicitCvt(right, IR::StringType);
+ }
+ binop(ast, left, right);
+ }
+ } break;
+
+ case QSOperator::Div:
+ case QSOperator::Mod:
+ case QSOperator::Mul:
+ case QSOperator::Sub: {
+ ExprResult left = expression(ast->left);
+ if (left.is(IR::InvalidType))
+ return false;
+
+ ExprResult right = expression(ast->right);
+ if (right.is(IR::InvalidType))
+ return false;
+
+ IR::Type t = maxType(left.type(), right.type());
+ if (t >= IR::FirstNumberType) {
+ implicitCvt(left, IR::RealType);
+ implicitCvt(right, IR::RealType);
+
+ IR::Expr *code = _block->BINOP(IR::binaryOperator(ast->op), left, right);
+ _expr.code = _block->TEMP(code->type);
+ _block->MOVE(_expr.code, code);
+ }
+ } break;
+
+ case QSOperator::In:
+ case QSOperator::InstanceOf:
+ case QSOperator::Assign:
+ case QSOperator::InplaceAnd:
+ case QSOperator::InplaceSub:
+ case QSOperator::InplaceDiv:
+ case QSOperator::InplaceAdd:
+ case QSOperator::InplaceLeftShift:
+ case QSOperator::InplaceMod:
+ case QSOperator::InplaceMul:
+ case QSOperator::InplaceOr:
+ case QSOperator::InplaceRightShift:
+ case QSOperator::InplaceURightShift:
+ case QSOperator::InplaceXor:
+ // yup, we don't do those.
+ break;
+ } // switch
+
+ return false;
+}
+
+bool QV4IRBuilder::visit(AST::ConditionalExpression *ast)
+{
+ IR::BasicBlock *iftrue = _function->newBasicBlock();
+ IR::BasicBlock *iffalse = _function->newBasicBlock();
+ IR::BasicBlock *endif = _function->newBasicBlock();
+
+ condition(ast->expression, iftrue, iffalse);
+
+ IR::Temp *r = _block->TEMP(IR::InvalidType);
+
+ qSwap(_block, iftrue);
+ ExprResult ok = expression(ast->ok);
+ _block->MOVE(r, ok);
+ _block->JUMP(endif);
+ qSwap(_block, iftrue);
+
+ qSwap(_block, iffalse);
+ ExprResult ko = expression(ast->ko);
+ _block->MOVE(r, ko);
+ _block->JUMP(endif);
+ qSwap(_block, iffalse);
+
+ r->type = maxType(ok.type(), ko.type());
+ _expr.code = r;
+
+ _block = endif;
+
+ return false;
+}
+
+bool QV4IRBuilder::visit(AST::Expression *ast)
+{
+ _block->EXP(expression(ast->left));
+ _expr = expression(ast->right);
+
+ return false;
+}
+
+
+// statements
+bool QV4IRBuilder::visit(AST::Block *ast)
+{
+ if (ast->statements && ! ast->statements->next) {
+ // we have one and only one statement
+ accept(ast->statements->statement);
+ }
+
+ return false;
+}
+
+bool QV4IRBuilder::visit(AST::StatementList *)
+{
+ return false;
+}
+
+bool QV4IRBuilder::visit(AST::VariableStatement *)
+{
+ return false;
+}
+
+bool QV4IRBuilder::visit(AST::VariableDeclarationList *)
+{
+ return false;
+}
+
+bool QV4IRBuilder::visit(AST::VariableDeclaration *)
+{
+ return false;
+}
+
+bool QV4IRBuilder::visit(AST::EmptyStatement *)
+{
+ return false;
+}
+
+bool QV4IRBuilder::visit(AST::ExpressionStatement *ast)
+{
+ if (ast->expression) {
+ // return the value of this expression
+ return true;
+ }
+
+ return false;
+}
+
+bool QV4IRBuilder::visit(AST::IfStatement *ast)
+{
+ if (! ast->ko) {
+ // This is an if statement without an else branch.
+ discard();
+ } else {
+ IR::BasicBlock *iftrue = _function->newBasicBlock();
+ IR::BasicBlock *iffalse = _function->newBasicBlock();
+ IR::BasicBlock *endif = _function->newBasicBlock();
+
+ condition(ast->expression, iftrue, iffalse);
+
+ IR::Temp *r = _block->TEMP(IR::InvalidType);
+
+ qSwap(_block, iftrue);
+ ExprResult ok = statement(ast->ok);
+ _block->MOVE(r, ok);
+ _block->JUMP(endif);
+ qSwap(_block, iftrue);
+
+ qSwap(_block, iffalse);
+ ExprResult ko = statement(ast->ko);
+ _block->MOVE(r, ko);
+ _block->JUMP(endif);
+ qSwap(_block, iffalse);
+
+ r->type = maxType(ok.type(), ko.type());
+ _expr.code = r;
+
+ _block = endif;
+ }
+
+ return false;
+}
+
+bool QV4IRBuilder::visit(AST::DoWhileStatement *)
+{
+ return false;
+}
+
+bool QV4IRBuilder::visit(AST::WhileStatement *)
+{
+ return false;
+}
+
+bool QV4IRBuilder::visit(AST::ForStatement *)
+{
+ return false;
+}
+
+bool QV4IRBuilder::visit(AST::LocalForStatement *)
+{
+ return false;
+}
+
+bool QV4IRBuilder::visit(AST::ForEachStatement *)
+{
+ return false;
+}
+
+bool QV4IRBuilder::visit(AST::LocalForEachStatement *)
+{
+ discard();
+ return false;
+}
+
+bool QV4IRBuilder::visit(AST::ContinueStatement *)
+{
+ return false;
+}
+
+bool QV4IRBuilder::visit(AST::BreakStatement *)
+{
+ return false;
+}
+
+bool QV4IRBuilder::visit(AST::ReturnStatement *ast)
+{
+ if (ast->expression) {
+ // return the value of the expression
+ return true;
+ }
+
+ return false;
+}
+
+bool QV4IRBuilder::visit(AST::WithStatement *)
+{
+ return false;
+}
+
+bool QV4IRBuilder::visit(AST::SwitchStatement *)
+{
+ return false;
+}
+
+bool QV4IRBuilder::visit(AST::CaseBlock *)
+{
+ return false;
+}
+
+bool QV4IRBuilder::visit(AST::CaseClauses *)
+{
+ return false;
+}
+
+bool QV4IRBuilder::visit(AST::CaseClause *)
+{
+ return false;
+}
+
+bool QV4IRBuilder::visit(AST::DefaultClause *)
+{
+ return false;
+}
+
+bool QV4IRBuilder::visit(AST::LabelledStatement *)
+{
+ return false;
+}
+
+bool QV4IRBuilder::visit(AST::ThrowStatement *)
+{
+ return false;
+}
+
+bool QV4IRBuilder::visit(AST::TryStatement *)
+{
+ return false;
+}
+
+bool QV4IRBuilder::visit(AST::Catch *)
+{
+ return false;
+}
+
+bool QV4IRBuilder::visit(AST::Finally *)
+{
+ return false;
+}
+
+bool QV4IRBuilder::visit(AST::FunctionDeclaration *)
+{
+ return false;
+}
+
+bool QV4IRBuilder::visit(AST::FunctionExpression *)
+{
+ return false;
+}
+
+bool QV4IRBuilder::visit(AST::FormalParameterList *)
+{
+ return false;
+}
+
+bool QV4IRBuilder::visit(AST::FunctionBody *)
+{
+ return false;
+}
+
+bool QV4IRBuilder::visit(AST::DebuggerStatement *)
+{
+ return false;
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/v4/qv4irbuilder_p.h b/src/qml/qml/v4/qv4irbuilder_p.h
new file mode 100644
index 0000000000..2b338c0778
--- /dev/null
+++ b/src/qml/qml/v4/qv4irbuilder_p.h
@@ -0,0 +1,240 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QV4IRBUILDER_P_H
+#define QV4IRBUILDER_P_H
+
+#include <QtCore/qglobal.h>
+
+#include "qv4ir_p.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class QV4IRBuilder : public QQmlJS::AST::Visitor
+{
+public:
+ QV4IRBuilder(const QV4Compiler::Expression *, QQmlEnginePrivate *);
+
+ bool operator()(QQmlJS::IR::Function *, QQmlJS::AST::Node *);
+
+protected:
+ struct ExprResult {
+ enum Format {
+ ex, // expression
+ cx // condition
+ };
+
+ QQmlJS::IR::Expr *code;
+ QQmlJS::IR::BasicBlock *iftrue;
+ QQmlJS::IR::BasicBlock *iffalse;
+ Format hint; // requested format
+ Format format; // instruction format
+
+ ExprResult(QQmlJS::IR::Expr *expr = 0)
+ : code(expr), iftrue(0), iffalse(0), hint(ex), format(ex) {}
+
+ ExprResult(QQmlJS::IR::BasicBlock *iftrue, QQmlJS::IR::BasicBlock *iffalse)
+ : code(0), iftrue(iftrue), iffalse(iffalse), hint(cx), format(ex) {}
+
+ inline QQmlJS::IR::Type type() const { return code ? code->type : QQmlJS::IR::InvalidType; }
+
+ inline QQmlJS::IR::Expr *get() const { return code; }
+ inline operator QQmlJS::IR::Expr *() const { return get(); }
+ inline QQmlJS::IR::Expr *operator->() const { return get(); }
+ inline bool isValid() const { return code ? code->type != QQmlJS::IR::InvalidType : false; }
+ inline bool is(QQmlJS::IR::Type t) const { return type() == t; }
+ inline bool isNot(QQmlJS::IR::Type t) const { return type() != t; }
+
+ bool isPrimitive() const {
+ switch (type()) {
+ case QQmlJS::IR::UndefinedType: // ### TODO
+ case QQmlJS::IR::NullType: // ### TODO
+ case QQmlJS::IR::UrlType: // ### TODO
+ return false;
+
+ case QQmlJS::IR::StringType:
+ case QQmlJS::IR::BoolType:
+ case QQmlJS::IR::IntType:
+ case QQmlJS::IR::RealType:
+ case QQmlJS::IR::RealNaNType:
+ return true;
+
+ default:
+ return false;
+ } // switch
+ }
+ };
+
+ inline void accept(QQmlJS::AST::Node *ast) { QQmlJS::AST::Node::accept(ast, this); }
+
+ ExprResult expression(QQmlJS::AST::ExpressionNode *ast);
+ ExprResult statement(QQmlJS::AST::Statement *ast);
+ void sourceElement(QQmlJS::AST::SourceElement *ast);
+ void condition(QQmlJS::AST::ExpressionNode *ast, QQmlJS::IR::BasicBlock *iftrue, QQmlJS::IR::BasicBlock *iffalse);
+ void binop(QQmlJS::AST::BinaryExpression *ast, ExprResult left, ExprResult right);
+
+ void implicitCvt(ExprResult &expr, QQmlJS::IR::Type type);
+
+ virtual bool preVisit(QQmlJS::AST::Node *ast);
+
+ // QML
+ virtual bool visit(QQmlJS::AST::UiProgram *ast);
+ virtual bool visit(QQmlJS::AST::UiImportList *ast);
+ virtual bool visit(QQmlJS::AST::UiImport *ast);
+ virtual bool visit(QQmlJS::AST::UiPublicMember *ast);
+ virtual bool visit(QQmlJS::AST::UiSourceElement *ast);
+ virtual bool visit(QQmlJS::AST::UiObjectDefinition *ast);
+ virtual bool visit(QQmlJS::AST::UiObjectInitializer *ast);
+ virtual bool visit(QQmlJS::AST::UiObjectBinding *ast);
+ virtual bool visit(QQmlJS::AST::UiScriptBinding *ast);
+ virtual bool visit(QQmlJS::AST::UiArrayBinding *ast);
+ virtual bool visit(QQmlJS::AST::UiObjectMemberList *ast);
+ virtual bool visit(QQmlJS::AST::UiArrayMemberList *ast);
+ virtual bool visit(QQmlJS::AST::UiQualifiedId *ast);
+
+ // JS
+ virtual bool visit(QQmlJS::AST::Program *ast);
+ virtual bool visit(QQmlJS::AST::SourceElements *ast);
+ virtual bool visit(QQmlJS::AST::FunctionSourceElement *ast);
+ virtual bool visit(QQmlJS::AST::StatementSourceElement *ast);
+
+ // object literals
+ virtual bool visit(QQmlJS::AST::PropertyNameAndValueList *ast);
+ virtual bool visit(QQmlJS::AST::IdentifierPropertyName *ast);
+ virtual bool visit(QQmlJS::AST::StringLiteralPropertyName *ast);
+ virtual bool visit(QQmlJS::AST::NumericLiteralPropertyName *ast);
+
+ // array literals
+ virtual bool visit(QQmlJS::AST::ElementList *ast);
+ virtual bool visit(QQmlJS::AST::Elision *ast);
+
+ // function calls
+ virtual bool visit(QQmlJS::AST::ArgumentList *ast);
+
+ // expressions
+ virtual bool visit(QQmlJS::AST::ObjectLiteral *ast);
+ virtual bool visit(QQmlJS::AST::ArrayLiteral *ast);
+ virtual bool visit(QQmlJS::AST::ThisExpression *ast);
+ virtual bool visit(QQmlJS::AST::IdentifierExpression *ast);
+ virtual bool visit(QQmlJS::AST::NullExpression *ast);
+ virtual bool visit(QQmlJS::AST::TrueLiteral *ast);
+ virtual bool visit(QQmlJS::AST::FalseLiteral *ast);
+ virtual bool visit(QQmlJS::AST::StringLiteral *ast);
+ virtual bool visit(QQmlJS::AST::NumericLiteral *ast);
+ virtual bool visit(QQmlJS::AST::RegExpLiteral *ast);
+ virtual bool visit(QQmlJS::AST::NestedExpression *ast);
+ virtual bool visit(QQmlJS::AST::ArrayMemberExpression *ast);
+ virtual bool visit(QQmlJS::AST::FieldMemberExpression *ast);
+ virtual bool visit(QQmlJS::AST::NewMemberExpression *ast);
+ virtual bool visit(QQmlJS::AST::NewExpression *ast);
+ virtual bool visit(QQmlJS::AST::CallExpression *ast);
+ virtual bool visit(QQmlJS::AST::PostIncrementExpression *ast);
+ virtual bool visit(QQmlJS::AST::PostDecrementExpression *ast);
+ virtual bool visit(QQmlJS::AST::DeleteExpression *ast);
+ virtual bool visit(QQmlJS::AST::VoidExpression *ast);
+ virtual bool visit(QQmlJS::AST::TypeOfExpression *ast);
+ virtual bool visit(QQmlJS::AST::PreIncrementExpression *ast);
+ virtual bool visit(QQmlJS::AST::PreDecrementExpression *ast);
+ virtual bool visit(QQmlJS::AST::UnaryPlusExpression *ast);
+ virtual bool visit(QQmlJS::AST::UnaryMinusExpression *ast);
+ virtual bool visit(QQmlJS::AST::TildeExpression *ast);
+ virtual bool visit(QQmlJS::AST::NotExpression *ast);
+ virtual bool visit(QQmlJS::AST::BinaryExpression *ast);
+ virtual bool visit(QQmlJS::AST::ConditionalExpression *ast);
+ virtual bool visit(QQmlJS::AST::Expression *ast);
+
+ // statements
+ virtual bool visit(QQmlJS::AST::Block *ast);
+ virtual bool visit(QQmlJS::AST::StatementList *ast);
+ virtual bool visit(QQmlJS::AST::VariableStatement *ast);
+ virtual bool visit(QQmlJS::AST::VariableDeclarationList *ast);
+ virtual bool visit(QQmlJS::AST::VariableDeclaration *ast);
+ virtual bool visit(QQmlJS::AST::EmptyStatement *ast);
+ virtual bool visit(QQmlJS::AST::ExpressionStatement *ast);
+ virtual bool visit(QQmlJS::AST::IfStatement *ast);
+ virtual bool visit(QQmlJS::AST::DoWhileStatement *ast);
+ virtual bool visit(QQmlJS::AST::WhileStatement *ast);
+ virtual bool visit(QQmlJS::AST::ForStatement *ast);
+ virtual bool visit(QQmlJS::AST::LocalForStatement *ast);
+ virtual bool visit(QQmlJS::AST::ForEachStatement *ast);
+ virtual bool visit(QQmlJS::AST::LocalForEachStatement *ast);
+ virtual bool visit(QQmlJS::AST::ContinueStatement *ast);
+ virtual bool visit(QQmlJS::AST::BreakStatement *ast);
+ virtual bool visit(QQmlJS::AST::ReturnStatement *ast);
+ virtual bool visit(QQmlJS::AST::WithStatement *ast);
+ virtual bool visit(QQmlJS::AST::SwitchStatement *ast);
+ virtual bool visit(QQmlJS::AST::CaseBlock *ast);
+ virtual bool visit(QQmlJS::AST::CaseClauses *ast);
+ virtual bool visit(QQmlJS::AST::CaseClause *ast);
+ virtual bool visit(QQmlJS::AST::DefaultClause *ast);
+ virtual bool visit(QQmlJS::AST::LabelledStatement *ast);
+ virtual bool visit(QQmlJS::AST::ThrowStatement *ast);
+ virtual bool visit(QQmlJS::AST::TryStatement *ast);
+ virtual bool visit(QQmlJS::AST::Catch *ast);
+ virtual bool visit(QQmlJS::AST::Finally *ast);
+ virtual bool visit(QQmlJS::AST::FunctionDeclaration *ast);
+ virtual bool visit(QQmlJS::AST::FunctionExpression *ast);
+ virtual bool visit(QQmlJS::AST::FormalParameterList *ast);
+ virtual bool visit(QQmlJS::AST::FunctionBody *ast);
+ virtual bool visit(QQmlJS::AST::DebuggerStatement *ast);
+
+private:
+ bool buildName(QList<QStringRef> &name, QQmlJS::AST::Node *node,
+ QList<QQmlJS::AST::ExpressionNode *> *nodes);
+ void discard();
+
+ const QV4Compiler::Expression *m_expression;
+ QQmlEnginePrivate *m_engine;
+
+ QQmlJS::IR::Function *_function;
+ QQmlJS::IR::BasicBlock *_block;
+ bool _discard;
+
+ ExprResult _expr;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QV4IRBUILDER_P_H
diff --git a/src/qml/qml/v4/qv4program_p.h b/src/qml/qml/v4/qv4program_p.h
new file mode 100644
index 0000000000..b6b03e438b
--- /dev/null
+++ b/src/qml/qml/v4/qv4program_p.h
@@ -0,0 +1,122 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QV4PROGRAM_P_H
+#define QV4PROGRAM_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 "qv4instruction_p.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+struct QV4Program {
+ quint32 bindings;
+ quint32 dataLength;
+ quint32 signalTableOffset;
+ quint32 exceptionDataOffset;
+ quint16 subscriptions;
+ quint16 identifiers;
+ quint16 instructionCount;
+
+ struct BindingReference {
+ quint32 binding;
+ quint32 blockMask;
+ };
+
+ struct BindingReferenceList {
+ quint32 count;
+ BindingReference bindings[];
+ };
+
+ inline const char *data() const;
+ inline const char *instructions() const;
+ inline BindingReferenceList *signalTable(int signalIndex) const;
+};
+
+enum QQmlRegisterType {
+ UndefinedType,
+ QObjectStarType,
+ QRealType,
+ IntType,
+ BoolType,
+
+ PODValueType,
+
+ FirstCleanupType,
+ QStringType = FirstCleanupType,
+ QUrlType,
+ QVariantType,
+};
+
+const char *QV4Program::data() const
+{
+ return ((const char *)this) + sizeof(QV4Program);
+}
+
+const char *QV4Program::instructions() const
+{
+ return (const char *)(data() + dataLength);
+}
+
+QV4Program::BindingReferenceList *QV4Program::signalTable(int signalIndex) const
+{
+ quint32 *signalTable = (quint32 *)(data() + signalTableOffset);
+ return (BindingReferenceList *)(signalTable + signalTable[signalIndex]);
+}
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QV4PROGRAM_P_H
+
diff --git a/src/qml/qml/v4/v4.pri b/src/qml/qml/v4/v4.pri
new file mode 100644
index 0000000000..b6784851d8
--- /dev/null
+++ b/src/qml/qml/v4/v4.pri
@@ -0,0 +1,15 @@
+HEADERS += \
+ $$PWD/qv4compiler_p.h \
+ $$PWD/qv4compiler_p_p.h \
+ $$PWD/qv4ir_p.h \
+ $$PWD/qv4irbuilder_p.h \
+ $$PWD/qv4instruction_p.h \
+ $$PWD/qv4bindings_p.h \
+ $$PWD/qv4program_p.h \
+
+SOURCES += \
+ $$PWD/qv4compiler.cpp \
+ $$PWD/qv4ir.cpp \
+ $$PWD/qv4irbuilder.cpp \
+ $$PWD/qv4instruction.cpp \
+ $$PWD/qv4bindings.cpp \
diff --git a/src/qml/qml/v8/notes.txt b/src/qml/qml/v8/notes.txt
new file mode 100644
index 0000000000..a4006b93c6
--- /dev/null
+++ b/src/qml/qml/v8/notes.txt
@@ -0,0 +1,4 @@
+Removed backwards compatible imports - QTBUG-17518
+
+autotest print() taking objects that don't ToString()
+autotest QQmlV8Function
diff --git a/src/qml/qml/v8/qjsconverter_impl_p.h b/src/qml/qml/v8/qjsconverter_impl_p.h
new file mode 100644
index 0000000000..10b8ab5fae
--- /dev/null
+++ b/src/qml/qml/v8/qjsconverter_impl_p.h
@@ -0,0 +1,268 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qjsconverter_p.h"
+
+#ifndef QJSCONVERTER_IMPL_P_H
+#define QJSCONVERTER_IMPL_P_H
+
+QT_BEGIN_NAMESPACE
+
+extern char *qdtoa(double d, int mode, int ndigits, int *decpt, int *sign, char **rve, char **digits_str);
+Q_CORE_EXPORT QString qt_regexp_toCanonical(const QString &, QRegExp::PatternSyntax);
+
+
+quint32 QJSConverter::toArrayIndex(const QString& string)
+{
+ // FIXME this function should be exported by JSC C API.
+ bool ok;
+ quint32 idx = string.toUInt(&ok);
+ if (!ok || toString(idx) != string)
+ idx = 0xffffffff;
+
+ return idx;
+}
+
+QString QJSConverter::toString(v8::Handle<v8::String> jsString)
+{
+ if (jsString.IsEmpty())
+ return QString();
+ QString qstr;
+ qstr.resize(jsString->Length());
+ jsString->Write(reinterpret_cast<uint16_t*>(qstr.data()));
+ return qstr;
+}
+
+v8::Local<v8::String> QJSConverter::toString(const QString& string)
+{
+ return v8::String::New(reinterpret_cast<const uint16_t*>(string.data()), string.size());
+}
+
+QString QJSConverter::toString(double value)
+{
+ // FIXME this should be easier. The ideal fix is to create
+ // a new function in V8 API which could cover the functionality.
+
+ if (qIsNaN(value))
+ return QString::fromLatin1("NaN");
+ if (qIsInf(value))
+ return QString::fromLatin1(value < 0 ? "-Infinity" : "Infinity");
+ if (!value)
+ return QString::fromLatin1("0");
+
+ QVarLengthArray<char, 25> buf;
+ int decpt;
+ int sign;
+ char* result = 0;
+ char* endresult;
+ (void)qdtoa(value, 0, 0, &decpt, &sign, &endresult, &result);
+
+ if (!result)
+ return QString();
+
+ int resultLen = endresult - result;
+ if (decpt <= 0 && decpt > -6) {
+ buf.resize(-decpt + 2 + sign);
+ qMemSet(buf.data(), '0', -decpt + 2 + sign);
+ if (sign) // fix the sign.
+ buf[0] = '-';
+ buf[sign + 1] = '.';
+ buf.append(result, resultLen);
+ } else {
+ if (sign)
+ buf.append('-');
+ int length = buf.size() - sign + resultLen;
+ if (decpt <= 21 && decpt > 0) {
+ if (length <= decpt) {
+ const char* zeros = "0000000000000000000000000";
+ buf.append(result, resultLen);
+ buf.append(zeros, decpt - length);
+ } else {
+ buf.append(result, decpt);
+ buf.append('.');
+ buf.append(result + decpt, resultLen - decpt);
+ }
+ } else if (result[0] >= '0' && result[0] <= '9') {
+ if (length > 1) {
+ buf.append(result, 1);
+ buf.append('.');
+ buf.append(result + 1, resultLen - 1);
+ } else
+ buf.append(result, resultLen);
+ buf.append('e');
+ buf.append(decpt >= 0 ? '+' : '-');
+ int e = qAbs(decpt - 1);
+ if (e >= 100)
+ buf.append('0' + e / 100);
+ if (e >= 10)
+ buf.append('0' + (e % 100) / 10);
+ buf.append('0' + e % 10);
+ }
+ }
+ free(result);
+ buf.append(0);
+ return QString::fromLatin1(buf.constData());
+}
+
+// return a mask of v8::PropertyAttribute that may also contains QScriptValue::PropertyGetter or QScriptValue::PropertySetter
+uint QJSConverter::toPropertyAttributes(const QFlags<QJSValuePrivate::PropertyFlag>& flags)
+{
+ uint attr = 0;
+ if (flags.testFlag(QJSValuePrivate::ReadOnly))
+ attr |= v8::ReadOnly;
+ if (flags.testFlag(QJSValuePrivate::Undeletable))
+ attr |= v8::DontDelete;
+ if (flags.testFlag(QJSValuePrivate::SkipInEnumeration))
+ attr |= v8::DontEnum;
+ // if (flags.testFlag(QScriptValue::PropertyGetter))
+ // attr |= QScriptValue::PropertyGetter;
+ // if (flags.testFlag(QScriptValue::PropertySetter))
+ // attr |= QScriptValue::PropertySetter;
+ return attr;
+}
+
+// Converts a JS RegExp to a QRegExp.
+// The conversion is not 100% exact since ECMA regexp and QRegExp
+// have different semantics/flags, but we try to do our best.
+QRegExp QJSConverter::toRegExp(v8::Handle<v8::RegExp> jsRegExp)
+{
+ QString pattern = QJSConverter::toString(jsRegExp->GetSource());
+ Qt::CaseSensitivity caseSensitivity = Qt::CaseSensitive;
+ if (jsRegExp->GetFlags() & v8::RegExp::kIgnoreCase)
+ caseSensitivity = Qt::CaseInsensitive;
+ return QRegExp(pattern, caseSensitivity, QRegExp::RegExp2);
+}
+
+// Converts a QRegExp to a JS RegExp.
+// The conversion is not 100% exact since ECMA regexp and QRegExp
+// have different semantics/flags, but we try to do our best.
+v8::Local<v8::RegExp> QJSConverter::toRegExp(const QRegExp &re)
+{
+ // Convert the pattern to a ECMAScript pattern.
+ QString pattern = qt_regexp_toCanonical(re.pattern(), re.patternSyntax());
+ if (re.isMinimal()) {
+ QString ecmaPattern;
+ int len = pattern.length();
+ ecmaPattern.reserve(len);
+ int i = 0;
+ const QChar *wc = pattern.unicode();
+ bool inBracket = false;
+ while (i < len) {
+ QChar c = wc[i++];
+ ecmaPattern += c;
+ switch (c.unicode()) {
+ case '?':
+ case '+':
+ case '*':
+ case '}':
+ if (!inBracket)
+ ecmaPattern += QLatin1Char('?');
+ break;
+ case '\\':
+ if (i < len)
+ ecmaPattern += wc[i++];
+ break;
+ case '[':
+ inBracket = true;
+ break;
+ case ']':
+ inBracket = false;
+ break;
+ default:
+ break;
+ }
+ }
+ pattern = ecmaPattern;
+ }
+
+ int flags = v8::RegExp::kNone;
+ if (re.caseSensitivity() == Qt::CaseInsensitive)
+ flags |= v8::RegExp::kIgnoreCase;
+
+ return v8::RegExp::New(QJSConverter::toString(pattern), static_cast<v8::RegExp::Flags>(flags));
+}
+
+// Converts a QStringList to JS.
+// The result is a new Array object with length equal to the length
+// of the QStringList, and the elements being the QStringList's
+// elements converted to JS Strings.
+v8::Local<v8::Array> QJSConverter::toStringList(const QStringList &lst)
+{
+ v8::Local<v8::Array> result = v8::Array::New(lst.size());
+ for (int i = 0; i < lst.size(); ++i)
+ result->Set(i, toString(lst.at(i)));
+ return result;
+}
+
+// Converts a JS Array object to a QStringList.
+// The result is a QStringList with length equal to the length
+// of the JS Array, and elements being the JS Array's elements
+// converted to QStrings.
+QStringList QJSConverter::toStringList(v8::Handle<v8::Array> jsArray)
+{
+ QStringList result;
+ uint32_t length = jsArray->Length();
+ for (uint32_t i = 0; i < length; ++i)
+ result.append(toString(jsArray->Get(i)->ToString()));
+ return result;
+}
+
+
+// Converts a JS Date to a QDateTime.
+QDateTime QJSConverter::toDateTime(v8::Handle<v8::Date> jsDate)
+{
+ return QDateTime::fromMSecsSinceEpoch(jsDate->NumberValue());
+}
+
+// Converts a QDateTime to a JS Date.
+v8::Local<v8::Value> QJSConverter::toDateTime(const QDateTime &dt)
+{
+ double date;
+ if (!dt.isValid())
+ date = qSNaN();
+ else
+ date = dt.toMSecsSinceEpoch();
+ return v8::Date::New(date);
+}
+
+QT_END_NAMESPACE
+
+#endif // QJSCONVERTER_IMPL_P_H
diff --git a/src/qml/qml/v8/qjsconverter_p.h b/src/qml/qml/v8/qjsconverter_p.h
new file mode 100644
index 0000000000..29fef3c700
--- /dev/null
+++ b/src/qml/qml/v8/qjsconverter_p.h
@@ -0,0 +1,93 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtScript module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL-ONLY$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** If you have questions regarding the use of this file, please contact
+** us via http://www.qt-project.org/.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QJSCONVERTER_P_H
+#define QJSCONVERTER_P_H
+
+#include "qjsvalue_p.h"
+#include <QtCore/qglobal.h>
+#include <QtCore/qnumeric.h>
+#include <QtCore/qstring.h>
+#include <QtCore/qstringlist.h>
+#include <QtCore/qvarlengtharray.h>
+#include <QtCore/qregexp.h>
+#include <QtCore/qdatetime.h>
+
+#include <private/qv8_p.h>
+
+QT_BEGIN_NAMESPACE
+
+/*
+ \internal
+ \class QJSConverter
+ QJSValue and QJSEngine helper class. This class's responsibility is to convert values
+ between JS values and Qt/C++ values.
+
+ This is a nice way to inline these functions in both QJSValue and QJSEngine.
+*/
+class QJSConverter {
+public:
+ static inline quint32 toArrayIndex(const QString& string);
+
+ static inline QString toString(v8::Handle<v8::String> jsString);
+ static inline v8::Local<v8::String> toString(const QString& string);
+ static inline QString toString(double value);
+
+ enum {
+ PropertyAttributeMask = v8::ReadOnly | v8::DontDelete | v8::DontEnum,
+ };
+ // return a mask of v8::PropertyAttribute that may also contains QScriptValue::PropertyGetter or QScriptValue::PropertySetter
+ static inline uint toPropertyAttributes(const QFlags<QJSValuePrivate::PropertyFlag>& flags);
+
+ // Converts a JS RegExp to a QRegExp.
+ // The conversion is not 100% exact since ECMA regexp and QRegExp
+ // have different semantics/flags, but we try to do our best.
+ static inline QRegExp toRegExp(v8::Handle<v8::RegExp> jsRegExp);
+
+ // Converts a QRegExp to a JS RegExp.
+ // The conversion is not 100% exact since ECMA regexp and QRegExp
+ // have different semantics/flags, but we try to do our best.
+ static inline v8::Local<v8::RegExp> toRegExp(const QRegExp &re);
+
+ // Converts a QStringList to JS.
+ // The result is a new Array object with length equal to the length
+ // of the QStringList, and the elements being the QStringList's
+ // elements converted to JS Strings.
+ static inline v8::Local<v8::Array> toStringList(const QStringList &lst);
+
+ // Converts a JS Array object to a QStringList.
+ // The result is a QStringList with length equal to the length
+ // of the JS Array, and elements being the JS Array's elements
+ // converted to QStrings.
+ static inline QStringList toStringList(v8::Handle<v8::Array> jsArray);
+
+ // Converts a JS Date to a QDateTime.
+ static inline QDateTime toDateTime(v8::Handle<v8::Date> jsDate);
+
+ // Converts a QDateTime to a JS Date.
+ static inline v8::Local<v8::Value> toDateTime(const QDateTime &dt);
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/qml/qml/v8/qjsengine.cpp b/src/qml/qml/v8/qjsengine.cpp
new file mode 100644
index 0000000000..3121d1b361
--- /dev/null
+++ b/src/qml/qml/v8/qjsengine.cpp
@@ -0,0 +1,476 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtScript module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL-ONLY$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** If you have questions regarding the use of this file, please contact
+** us via http://www.qt-project.org/.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qjsengine.h"
+#include "qjsengine_p.h"
+#include "qjsvalue.h"
+#include "qjsvalue_p.h"
+#include "qscriptisolate_p.h"
+#include "qscript_impl_p.h"
+#include "qv8engine_p.h"
+
+#include <QtCore/qdatetime.h>
+#include <QtCore/qmetaobject.h>
+#include <QtCore/qstringlist.h>
+#include <QtCore/qvariant.h>
+#include <QtCore/qdatetime.h>
+
+#include <QtCore/qcoreapplication.h>
+#include <QtCore/qdir.h>
+#include <QtCore/qfile.h>
+#include <QtCore/qfileinfo.h>
+#include <QtCore/qpluginloader.h>
+#include <qthread.h>
+#include <qmutex.h>
+#include <qwaitcondition.h>
+
+#undef Q_D
+#undef Q_Q
+#define Q_D(blah)
+#define Q_Q(blah)
+
+Q_DECLARE_METATYPE(QJSValue)
+Q_DECLARE_METATYPE(QObjectList)
+Q_DECLARE_METATYPE(QList<int>)
+
+/*!
+ \since 5.0
+ \class QJSEngine
+
+ \brief The QJSEngine class provides an environment for evaluating JavaScript code.
+
+ \ingroup qtjavascript
+ \mainclass
+
+ \section1 Evaluating Scripts
+
+ Use evaluate() to evaluate script code.
+
+ \snippet doc/src/snippets/code/src_script_qjsengine.cpp 0
+
+ evaluate() returns a QJSValue that holds the result of the
+ evaluation. The QJSValue class provides functions for converting
+ the result to various C++ types (e.g. QJSValue::toString()
+ and QJSValue::toNumber()).
+
+ The following code snippet shows how a script function can be
+ defined and then invoked from C++ using QJSValue::call():
+
+ \snippet doc/src/snippets/code/src_script_qjsengine.cpp 1
+
+ As can be seen from the above snippets, a script is provided to the
+ engine in the form of a string. One common way of loading scripts is
+ by reading the contents of a file and passing it to evaluate():
+
+ \snippet doc/src/snippets/code/src_script_qjsengine.cpp 2
+
+ Here we pass the name of the file as the second argument to
+ evaluate(). This does not affect evaluation in any way; the second
+ argument is a general-purpose string that is used to identify the
+ script for debugging purposes (for example, our filename will now
+ show up in any uncaughtExceptionBacktrace() involving the script).
+
+ \section1 Engine Configuration
+
+ The globalObject() function returns the \bold {Global Object}
+ associated with the script engine. Properties of the Global Object
+ are accessible from any script code (i.e. they are global
+ variables). Typically, before evaluating "user" scripts, you will
+ want to configure a script engine by adding one or more properties
+ to the Global Object:
+
+ \snippet doc/src/snippets/code/src_script_qjsengine.cpp 3
+
+ Adding custom properties to the scripting environment is one of the
+ standard means of providing a scripting API that is specific to your
+ application. Usually these custom properties are objects created by
+ the newQObject() or newObject() functions.
+
+ \section1 Script Exceptions
+
+ evaluate() can throw a script exception (e.g. due to a syntax
+ error); in that case, the return value is the value that was thrown
+ (typically an \c{Error} object). You can check whether the
+ evaluation caused an exception by calling hasUncaughtException(). In
+ that case, you can call toString() on the error object to obtain an
+ error message. The current uncaught exception is also available
+ through uncaughtException().
+ Calling clearExceptions() will cause any uncaught exceptions to be
+ cleared.
+
+ \snippet doc/src/snippets/code/src_script_qjsengine.cpp 4
+
+ \section1 Script Object Creation
+
+ Use newObject() to create a JavaScript object; this is the
+ C++ equivalent of the script statement \c{new Object()}. You can use
+ the object-specific functionality in QJSValue to manipulate the
+ script object (e.g. QJSValue::setProperty()). Similarly, use
+ newArray() to create a JavaScript array object.
+
+ \section1 QObject Integration
+
+ Use newQObject() to wrap a QObject (or subclass)
+ pointer. newQObject() returns a proxy script object; properties,
+ children, and signals and slots of the QObject are available as
+ properties of the proxy object. No binding code is needed because it
+ is done dynamically using the Qt meta object system.
+
+ \snippet doc/src/snippets/code/src_script_qjsengine.cpp 5
+
+ \sa QJSValue, {Making Applications Scriptable}
+
+*/
+
+QT_BEGIN_NAMESPACE
+
+
+/*!
+ Constructs a QJSEngine object.
+
+ The globalObject() is initialized to have properties as described in
+ \l{ECMA-262}, Section 15.1.
+*/
+QJSEngine::QJSEngine()
+ : d(new QV8Engine(this))
+{
+}
+
+#ifdef QT_DEPRECATED
+
+/*!
+ \internal
+*/
+QJSEngine::QJSEngine(QJSEngine::ContextOwnership ownership)
+ : d(new QV8Engine(this, ownership))
+{
+}
+
+#endif // QT_DEPRECATED
+
+/*!
+ Constructs a QJSEngine object with the given \a parent.
+
+ The globalObject() is initialized to have properties as described in
+ \l{ECMA-262}, Section 15.1.
+*/
+
+QJSEngine::QJSEngine(QObject *parent)
+ : QObject(parent)
+ , d(new QV8Engine(this))
+{
+}
+
+QJSEngine::QJSEngine(QJSEnginePrivate &dd, QObject *parent)
+ : QObject(dd, parent)
+ , d(new QV8Engine(this))
+{
+}
+
+/*!
+ Destroys this QJSEngine.
+*/
+QJSEngine::~QJSEngine()
+{
+ delete d;
+}
+
+/*!
+ \fn QV8Engine *QJSEngine::handle() const
+ \internal
+*/
+
+#ifdef QT_DEPRECATED
+
+/*!
+ \obsolete
+
+ Returns true if the last script evaluation resulted in an uncaught
+ exception; otherwise returns false.
+
+ The exception state is cleared when evaluate() is called.
+
+ \sa uncaughtException(), uncaughtExceptionLineNumber(),
+ uncaughtExceptionBacktrace()
+*/
+bool QJSEngine::hasUncaughtException() const
+{
+ Q_D(const QJSEngine);
+ QScriptIsolate api(d);
+ return d->hasUncaughtException();
+}
+
+/*!
+ \obsolete
+
+ Returns the current uncaught exception, or an invalid QJSValue
+ if there is no uncaught exception.
+
+ The exception value is typically an \c{Error} object; in that case,
+ you can call toString() on the return value to obtain an error
+ message.
+
+ \sa hasUncaughtException(), uncaughtExceptionLineNumber(),
+ uncaughtExceptionBacktrace()
+*/
+QJSValue QJSEngine::uncaughtException() const
+{
+ Q_D(const QJSEngine);
+ QScriptIsolate api(d);
+ return d->scriptValueFromInternal(d->uncaughtException());
+}
+
+/*!
+ \obsolete
+
+ Clears any uncaught exceptions in this engine.
+
+ \sa hasUncaughtException()
+*/
+void QJSEngine::clearExceptions()
+{
+ Q_D(QJSEngine);
+ QScriptIsolate api(d);
+ d->clearExceptions();
+}
+
+#endif // QT_DEPRECATED
+
+/*!
+ Runs the garbage collector.
+
+ The garbage collector will attempt to reclaim memory by locating and disposing of objects that are
+ no longer reachable in the script environment.
+
+ Normally you don't need to call this function; the garbage collector will automatically be invoked
+ when the QJSEngine decides that it's wise to do so (i.e. when a certain number of new objects
+ have been created). However, you can call this function to explicitly request that garbage
+ collection should be performed as soon as possible.
+
+ \sa reportAdditionalMemoryCost()
+*/
+void QJSEngine::collectGarbage()
+{
+ Q_D(QJSEngine);
+ QScriptIsolate api(d);
+ d->collectGarbage();
+}
+
+/*!
+ Evaluates \a program, using \a lineNumber as the base line number,
+ and returns the result of the evaluation.
+
+ The script code will be evaluated in the current context.
+
+ The evaluation of \a program can cause an exception in the
+ engine; in this case the return value will be the exception
+ that was thrown (typically an \c{Error} object). You can call
+ hasUncaughtException() to determine if an exception occurred in
+ the last call to evaluate().
+
+ \a lineNumber is used to specify a starting line number for \a
+ program; line number information reported by the engine that pertain
+ to this evaluation (e.g. uncaughtExceptionLineNumber()) will be
+ based on this argument. For example, if \a program consists of two
+ lines of code, and the statement on the second line causes a script
+ exception, uncaughtExceptionLineNumber() would return the given \a
+ lineNumber plus one. When no starting line number is specified, line
+ numbers will be 1-based.
+
+ \a fileName is used for error reporting. For example in error objects
+ the file name is accessible through the "fileName" property if it's
+ provided with this function.
+*/
+QJSValue QJSEngine::evaluate(const QString& program, const QString& fileName, int lineNumber)
+{
+ Q_D(QJSEngine);
+ QScriptIsolate api(d, QScriptIsolate::NotNullEngine);
+ v8::HandleScope handleScope;
+ return QJSValuePrivate::get(d->evaluate(program, fileName, lineNumber));
+}
+
+/*!
+ Creates a JavaScript object of class Object.
+
+ The prototype of the created object will be the Object
+ prototype object.
+
+ \sa newArray(), QJSValue::setProperty()
+*/
+QJSValue QJSEngine::newObject()
+{
+ Q_D(QJSEngine);
+ QScriptIsolate api(d, QScriptIsolate::NotNullEngine);
+ v8::HandleScope handleScope;
+ return QJSValuePrivate::get(new QJSValuePrivate(d, v8::Object::New()));
+}
+
+/*!
+ Creates a JavaScript object of class Array with the given \a length.
+
+ \sa newObject()
+*/
+QJSValue QJSEngine::newArray(uint length)
+{
+ Q_D(QJSEngine);
+ QScriptIsolate api(d, QScriptIsolate::NotNullEngine);
+ v8::HandleScope handleScope;
+ return QJSValuePrivate::get(d->newArray(length));
+}
+
+/*!
+ Creates a JavaScript object that wraps the given QObject \a
+ object, using JavaScriptOwnership. The given \a options control
+ various aspects of the interaction with the resulting script object.
+
+ Signals and slots, properties and children of \a object are
+ available as properties of the created QJSValue.
+
+ If \a object is a null pointer, this function returns a null value.
+
+ If a default prototype has been registered for the \a object's class
+ (or its superclass, recursively), the prototype of the new script
+ object will be set to be that default prototype.
+
+ If the given \a object is deleted outside of the engine's control, any
+ attempt to access the deleted QObject's members through the JavaScript
+ wrapper object (either by script code or C++) will result in a
+ script exception.
+
+ \sa QJSValue::toQObject(), reportAdditionalMemoryCost()
+*/
+QJSValue QJSEngine::newQObject(QObject *object)
+{
+ Q_D(QJSEngine);
+ QScriptIsolate api(d, QScriptIsolate::NotNullEngine);
+ v8::HandleScope handleScope;
+ return d->scriptValueFromInternal(d->newQObject(object, QV8Engine::JavaScriptOwnership));
+}
+
+/*!
+ Returns this engine's Global Object.
+
+ By default, the Global Object contains the built-in objects that are
+ part of \l{ECMA-262}, such as Math, Date and String. Additionally,
+ you can set properties of the Global Object to make your own
+ extensions available to all script code. Non-local variables in
+ script code will be created as properties of the Global Object, as
+ well as local variables in global code.
+*/
+QJSValue QJSEngine::globalObject() const
+{
+ Q_D(const QJSEngine);
+ QScriptIsolate api(d, QScriptIsolate::NotNullEngine);
+ v8::HandleScope handleScope;
+ return d->scriptValueFromInternal(d->global());
+}
+
+/*!
+ * \internal
+ * used by QJSEngine::toScriptValue
+ */
+QJSValue QJSEngine::create(int type, const void *ptr)
+{
+ Q_D(QJSEngine);
+ QScriptIsolate api(d, QScriptIsolate::NotNullEngine);
+ v8::HandleScope handleScope;
+ return d->scriptValueFromInternal(d->metaTypeToJS(type, ptr));
+}
+
+/*!
+ \internal
+ \since 4.5
+ convert \a value to \a type, store the result in \a ptr
+*/
+bool QJSEngine::convertV2(const QJSValue &value, int type, void *ptr)
+{
+ QJSValuePrivate *vp = QJSValuePrivate::get(value);
+ QV8Engine *engine = vp->engine();
+ if (engine) {
+ QScriptIsolate api(engine, QScriptIsolate::NotNullEngine);
+ v8::HandleScope handleScope;
+ return engine->metaTypeFromJS(*vp, type, ptr);
+ } else {
+ switch (type) {
+ case QMetaType::Bool:
+ *reinterpret_cast<bool*>(ptr) = vp->toBool();
+ return true;
+ case QMetaType::Int:
+ *reinterpret_cast<int*>(ptr) = vp->toInt32();
+ return true;
+ case QMetaType::UInt:
+ *reinterpret_cast<uint*>(ptr) = vp->toUInt32();
+ return true;
+ case QMetaType::LongLong:
+ *reinterpret_cast<qlonglong*>(ptr) = vp->toInteger();
+ return true;
+ case QMetaType::ULongLong:
+ *reinterpret_cast<qulonglong*>(ptr) = vp->toInteger();
+ return true;
+ case QMetaType::Double:
+ *reinterpret_cast<double*>(ptr) = vp->toNumber();
+ return true;
+ case QMetaType::QString:
+ *reinterpret_cast<QString*>(ptr) = vp->toString();
+ return true;
+ case QMetaType::Float:
+ *reinterpret_cast<float*>(ptr) = vp->toNumber();
+ return true;
+ case QMetaType::Short:
+ *reinterpret_cast<short*>(ptr) = vp->toInt32();
+ return true;
+ case QMetaType::UShort:
+ *reinterpret_cast<unsigned short*>(ptr) = vp->toUInt16();
+ return true;
+ case QMetaType::Char:
+ *reinterpret_cast<char*>(ptr) = vp->toInt32();
+ return true;
+ case QMetaType::UChar:
+ *reinterpret_cast<unsigned char*>(ptr) = vp->toUInt16();
+ return true;
+ case QMetaType::QChar:
+ *reinterpret_cast<QChar*>(ptr) = vp->toUInt16();
+ return true;
+ default:
+ return false;
+ }
+ }
+}
+
+/*! \fn QJSValue QJSEngine::toScriptValue(const T &value)
+
+ Creates a QJSValue with the given \a value.
+
+ \sa fromScriptValue()
+*/
+
+/*! \fn T QJSEngine::fromScriptValue(const QJSValue &value)
+
+ Returns the given \a value converted to the template type \c{T}.
+
+ \sa toScriptValue()
+*/
+
+QT_END_NAMESPACE
+
+#include "moc_qjsengine.cpp"
diff --git a/src/qml/qml/v8/qjsengine.h b/src/qml/qml/v8/qjsengine.h
new file mode 100644
index 0000000000..1521c752d4
--- /dev/null
+++ b/src/qml/qml/v8/qjsengine.h
@@ -0,0 +1,141 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtScript module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL-ONLY$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** If you have questions regarding the use of this file, please contact
+** us via http://www.qt-project.org/.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QJSENGINE_H
+#define QJSENGINE_H
+
+#include <QtCore/qmetatype.h>
+
+#include <QtCore/qvariant.h>
+#include <QtCore/qsharedpointer.h>
+#include <QtCore/qobject.h>
+#include <QtQml/qjsvalue.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+
+class QV8Engine;
+
+template <typename T>
+inline T qjsvalue_cast(const QJSValue &);
+
+class QJSEnginePrivate;
+class Q_QML_EXPORT QJSEngine
+ : public QObject
+{
+ Q_OBJECT
+public:
+#ifdef QT_DEPRECATED
+ enum ContextOwnership {
+ AdoptCurrentContext,
+ CreateNewContext
+ };
+ QT_DEPRECATED explicit QJSEngine(ContextOwnership ownership);
+#endif
+
+ QJSEngine();
+ explicit QJSEngine(QObject *parent);
+ virtual ~QJSEngine();
+
+ QJSValue globalObject() const;
+
+ QJSValue evaluate(const QString &program, const QString &fileName = QString(), int lineNumber = 1);
+
+ QJSValue newObject();
+ QJSValue newArray(uint length = 0);
+
+ QJSValue newQObject(QObject *object);
+
+ template <typename T>
+ inline QJSValue toScriptValue(const T &value)
+ {
+ return create(qMetaTypeId<T>(), &value);
+ }
+ template <typename T>
+ inline T fromScriptValue(const QJSValue &value)
+ {
+ return qjsvalue_cast<T>(value);
+ }
+
+ void collectGarbage();
+
+ QV8Engine *handle() const { return d; }
+
+#ifdef QT_DEPRECATED
+ QT_DEPRECATED bool hasUncaughtException() const;
+ QT_DEPRECATED QJSValue uncaughtException() const;
+ QT_DEPRECATED void clearExceptions();
+#endif
+
+Q_SIGNALS:
+ void signalHandlerException(const QJSValue &exception);
+
+private:
+ QJSValue create(int type, const void *ptr);
+
+ static bool convertV2(const QJSValue &value, int type, void *ptr);
+
+ friend inline bool qjsvalue_cast_helper(const QJSValue &, int, void *);
+
+protected:
+ QJSEngine(QJSEnginePrivate &dd, QObject *parent = 0);
+
+private:
+ QV8Engine *d;
+ Q_DISABLE_COPY(QJSEngine)
+ Q_DECLARE_PRIVATE(QJSEngine)
+ friend class QV8Engine;
+};
+
+inline bool qjsvalue_cast_helper(const QJSValue &value, int type, void *ptr)
+{
+ return QJSEngine::convertV2(value, type, ptr);
+}
+
+template<typename T>
+T qjsvalue_cast(const QJSValue &value)
+{
+ T t;
+ const int id = qMetaTypeId<T>();
+
+ if (qjsvalue_cast_helper(value, id, &t))
+ return t;
+ else if (value.isVariant())
+ return qvariant_cast<T>(value.toVariant());
+
+ return T();
+}
+
+template <>
+inline QVariant qjsvalue_cast<QVariant>(const QJSValue &value)
+{
+ return value.toVariant();
+}
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QJSENGINE_H
diff --git a/src/qml/qml/v8/qjsengine_p.h b/src/qml/qml/v8/qjsengine_p.h
new file mode 100644
index 0000000000..ecd5f7cc86
--- /dev/null
+++ b/src/qml/qml/v8/qjsengine_p.h
@@ -0,0 +1,57 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtScript module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL-ONLY$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** If you have questions regarding the use of this file, please contact
+** us via http://www.qt-project.org/.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QJSENGINE_P_H
+#define QJSENGINE_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/private/qobject_p.h>
+#include "qjsengine.h"
+
+
+QT_BEGIN_NAMESPACE
+
+
+class QJSEnginePrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QJSEngine)
+
+public:
+ static QJSEnginePrivate* get(QJSEngine*e) { return e->d_func(); }
+
+ QJSEnginePrivate() {}
+};
+
+QT_END_NAMESPACE
+
+#endif // QJSENGINE_P_H
diff --git a/src/qml/qml/v8/qjsvalue.cpp b/src/qml/qml/v8/qjsvalue.cpp
new file mode 100644
index 0000000000..e0a925c3bb
--- /dev/null
+++ b/src/qml/qml/v8/qjsvalue.cpp
@@ -0,0 +1,856 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtScript module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL-ONLY$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** If you have questions regarding the use of this file, please contact
+** us via http://www.qt-project.org/.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qscriptisolate_p.h"
+#include "qjsengine.h"
+#include "qv8engine_p.h"
+#include "qjsvalue.h"
+#include "qjsvalue_p.h"
+#include "qscript_impl_p.h"
+#include "qscriptshareddata_p.h"
+#include <QtCore/qstring.h>
+
+/*!
+ \since 5.0
+ \class QJSValue
+
+ \brief The QJSValue class acts as a container for Qt/JavaScript data types.
+
+ \ingroup qtjavascript
+ \mainclass
+
+ QJSValue supports the types defined in the \l{ECMA-262}
+ standard: The primitive types, which are Undefined, Null, Boolean,
+ Number, and String; and the Object type. Additionally, built-in
+ support is provided for Qt/C++ types such as QVariant and QObject.
+
+ For the object-based types (including Date and RegExp), use the
+ newT() functions in QJSEngine (e.g. QJSEngine::newObject())
+ to create a QJSValue of the desired type. For the primitive types,
+ use one of the QJSValue constructor overloads.
+
+ The methods named isT() (e.g. isBool(), isUndefined()) can be
+ used to test if a value is of a certain type. The methods named
+ toT() (e.g. toBool(), toString()) can be used to convert a
+ QJSValue to another type. You can also use the generic
+ QJSValue_cast() function.
+
+ Object values have zero or more properties which are themselves
+ QJSValues. Use setProperty() to set a property of an object, and
+ call property() to retrieve the value of a property.
+
+ \snippet doc/src/snippets/code/src_script_qjsvalue.cpp 0
+
+ If you want to iterate over the properties of a script object, use
+ the QJSValueIterator class.
+
+ Object values have an internal \c{prototype} property, which can be
+ accessed with prototype() and setPrototype().
+
+ Function objects (objects for which isCallable()) returns true) can
+ be invoked by calling call(). Constructor functions can be used to
+ construct new objects by calling callAsConstructor().
+
+ Use equals() or strictlyEquals() to compare a QJSValue to another.
+
+ Note that a QJSValue for which isObject() is true only carries a
+ reference to an actual object; copying the QJSValue will only
+ copy the object reference, not the object itself. If you want to
+ clone an object (i.e. copy an object's properties to another
+ object), you can do so with the help of a \c{for-in} statement in
+ script code, or QJSValueIterator in C++.
+
+ \sa QJSEngine, QJSValueIterator
+*/
+
+/*!
+ \enum QJSValue::SpecialValue
+
+ This enum is used to specify a single-valued type.
+
+ \value UndefinedValue An undefined value.
+
+ \value NullValue A null value.
+*/
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ Constructs a new QJSValue with a boolean \a value.
+*/
+QJSValue::QJSValue(bool value)
+ : d_ptr(new QJSValuePrivate(value))
+{
+}
+
+/*!
+ Constructs a new QJSValue with a number \a value.
+*/
+QJSValue::QJSValue(int value)
+ : d_ptr(new QJSValuePrivate(value))
+{
+}
+
+/*!
+ Constructs a new QJSValue with a number \a value.
+*/
+QJSValue::QJSValue(uint value)
+ : d_ptr(new QJSValuePrivate(value))
+{
+}
+
+/*!
+ Constructs a new QJSValue with a number \a value.
+*/
+QJSValue::QJSValue(double value)
+ : d_ptr(new QJSValuePrivate(value))
+{
+}
+
+/*!
+ Constructs a new QJSValue with a string \a value.
+*/
+QJSValue::QJSValue(const QString& value)
+ : d_ptr(new QJSValuePrivate(value))
+{
+}
+
+/*!
+ Constructs a new QJSValue with a special \a value.
+*/
+QJSValue::QJSValue(SpecialValue value)
+ : d_ptr(new QJSValuePrivate(value))
+{
+}
+
+/*!
+ Constructs a new QJSValue with a string \a value.
+*/
+QJSValue::QJSValue(const QLatin1String &value)
+ : d_ptr(new QJSValuePrivate(value))
+{
+}
+
+/*!
+ Constructs a new QJSValue with a string \a value.
+*/
+#ifndef QT_NO_CAST_FROM_ASCII
+QJSValue::QJSValue(const char *value)
+ : d_ptr(new QJSValuePrivate(QString::fromAscii(value)))
+{
+}
+#endif
+
+/*!
+ Constructs a new QJSValue from private
+ \internal
+*/
+QJSValue::QJSValue(QJSValuePrivate* d)
+ : d_ptr(d)
+{
+}
+
+/*!
+ Constructs a new QJSValue from private
+ \internal
+*/
+QJSValue::QJSValue(QScriptPassPointer<QJSValuePrivate> d)
+ : d_ptr(d.give())
+{
+}
+
+/*!
+ Constructs a new QJSValue that is a copy of \a other.
+
+ Note that if \a other is an object (i.e., isObject() would return
+ true), then only a reference to the underlying object is copied into
+ the new script value (i.e., the object itself is not copied).
+*/
+QJSValue::QJSValue(const QJSValue& other)
+ : d_ptr(other.d_ptr)
+{
+}
+
+/*!
+ Destroys this QJSValue.
+*/
+QJSValue::~QJSValue()
+{
+}
+
+/*!
+ Returns true if this QJSValue is of the primitive type Boolean;
+ otherwise returns false.
+
+ \sa toBool()
+*/
+bool QJSValue::isBool() const
+{
+ Q_D(const QJSValue);
+ QScriptIsolate api(d->engine());
+ return d->isBool();
+}
+
+/*!
+ Returns true if this QJSValue is of the primitive type Number;
+ otherwise returns false.
+
+ \sa toNumber()
+*/
+bool QJSValue::isNumber() const
+{
+ Q_D(const QJSValue);
+ QScriptIsolate api(d->engine());
+ return d->isNumber();
+}
+
+/*!
+ Returns true if this QJSValue is of the primitive type Null;
+ otherwise returns false.
+*/
+bool QJSValue::isNull() const
+{
+ Q_D(const QJSValue);
+ QScriptIsolate api(d->engine());
+ return d->isNull();
+}
+
+/*!
+ Returns true if this QJSValue is of the primitive type String;
+ otherwise returns false.
+
+ \sa toString()
+*/
+bool QJSValue::isString() const
+{
+ Q_D(const QJSValue);
+ QScriptIsolate api(d->engine());
+ return d->isString();
+}
+
+/*!
+ Returns true if this QJSValue is of the primitive type Undefined;
+ otherwise returns false.
+*/
+bool QJSValue::isUndefined() const
+{
+ Q_D(const QJSValue);
+ QScriptIsolate api(d->engine());
+ return d->isUndefined();
+}
+
+/*!
+ Returns true if this QJSValue is an object of the Error class;
+ otherwise returns false.
+*/
+bool QJSValue::isError() const
+{
+ Q_D(const QJSValue);
+ QScriptIsolate api(d->engine());
+ return d->isError();
+}
+
+/*!
+ Returns true if this QJSValue is an object of the Array class;
+ otherwise returns false.
+
+ \sa QJSEngine::newArray()
+*/
+bool QJSValue::isArray() const
+{
+ Q_D(const QJSValue);
+ QScriptIsolate api(d->engine());
+ return d->isArray();
+ }
+
+/*!
+ Returns true if this QJSValue is of the Object type; otherwise
+ returns false.
+
+ Note that function values, variant values, and QObject values are
+ objects, so this function returns true for such values.
+
+ \sa QJSEngine::newObject()
+*/
+bool QJSValue::isObject() const
+{
+ Q_D(const QJSValue);
+ QScriptIsolate api(d->engine());
+ return d->isObject();
+}
+
+/*!
+ Returns true if this QJSValue can be called a function, otherwise
+ returns false.
+
+ \sa call()
+*/
+bool QJSValue::isCallable() const
+{
+ Q_D(const QJSValue);
+ QScriptIsolate api(d->engine());
+ return d->isCallable();
+}
+
+/*!
+ Returns true if this QJSValue is a variant value;
+ otherwise returns false.
+
+ \sa toVariant()
+*/
+bool QJSValue::isVariant() const
+{
+ Q_D(const QJSValue);
+ QScriptIsolate api(d->engine());
+ return d->isVariant();
+}
+
+/*!
+ Returns the string value of this QJSValue, as defined in
+ \l{ECMA-262} section 9.8, "ToString".
+
+ Note that if this QJSValue is an object, calling this function
+ has side effects on the script engine, since the engine will call
+ the object's toString() function (and possibly valueOf()) in an
+ attempt to convert the object to a primitive value (possibly
+ resulting in an uncaught script exception).
+
+ \sa isString()
+*/
+QString QJSValue::toString() const
+{
+ Q_D(const QJSValue);
+ QScriptIsolate api(d->engine());
+ return d->toString();
+}
+
+/*!
+ Returns the number value of this QJSValue, as defined in
+ \l{ECMA-262} section 9.3, "ToNumber".
+
+ Note that if this QJSValue is an object, calling this function
+ has side effects on the script engine, since the engine will call
+ the object's valueOf() function (and possibly toString()) in an
+ attempt to convert the object to a primitive value (possibly
+ resulting in an uncaught script exception).
+
+ \sa isNumber(), toInt(), toUInt()
+*/
+double QJSValue::toNumber() const
+{
+ Q_D(const QJSValue);
+ QScriptIsolate api(d->engine());
+ return d->toNumber();
+}
+
+/*!
+ Returns the boolean value of this QJSValue, using the conversion
+ rules described in \l{ECMA-262} section 9.2, "ToBoolean".
+
+ Note that if this QJSValue is an object, calling this function
+ has side effects on the script engine, since the engine will call
+ the object's valueOf() function (and possibly toString()) in an
+ attempt to convert the object to a primitive value (possibly
+ resulting in an uncaught script exception).
+
+ \sa isBool()
+*/
+bool QJSValue::toBool() const
+{
+ Q_D(const QJSValue);
+ QScriptIsolate api(d->engine());
+ return d->toBool();
+}
+
+/*!
+ Returns the signed 32-bit integer value of this QJSValue, using
+ the conversion rules described in \l{ECMA-262} section 9.5, "ToInt32".
+
+ Note that if this QJSValue is an object, calling this function
+ has side effects on the script engine, since the engine will call
+ the object's valueOf() function (and possibly toString()) in an
+ attempt to convert the object to a primitive value (possibly
+ resulting in an uncaught script exception).
+
+ \sa toNumber(), toUInt()
+*/
+qint32 QJSValue::toInt() const
+{
+ Q_D(const QJSValue);
+ QScriptIsolate api(d->engine());
+ return d->toInt32();
+}
+
+/*!
+ Returns the unsigned 32-bit integer value of this QJSValue, using
+ the conversion rules described in \l{ECMA-262} section 9.6, "ToUint32".
+
+ Note that if this QJSValue is an object, calling this function
+ has side effects on the script engine, since the engine will call
+ the object's valueOf() function (and possibly toString()) in an
+ attempt to convert the object to a primitive value (possibly
+ resulting in an uncaught script exception).
+
+ \sa toNumber(), toInt()
+*/
+quint32 QJSValue::toUInt() const
+{
+ Q_D(const QJSValue);
+ QScriptIsolate api(d->engine());
+ return d->toUInt32();
+}
+
+/*!
+ Returns the QVariant value of this QJSValue, if it can be
+ converted to a QVariant; otherwise returns an invalid QVariant.
+ The conversion is performed according to the following table:
+
+ \table
+ \header \o Input Type \o Result
+ \row \o Undefined \o An invalid QVariant.
+ \row \o Null \o An invalid QVariant.
+ \row \o Boolean \o A QVariant containing the value of the boolean.
+ \row \o Number \o A QVariant containing the value of the number.
+ \row \o String \o A QVariant containing the value of the string.
+ \row \o QVariant Object \o The result is the QVariant value of the object (no conversion).
+ \row \o QObject Object \o A QVariant containing a pointer to the QObject.
+ \row \o Date Object \o A QVariant containing the date value (toDateTime()).
+ \row \o RegExp Object \o A QVariant containing the regular expression value.
+ \row \o Array Object \o The array is converted to a QVariantList. Each element is converted to a QVariant, recursively; cyclic references are not followed.
+ \row \o Object \o The object is converted to a QVariantMap. Each property is converted to a QVariant, recursively; cyclic references are not followed.
+ \endtable
+
+ \sa isVariant()
+*/
+QVariant QJSValue::toVariant() const
+{
+ Q_D(const QJSValue);
+ QScriptIsolate api(d->engine());
+ return d->toVariant();
+}
+
+/*!
+ Calls this QJSValue as a function, passing \a args as arguments
+ to the function, and using the globalObject() as the "this"-object.
+ Returns the value returned from the function.
+
+ If this QJSValue is not callable, call() does nothing and
+ returns an undefined QJSValue.
+
+ Calling call() can cause an exception to occur in the script engine;
+ in that case, call() returns the value that was thrown (typically an
+ \c{Error} object). You can call
+ QJSEngine::hasUncaughtException() to determine if an exception
+ occurred.
+
+ \sa isCallable(), callWithInstance(), callAsConstructor()
+*/
+QJSValue QJSValue::call(const QJSValueList &args)
+{
+ Q_D(QJSValue);
+ QScriptIsolate api(d->engine());
+ return d->call(/*thisObject=*/0, args);
+}
+
+/*!
+ Calls this QJSValue as a function, using \a instance as
+ the `this' object in the function call, and passing \a args
+ as arguments to the function. Returns the value returned from
+ the function.
+
+ If this QJSValue is not a function, call() does nothing
+ and returns an undefined QJSValue.
+
+ Note that if \a instance is not an object, the global object
+ (see \l{QJSEngine::globalObject()}) will be used as the
+ `this' object.
+
+ Calling call() can cause an exception to occur in the script engine;
+ in that case, call() returns the value that was thrown (typically an
+ \c{Error} object). You can call
+ QJSEngine::hasUncaughtException() to determine if an exception
+ occurred.
+
+ \sa call()
+*/
+QJSValue QJSValue::callWithInstance(const QJSValue &instance, const QJSValueList &args)
+{
+ Q_D(QJSValue);
+ QScriptIsolate api(d->engine());
+ return d->call(QJSValuePrivate::get(instance), args);
+}
+
+/*!
+ Creates a new \c{Object} and calls this QJSValue as a
+ constructor, using the created object as the `this' object and
+ passing \a args as arguments. If the return value from the
+ constructor call is an object, then that object is returned;
+ otherwise the default constructed object is returned.
+
+ If this QJSValue is not a function, callAsConstructor() does
+ nothing and returns an undefined QJSValue.
+
+ Calling this function can cause an exception to occur in the
+ script engine; in that case, the value that was thrown
+ (typically an \c{Error} object) is returned. You can call
+ QJSEngine::hasUncaughtException() to determine if an exception
+ occurred.
+
+ \sa call(), QJSEngine::newObject()
+*/
+QJSValue QJSValue::callAsConstructor(const QJSValueList &args)
+{
+ Q_D(QJSValue);
+ QScriptIsolate api(d->engine());
+ return QJSValuePrivate::get(d->callAsConstructor(args));
+}
+
+#ifdef QT_DEPRECATED
+
+/*!
+ \obsolete
+
+ Returns the QJSEngine that created this QJSValue,
+ or 0 if this QJSValue is invalid or the value is not
+ associated with a particular engine.
+*/
+QJSEngine* QJSValue::engine() const
+{
+ Q_D(const QJSValue);
+ QScriptIsolate api(d->engine());
+ QV8Engine* engine = d->engine();
+ if (engine)
+ return QV8Engine::get(engine);
+ return 0;
+}
+
+#endif // QT_DEPRECATED
+
+/*!
+ If this QJSValue is an object, returns the internal prototype
+ (\c{__proto__} property) of this object; otherwise returns an
+ undefined QJSValue.
+
+ \sa setPrototype(), isObject()
+*/
+QJSValue QJSValue::prototype() const
+{
+ Q_D(const QJSValue);
+ QScriptIsolate api(d->engine());
+ return QJSValuePrivate::get(d->prototype());
+}
+
+/*!
+ If this QJSValue is an object, sets the internal prototype
+ (\c{__proto__} property) of this object to be \a prototype;
+ otherwise does nothing.
+
+ The internal prototype should not be confused with the public
+ property with name "prototype"; the public prototype is usually
+ only set on functions that act as constructors.
+
+ \sa prototype(), isObject()
+*/
+void QJSValue::setPrototype(const QJSValue& prototype)
+{
+ Q_D(QJSValue);
+ QScriptIsolate api(d->engine());
+ d->setPrototype(QJSValuePrivate::get(prototype));
+}
+
+/*!
+ Assigns the \a other value to this QJSValue.
+
+ Note that if \a other is an object (isObject() returns true),
+ only a reference to the underlying object will be assigned;
+ the object itself will not be copied.
+*/
+QJSValue& QJSValue::operator=(const QJSValue& other)
+{
+ d_ptr = other.d_ptr;
+ return *this;
+}
+
+/*!
+ Returns true if this QJSValue is equal to \a other, otherwise
+ returns false. The comparison follows the behavior described in
+ \l{ECMA-262} section 11.9.3, "The Abstract Equality Comparison
+ Algorithm".
+
+ This function can return true even if the type of this QJSValue
+ is different from the type of the \a other value; i.e. the
+ comparison is not strict. For example, comparing the number 9 to
+ the string "9" returns true; comparing an undefined value to a null
+ value returns true; comparing a \c{Number} object whose primitive
+ value is 6 to a \c{String} object whose primitive value is "6"
+ returns true; and comparing the number 1 to the boolean value
+ \c{true} returns true. If you want to perform a comparison
+ without such implicit value conversion, use strictlyEquals().
+
+ Note that if this QJSValue or the \a other value are objects,
+ calling this function has side effects on the script engine, since
+ the engine will call the object's valueOf() function (and possibly
+ toString()) in an attempt to convert the object to a primitive value
+ (possibly resulting in an uncaught script exception).
+
+ \sa strictlyEquals()
+*/
+bool QJSValue::equals(const QJSValue& other) const
+{
+ Q_D(const QJSValue);
+ QJSValuePrivate* otherValue = QJSValuePrivate::get(other);
+ QScriptIsolate api(d->engine() ? d->engine() : otherValue->engine());
+ return d_ptr->equals(otherValue);
+}
+
+/*!
+ Returns true if this QJSValue is equal to \a other using strict
+ comparison (no conversion), otherwise returns false. The comparison
+ follows the behavior described in \l{ECMA-262} section 11.9.6, "The
+ Strict Equality Comparison Algorithm".
+
+ If the type of this QJSValue is different from the type of the
+ \a other value, this function returns false. If the types are equal,
+ the result depends on the type, as shown in the following table:
+
+ \table
+ \header \o Type \o Result
+ \row \o Undefined \o true
+ \row \o Null \o true
+ \row \o Boolean \o true if both values are true, false otherwise
+ \row \o Number \o false if either value is NaN (Not-a-Number); true if values are equal, false otherwise
+ \row \o String \o true if both values are exactly the same sequence of characters, false otherwise
+ \row \o Object \o true if both values refer to the same object, false otherwise
+ \endtable
+
+ \sa equals()
+*/
+bool QJSValue::strictlyEquals(const QJSValue& other) const
+{
+ Q_D(const QJSValue);
+ QJSValuePrivate* o = QJSValuePrivate::get(other);
+ QScriptIsolate api(d->engine() ? d->engine() : o->engine());
+ return d_ptr->strictlyEquals(o);
+}
+
+/*!
+ Returns the value of this QJSValue's property with the given \a name.
+ If no such property exists, an undefined QJSValue is returned.
+
+ If the property is implemented using a getter function (i.e. has the
+ PropertyGetter flag set), calling property() has side-effects on the
+ script engine, since the getter function will be called (possibly
+ resulting in an uncaught script exception). If an exception
+ occurred, property() returns the value that was thrown (typically
+ an \c{Error} object).
+
+ \sa setProperty(), hasProperty(), QJSValueIterator
+*/
+QJSValue QJSValue::property(const QString& name) const
+{
+ Q_D(const QJSValue);
+ QScriptIsolate api(d->engine());
+ return QJSValuePrivate::get(d->property(name));
+}
+
+/*!
+ \overload
+
+ Returns the property at the given \a arrayIndex.
+
+ This function is provided for convenience and performance when
+ working with array objects.
+
+ If this QJSValue is not an Array object, this function behaves
+ as if property() was called with the string representation of \a
+ arrayIndex.
+*/
+QJSValue QJSValue::property(quint32 arrayIndex) const
+{
+ Q_D(const QJSValue);
+ QScriptIsolate api(d->engine());
+ return QJSValuePrivate::get(d->property(arrayIndex));
+}
+
+/*!
+ Sets the value of this QJSValue's property with the given \a name to
+ the given \a value.
+
+ If this QJSValue is not an object, this function does nothing.
+
+ If this QJSValue does not already have a property with name \a name,
+ a new property is created.
+
+ \sa property(), deleteProperty()
+*/
+void QJSValue::setProperty(const QString& name, const QJSValue& value)
+{
+ Q_D(QJSValue);
+ QScriptIsolate api(d->engine());
+ d->setProperty(name, QJSValuePrivate::get(value));
+}
+
+/*!
+ \overload
+
+ Sets the property at the given \a arrayIndex to the given \a value.
+
+ This function is provided for convenience and performance when
+ working with array objects.
+
+ If this QJSValue is not an Array object, this function behaves
+ as if setProperty() was called with the string representation of \a
+ arrayIndex.
+*/
+void QJSValue::setProperty(quint32 arrayIndex, const QJSValue& value)
+{
+ Q_D(QJSValue);
+ QScriptIsolate api(d->engine());
+ d->setProperty(arrayIndex, QJSValuePrivate::get(value));
+}
+
+/*!
+ Attempts to delete this object's property of the given \a name.
+ Returns true if the property was deleted, otherwise returns false.
+
+ The behavior of this function is consistent with the JavaScript
+ delete operator. In particular:
+
+ \list
+ \o Non-configurable properties cannot be deleted.
+ \o This function will return true even if this object doesn't
+ have a property of the given \a name (i.e., non-existent
+ properties are "trivially deletable").
+ \o If this object doesn't have an own property of the given
+ \a name, but an object in the prototype() chain does, the
+ prototype object's property is not deleted, and this function
+ returns true.
+ \endlist
+
+ \sa setProperty(), hasOwnProperty()
+*/
+bool QJSValue::deleteProperty(const QString &name)
+{
+ Q_D(QJSValue);
+ QScriptIsolate api(d->engine());
+ return d->deleteProperty(name);
+}
+
+/*!
+ Returns true if this object has a property of the given \a name,
+ otherwise returns false.
+
+ \sa property(), hasOwnProperty()
+*/
+bool QJSValue::hasProperty(const QString &name) const
+{
+ Q_D(const QJSValue);
+ QScriptIsolate api(d->engine());
+ return d->hasProperty(name);
+}
+
+/*!
+ Returns true if this object has an own (not prototype-inherited)
+ property of the given \a name, otherwise returns false.
+
+ \sa property(), hasProperty()
+*/
+bool QJSValue::hasOwnProperty(const QString &name) const
+{
+ Q_D(const QJSValue);
+ QScriptIsolate api(d->engine());
+ return d->hasOwnProperty(name);
+}
+
+/*!
+ * If this QJSValue is a QObject, returns the QObject pointer
+ * that the QJSValue represents; otherwise, returns 0.
+ *
+ * If the QObject that this QJSValue wraps has been deleted,
+ * this function returns 0 (i.e. it is possible for toQObject()
+ * to return 0 even when isQObject() returns true).
+ *
+ * \sa isQObject()
+ */
+QObject *QJSValue::toQObject() const
+{
+ Q_D(const QJSValue);
+ QScriptIsolate api(d->engine());
+ return d->toQObject();
+}
+
+/*!
+ Returns a QDateTime representation of this value, in local time.
+ If this QJSValue is not a date, or the value of the date is NaN
+ (Not-a-Number), an invalid QDateTime is returned.
+
+ \sa isDate()
+*/
+QDateTime QJSValue::toDateTime() const
+{
+ Q_D(const QJSValue);
+ QScriptIsolate api(d->engine());
+ return d->toDataTime();
+}
+
+/*!
+ Returns true if this QJSValue is an object of the Date class;
+ otherwise returns false.
+
+ \sa QJSEngine::newDate()
+*/
+bool QJSValue::isDate() const
+{
+ Q_D(const QJSValue);
+ QScriptIsolate api(d->engine());
+ return d->isDate();
+}
+
+/*!
+ Returns true if this QJSValue is an object of the RegExp class;
+ otherwise returns false.
+*/
+bool QJSValue::isRegExp() const
+{
+ Q_D(const QJSValue);
+ QScriptIsolate api(d->engine());
+ return d->isRegExp();
+}
+
+/*!
+ Returns true if this QJSValue is a QObject; otherwise returns
+ false.
+
+ Note: This function returns true even if the QObject that this
+ QJSValue wraps has been deleted.
+
+ \sa toQObject(), QJSEngine::newQObject()
+*/
+bool QJSValue::isQObject() const
+{
+ Q_D(const QJSValue);
+ QScriptIsolate api(d->engine());
+ return d->isQObject();
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/v8/qjsvalue.h b/src/qml/qml/v8/qjsvalue.h
new file mode 100644
index 0000000000..30ea2e7345
--- /dev/null
+++ b/src/qml/qml/v8/qjsvalue.h
@@ -0,0 +1,143 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtScript module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL-ONLY$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** If you have questions regarding the use of this file, please contact
+** us via http://www.qt-project.org/.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QJSVALUE_H
+#define QJSVALUE_H
+
+#include <QtQml/qtqmlglobal.h>
+
+#include <QtCore/qstring.h>
+#include <QtCore/qlist.h>
+#include <QtCore/qsharedpointer.h>
+#include <QtCore/qshareddata.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+
+class QJSValue;
+class QJSEngine;
+class QVariant;
+class QObject;
+struct QMetaObject;
+class QDateTime;
+
+typedef QList<QJSValue> QJSValueList;
+
+class QJSValuePrivate;
+struct QScriptValuePrivatePointerDeleter;
+template <class T> class QScriptPassPointer;
+
+class Q_QML_EXPORT QJSValue
+{
+public:
+ enum SpecialValue {
+ NullValue,
+ UndefinedValue
+ };
+
+public:
+ QJSValue(SpecialValue value = UndefinedValue);
+ ~QJSValue();
+ QJSValue(const QJSValue &other);
+
+ QJSValue(bool value);
+ QJSValue(int value);
+ QJSValue(uint value);
+ QJSValue(double value);
+ QJSValue(const QString &value);
+ QJSValue(const QLatin1String &value);
+#ifndef QT_NO_CAST_FROM_ASCII
+ QT_ASCII_CAST_WARN_CONSTRUCTOR QJSValue(const char *str);
+#endif
+
+ QJSValue &operator=(const QJSValue &other);
+
+ bool isBool() const;
+ bool isNumber() const;
+ bool isNull() const;
+ bool isString() const;
+ bool isUndefined() const;
+ bool isVariant() const;
+ bool isQObject() const;
+ bool isObject() const;
+ bool isDate() const;
+ bool isRegExp() const;
+ bool isArray() const;
+ bool isError() const;
+
+ QString toString() const;
+ double toNumber() const;
+ qint32 toInt() const;
+ quint32 toUInt() const;
+ bool toBool() const;
+ QVariant toVariant() const;
+ QObject *toQObject() const;
+ QDateTime toDateTime() const;
+
+ bool equals(const QJSValue &other) const;
+ bool strictlyEquals(const QJSValue &other) const;
+
+ QJSValue prototype() const;
+ void setPrototype(const QJSValue &prototype);
+
+ QJSValue property(const QString &name) const;
+ void setProperty(const QString &name, const QJSValue &value);
+
+ bool hasProperty(const QString &name) const;
+ bool hasOwnProperty(const QString &name) const;
+
+ QJSValue property(quint32 arrayIndex) const;
+ void setProperty(quint32 arrayIndex, const QJSValue &value);
+
+ bool deleteProperty(const QString &name);
+
+ bool isCallable() const;
+ QJSValue call(const QJSValueList &args = QJSValueList());
+ QJSValue callWithInstance(const QJSValue &instance, const QJSValueList &args = QJSValueList());
+ QJSValue callAsConstructor(const QJSValueList &args = QJSValueList());
+
+#ifdef QT_DEPRECATED
+ QT_DEPRECATED QJSEngine *engine() const;
+#endif
+
+private:
+ // force compile error, prevent QJSValue(bool) to be called
+
+ QJSValue(void *) Q_DECL_EQ_DELETE;
+
+ QJSValue(QJSValuePrivate*);
+ QJSValue(QScriptPassPointer<QJSValuePrivate>);
+
+private:
+ QExplicitlySharedDataPointer<QJSValuePrivate> d_ptr;
+
+ Q_DECLARE_PRIVATE(QJSValue)
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/qml/qml/v8/qjsvalue_impl_p.h b/src/qml/qml/v8/qjsvalue_impl_p.h
new file mode 100644
index 0000000000..cd33859c50
--- /dev/null
+++ b/src/qml/qml/v8/qjsvalue_impl_p.h
@@ -0,0 +1,977 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtScript module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL-ONLY$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** If you have questions regarding the use of this file, please contact
+** us via http://www.qt-project.org/.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// 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.
+//
+
+#ifndef QJSVALUE_IMPL_P_H
+#define QJSVALUE_IMPL_P_H
+
+#include "qjsconverter_p.h"
+#include "qjsvalue_p.h"
+#include "qv8engine_p.h"
+#include "qscriptisolate_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QJSValuePrivate* QJSValuePrivate::get(const QJSValue& q) { Q_ASSERT(q.d_ptr.data()); return q.d_ptr.data(); }
+
+QJSValue QJSValuePrivate::get(const QJSValuePrivate* d)
+{
+ Q_ASSERT(d);
+ return QJSValue(const_cast<QJSValuePrivate*>(d));
+}
+
+QJSValue QJSValuePrivate::get(QScriptPassPointer<QJSValuePrivate> d)
+{
+ Q_ASSERT(d);
+ return QJSValue(d);
+}
+
+QJSValue QJSValuePrivate::get(QJSValuePrivate* d)
+{
+ Q_ASSERT(d);
+ return QJSValue(d);
+}
+
+QJSValuePrivate::QJSValuePrivate(bool value)
+ : m_engine(0), m_state(CBool), u(value)
+{
+}
+
+QJSValuePrivate::QJSValuePrivate(int value)
+ : m_engine(0), m_state(CNumber), u(value)
+{
+}
+
+QJSValuePrivate::QJSValuePrivate(uint value)
+ : m_engine(0), m_state(CNumber), u(value)
+{
+}
+
+QJSValuePrivate::QJSValuePrivate(double value)
+ : m_engine(0), m_state(CNumber), u(value)
+{
+}
+
+QJSValuePrivate::QJSValuePrivate(const QString& value)
+ : m_engine(0), m_state(CString), u(new QString(value))
+{
+}
+
+QJSValuePrivate::QJSValuePrivate(QJSValue::SpecialValue value)
+ : m_engine(0), m_state(value == QJSValue::NullValue ? CNull : CUndefined)
+{
+}
+
+QJSValuePrivate::QJSValuePrivate(QV8Engine* engine, bool value)
+ : m_engine(engine), m_state(JSValue)
+{
+ Q_ASSERT(engine);
+ v8::HandleScope handleScope;
+ m_value = v8::Persistent<v8::Value>::New(m_engine->makeJSValue(value));
+ m_engine->registerValue(this);
+}
+
+QJSValuePrivate::QJSValuePrivate(QV8Engine* engine, int value)
+ : m_engine(engine), m_state(JSValue)
+{
+ Q_ASSERT(engine);
+ v8::HandleScope handleScope;
+ m_value = v8::Persistent<v8::Value>::New(m_engine->makeJSValue(value));
+ m_engine->registerValue(this);
+}
+
+QJSValuePrivate::QJSValuePrivate(QV8Engine* engine, uint value)
+ : m_engine(engine), m_state(JSValue)
+{
+ Q_ASSERT(engine);
+ v8::HandleScope handleScope;
+ m_value = v8::Persistent<v8::Value>::New(m_engine->makeJSValue(value));
+ m_engine->registerValue(this);
+}
+
+QJSValuePrivate::QJSValuePrivate(QV8Engine* engine, double value)
+ : m_engine(engine), m_state(JSValue)
+{
+ Q_ASSERT(engine);
+ v8::HandleScope handleScope;
+ m_value = v8::Persistent<v8::Value>::New(m_engine->makeJSValue(value));
+ m_engine->registerValue(this);
+}
+
+QJSValuePrivate::QJSValuePrivate(QV8Engine* engine, const QString& value)
+ : m_engine(engine), m_state(JSValue)
+{
+ Q_ASSERT(engine);
+ v8::HandleScope handleScope;
+ m_value = v8::Persistent<v8::Value>::New(m_engine->makeJSValue(value));
+ m_engine->registerValue(this);
+}
+
+QJSValuePrivate::QJSValuePrivate(QV8Engine* engine, QJSValue::SpecialValue value)
+ : m_engine(engine), m_state(JSValue)
+{
+ Q_ASSERT(engine);
+ v8::HandleScope handleScope;
+ m_value = v8::Persistent<v8::Value>::New(m_engine->makeJSValue(value));
+ m_engine->registerValue(this);
+}
+
+QJSValuePrivate::QJSValuePrivate(QV8Engine *engine, v8::Handle<v8::Value> value)
+ : m_engine(engine), m_state(JSValue), m_value(v8::Persistent<v8::Value>::New(value))
+{
+ Q_ASSERT(engine);
+ // It shouldn't happen, v8 shows errors by returning an empty handler. This is important debug
+ // information and it can't be simply ignored.
+ Q_ASSERT(!value.IsEmpty());
+ m_engine->registerValue(this);
+}
+
+QJSValuePrivate::~QJSValuePrivate()
+{
+ if (isJSBased()) {
+ m_engine->unregisterValue(this);
+ QScriptIsolate api(m_engine);
+ m_value.Dispose();
+ } else if (isStringBased()) {
+ delete u.m_string;
+ }
+}
+
+bool QJSValuePrivate::toBool() const
+{
+ switch (m_state) {
+ case JSValue:
+ {
+ v8::HandleScope scope;
+ return m_value->ToBoolean()->Value();
+ }
+ case CNumber:
+ return !(qIsNaN(u.m_number) || !u.m_number);
+ case CBool:
+ return u.m_bool;
+ case CNull:
+ case CUndefined:
+ return false;
+ case CString:
+ return u.m_string->length();
+ }
+
+ Q_ASSERT_X(false, "toBool()", "Not all states are included in the previous switch statement.");
+ return false; // Avoid compiler warning.
+}
+
+double QJSValuePrivate::toNumber() const
+{
+ switch (m_state) {
+ case JSValue:
+ {
+ v8::HandleScope scope;
+ return m_value->ToNumber()->Value();
+ }
+ case CNumber:
+ return u.m_number;
+ case CBool:
+ return u.m_bool ? 1 : 0;
+ case CNull:
+ case CUndefined:
+ return qQNaN();
+ case CString:
+ bool ok;
+ double result = u.m_string->toDouble(&ok);
+ if (ok)
+ return result;
+ result = u.m_string->toInt(&ok, 0); // Try other bases.
+ if (ok)
+ return result;
+ if (*u.m_string == QLatin1String("Infinity"))
+ return qInf();
+ if (*u.m_string == QLatin1String("-Infinity"))
+ return -qInf();
+ return u.m_string->length() ? qQNaN() : 0;
+ }
+
+ Q_ASSERT_X(false, "toNumber()", "Not all states are included in the previous switch statement.");
+ return 0; // Avoid compiler warning.
+}
+
+QString QJSValuePrivate::toString() const
+{
+ switch (m_state) {
+ case CBool:
+ return u.m_bool ? QString::fromLatin1("true") : QString::fromLatin1("false");
+ case CString:
+ return *u.m_string;
+ case CNumber:
+ return QJSConverter::toString(u.m_number);
+ case CNull:
+ return QString::fromLatin1("null");
+ case CUndefined:
+ return QString::fromLatin1("undefined");
+ case JSValue:
+ Q_ASSERT(!m_value.IsEmpty());
+ v8::HandleScope handleScope;
+ v8::TryCatch tryCatch;
+ v8::Local<v8::String> result = m_value->ToString();
+ if (result.IsEmpty()) {
+ result = tryCatch.Exception()->ToString();
+ m_engine->setException(tryCatch.Exception(), tryCatch.Message());
+ }
+ return QJSConverter::toString(result);
+ }
+
+ Q_ASSERT_X(false, "toString()", "Not all states are included in the previous switch statement.");
+ return QString(); // Avoid compiler warning.
+}
+
+QVariant QJSValuePrivate::toVariant() const
+{
+ switch (m_state) {
+ case CBool:
+ return QVariant(u.m_bool);
+ case CString:
+ return QVariant(*u.m_string);
+ case CNumber:
+ return QVariant(u.m_number);
+ case CNull:
+ return QVariant();
+ case CUndefined:
+ return QVariant();
+ case JSValue:
+ break;
+ }
+
+ Q_ASSERT(m_state == JSValue);
+ Q_ASSERT(!m_value.IsEmpty());
+ Q_ASSERT(m_engine);
+
+ v8::HandleScope handleScope;
+ return m_engine->variantFromJS(m_value);
+}
+
+inline QDateTime QJSValuePrivate::toDataTime() const
+{
+ if (!isDate())
+ return QDateTime();
+
+ v8::HandleScope handleScope;
+ return QJSConverter::toDateTime(v8::Handle<v8::Date>::Cast(m_value));
+
+}
+
+QObject* QJSValuePrivate::toQObject() const
+{
+ if (!isJSBased())
+ return 0;
+
+ v8::HandleScope handleScope;
+ return engine()->qtObjectFromJS(m_value);
+}
+
+double QJSValuePrivate::toInteger() const
+{
+ double result = toNumber();
+ if (qIsNaN(result))
+ return 0;
+ if (qIsInf(result))
+ return result;
+
+ // Must use floor explicitly rather than qFloor here. On some
+ // platforms qFloor will cast the value to a single precision float and use
+ // floorf() which results in test failures.
+ return (result > 0) ? floor(result) : -1 * floor(-result);
+}
+
+qint32 QJSValuePrivate::toInt32() const
+{
+ double result = toInteger();
+ // Orginaly it should look like that (result == 0 || qIsInf(result) || qIsNaN(result)), but
+ // some of these operation are invoked in toInteger subcall.
+ if (qIsInf(result))
+ return 0;
+ return result;
+}
+
+quint32 QJSValuePrivate::toUInt32() const
+{
+ double result = toInteger();
+ // Orginaly it should look like that (result == 0 || qIsInf(result) || qIsNaN(result)), but
+ // some of these operation are invoked in toInteger subcall.
+ if (qIsInf(result))
+ return 0;
+
+ // The explicit casts are required to avoid undefined behaviour. For example, casting
+ // a negative double directly to an unsigned int on ARM NEON FPU results in the value
+ // being set to zero. Casting to a signed int first ensures well defined behaviour.
+ return (quint32) (qint32) result;
+}
+
+quint16 QJSValuePrivate::toUInt16() const
+{
+ return toInt32();
+}
+
+inline bool QJSValuePrivate::isArray() const
+{
+ return isJSBased() && m_value->IsArray();
+}
+
+inline bool QJSValuePrivate::isBool() const
+{
+ return m_state == CBool || (isJSBased() && m_value->IsBoolean());
+}
+
+inline bool QJSValuePrivate::isCallable() const
+{
+ if (isFunction())
+ return true;
+ if (isObject()) {
+ // Our C++ wrappers register function handlers but not always act as callables.
+ return v8::Object::Cast(*m_value)->IsCallable();
+ }
+ return false;
+}
+
+inline bool QJSValuePrivate::isError() const
+{
+ if (!isJSBased())
+ return false;
+ v8::HandleScope handleScope;
+ return m_value->IsError();
+}
+
+inline bool QJSValuePrivate::isFunction() const
+{
+ return isJSBased() && m_value->IsFunction();
+}
+
+inline bool QJSValuePrivate::isNull() const
+{
+ return m_state == CNull || (isJSBased() && m_value->IsNull());
+}
+
+inline bool QJSValuePrivate::isNumber() const
+{
+ return m_state == CNumber || (isJSBased() && m_value->IsNumber());
+}
+
+inline bool QJSValuePrivate::isObject() const
+{
+ return isJSBased() && m_value->IsObject();
+}
+
+inline bool QJSValuePrivate::isString() const
+{
+ return m_state == CString || (isJSBased() && m_value->IsString());
+}
+
+inline bool QJSValuePrivate::isUndefined() const
+{
+ return m_state == CUndefined || (isJSBased() && m_value->IsUndefined());
+}
+
+inline bool QJSValuePrivate::isVariant() const
+{
+ return isJSBased() && m_engine->isVariant(m_value);
+}
+
+bool QJSValuePrivate::isDate() const
+{
+ return (isJSBased() && m_value->IsDate());
+}
+
+bool QJSValuePrivate::isRegExp() const
+{
+ return (isJSBased() && m_value->IsRegExp());
+}
+
+bool QJSValuePrivate::isQObject() const
+{
+ return isJSBased() && engine()->isQObject(m_value);
+}
+
+inline bool QJSValuePrivate::equals(QJSValuePrivate* other)
+{
+ if (!isJSBased() && !other->isJSBased()) {
+ switch (m_state) {
+ case CNull:
+ case CUndefined:
+ return other->isUndefined() || other->isNull();
+ case CNumber:
+ switch (other->m_state) {
+ case CBool:
+ case CString:
+ return u.m_number == other->toNumber();
+ case CNumber:
+ return u.m_number == other->u.m_number;
+ default:
+ return false;
+ }
+ case CBool:
+ switch (other->m_state) {
+ case CBool:
+ return u.m_bool == other->u.m_bool;
+ case CNumber:
+ return toNumber() == other->u.m_number;
+ case CString:
+ return toNumber() == other->toNumber();
+ default:
+ return false;
+ }
+ case CString:
+ switch (other->m_state) {
+ case CBool:
+ return toNumber() == other->toNumber();
+ case CNumber:
+ return toNumber() == other->u.m_number;
+ case CString:
+ return *u.m_string == *other->u.m_string;
+ default:
+ return false;
+ }
+ default:
+ Q_ASSERT_X(false, "QJSValue::equals", "Not all states are included in the previous switch statement.");
+ }
+ }
+
+ v8::HandleScope handleScope;
+ if (isJSBased() && !other->isJSBased()) {
+ if (!other->assignEngine(engine())) {
+ qWarning("QJSValue::equals: cannot compare to a value created in a different engine");
+ return false;
+ }
+ } else if (!isJSBased() && other->isJSBased()) {
+ if (!assignEngine(other->engine())) {
+ qWarning("QJSValue::equals: cannot compare to a value created in a different engine");
+ return false;
+ }
+ }
+
+ Q_ASSERT(this->engine() && other->engine());
+ if (this->engine() != other->engine()) {
+ qWarning("QJSValue::equals: cannot compare to a value created in a different engine");
+ return false;
+ }
+ return m_value->Equals(other->m_value);
+}
+
+inline bool QJSValuePrivate::strictlyEquals(QJSValuePrivate* other)
+{
+ if (isJSBased()) {
+ // We can't compare these two values without binding to the same engine.
+ if (!other->isJSBased()) {
+ if (other->assignEngine(engine()))
+ return m_value->StrictEquals(other->m_value);
+ return false;
+ }
+ if (other->engine() != engine()) {
+ qWarning("QJSValue::strictlyEquals: cannot compare to a value created in a different engine");
+ return false;
+ }
+ return m_value->StrictEquals(other->m_value);
+ }
+ if (isStringBased()) {
+ if (other->isStringBased())
+ return *u.m_string == *(other->u.m_string);
+ if (other->isJSBased()) {
+ assignEngine(other->engine());
+ return m_value->StrictEquals(other->m_value);
+ }
+ }
+ if (isNumberBased()) {
+ if (other->isJSBased()) {
+ assignEngine(other->engine());
+ return m_value->StrictEquals(other->m_value);
+ }
+ if (m_state != other->m_state)
+ return false;
+ if (m_state == CNumber)
+ return u.m_number == other->u.m_number;
+ Q_ASSERT(m_state == CBool);
+ return u.m_bool == other->u.m_bool;
+ }
+
+ return (isUndefined() && other->isUndefined())
+ || (isNull() && other->isNull());
+}
+
+inline bool QJSValuePrivate::lessThan(QJSValuePrivate *other) const
+{
+ if (engine() != other->engine() && engine() && other->engine()) {
+ qWarning("QJSValue::lessThan: cannot compare to a value created in a different engine");
+ return false;
+ }
+
+ if (isString() && other->isString())
+ return toString() < other->toString();
+
+ if (isObject() || other->isObject()) {
+ v8::HandleScope handleScope;
+ QV8Engine *eng = m_engine ? engine() : other->engine();
+ // FIXME: lessThan can throw an exception which will be dropped by this code:
+ Q_ASSERT(eng);
+ eng->saveException();
+ QScriptSharedDataPointer<QJSValuePrivate> cmp(eng->evaluate(QString::fromLatin1("(function(a,b){return a<b})")));
+ Q_ASSERT(cmp->isFunction());
+ v8::Handle<v8::Value> args[2];
+ cmp->prepareArgumentsForCall(args, QJSValueList() << QJSValuePrivate::get(this) << QJSValuePrivate::get(other));
+ QScriptSharedDataPointer<QJSValuePrivate> resultValue(cmp->call(0, 2, args));
+ bool result = resultValue->toBool();
+ eng->restoreException();
+ return result;
+ }
+
+ double nthis = toNumber();
+ double nother = other->toNumber();
+ if (qIsNaN(nthis) || qIsNaN(nother)) {
+ // Should return undefined in ECMA standard.
+ return false;
+ }
+ return nthis < nother;
+}
+
+inline QScriptPassPointer<QJSValuePrivate> QJSValuePrivate::prototype() const
+{
+ if (isObject()) {
+ v8::HandleScope handleScope;
+ return new QJSValuePrivate(engine(), v8::Handle<v8::Object>::Cast(m_value)->GetPrototype());
+ }
+ return new QJSValuePrivate();
+}
+
+inline void QJSValuePrivate::setPrototype(QJSValuePrivate* prototype)
+{
+ if (isObject() && (prototype->isObject() || prototype->isNull())) {
+ if (engine() != prototype->engine()) {
+ if (prototype->engine()) {
+ qWarning("QJSValue::setPrototype() failed: cannot set a prototype created in a different engine");
+ return;
+ }
+ prototype->assignEngine(engine());
+ }
+ v8::HandleScope handleScope;
+ if (!v8::Handle<v8::Object>::Cast(m_value)->SetPrototype(*prototype))
+ qWarning("QJSValue::setPrototype() failed: cyclic prototype value");
+ }
+}
+
+inline void QJSValuePrivate::setProperty(const QString& name, QJSValuePrivate* value, uint attribs)
+{
+ if (!isObject())
+ return;
+ v8::HandleScope handleScope;
+ setProperty(QJSConverter::toString(name), value, attribs);
+}
+
+inline void QJSValuePrivate::setProperty(v8::Handle<v8::String> name, QJSValuePrivate* value, uint attribs)
+{
+ if (!isObject())
+ return;
+
+ if (!value->isJSBased())
+ value->assignEngine(engine());
+
+ if (engine() != value->engine()) {
+ qWarning("QJSValue::setProperty(%s) failed: "
+ "cannot set value created in a different engine",
+ qPrintable(QJSConverter::toString(name)));
+ return;
+ }
+
+ v8::TryCatch tryCatch;
+// if (attribs & (QJSValue::PropertyGetter | QJSValue::PropertySetter)) {
+// engine()->originalGlobalObject()->defineGetterOrSetter(*this, name, value->m_value, attribs);
+// } else {
+ v8::Object::Cast(*m_value)->Set(name, value->m_value, v8::PropertyAttribute(attribs & QJSConverter::PropertyAttributeMask));
+// }
+ if (tryCatch.HasCaught())
+ engine()->setException(tryCatch.Exception(), tryCatch.Message());
+}
+
+inline void QJSValuePrivate::setProperty(quint32 index, QJSValuePrivate* value, uint attribs)
+{
+ // FIXME this method should by integrated with other overloads to use the same code patch.
+ // for now it is not possible as v8 doesn't allow to set property attributes using index based api.
+
+ if (!isObject())
+ return;
+
+ if (attribs) {
+ // FIXME we dont need to convert index to a string.
+ //Object::Set(int,value) do not take attributes.
+ setProperty(QString::number(index), value, attribs);
+ return;
+ }
+
+ if (!value->isJSBased())
+ value->assignEngine(engine());
+
+ if (engine() != value->engine()) {
+ qWarning("QJSValue::setProperty() failed: cannot set value created in a different engine");
+ return;
+ }
+
+ v8::HandleScope handleScope;
+ v8::TryCatch tryCatch;
+ v8::Object::Cast(*m_value)->Set(index, value->m_value);
+ if (tryCatch.HasCaught())
+ engine()->setException(tryCatch.Exception(), tryCatch.Message());
+}
+
+inline QScriptPassPointer<QJSValuePrivate> QJSValuePrivate::property(const QString& name) const
+{
+ if (!isObject())
+ return new QJSValuePrivate();
+ if (!name.length())
+ return new QJSValuePrivate(engine());
+
+ v8::HandleScope handleScope;
+ return property(QJSConverter::toString(name));
+}
+
+inline QScriptPassPointer<QJSValuePrivate> QJSValuePrivate::property(v8::Handle<v8::String> name) const
+{
+ Q_ASSERT(!name.IsEmpty());
+ if (!isObject())
+ return new QJSValuePrivate();
+ return property<>(name);
+}
+
+inline QScriptPassPointer<QJSValuePrivate> QJSValuePrivate::property(quint32 index) const
+{
+ if (!isObject())
+ return new QJSValuePrivate();
+ return property<>(index);
+}
+
+template<typename T>
+inline QScriptPassPointer<QJSValuePrivate> QJSValuePrivate::property(T name) const
+{
+ Q_ASSERT(isObject());
+ v8::HandleScope handleScope;
+ v8::Handle<v8::Object> self(v8::Object::Cast(*m_value));
+
+ v8::TryCatch tryCatch;
+ v8::Handle<v8::Value> result = self->Get(name);
+ if (tryCatch.HasCaught()) {
+ result = tryCatch.Exception();
+ engine()->setException(result, tryCatch.Message());
+ return new QJSValuePrivate(engine(), result);
+ }
+ if (result.IsEmpty())
+ return new QJSValuePrivate(engine());
+ return new QJSValuePrivate(engine(), result);
+}
+
+inline bool QJSValuePrivate::deleteProperty(const QString& name)
+{
+ if (!isObject())
+ return false;
+
+ v8::HandleScope handleScope;
+ v8::Handle<v8::Object> self(v8::Handle<v8::Object>::Cast(m_value));
+ return self->Delete(QJSConverter::toString(name));
+}
+
+inline bool QJSValuePrivate::hasProperty(const QString &name) const
+{
+ if (!isObject())
+ return false;
+
+ v8::HandleScope handleScope;
+ v8::Handle<v8::Object> self(v8::Handle<v8::Object>::Cast(m_value));
+ return self->Has(QJSConverter::toString(name));
+}
+
+inline bool QJSValuePrivate::hasOwnProperty(const QString &name) const
+{
+ if (!isObject())
+ return false;
+
+ v8::HandleScope handleScope;
+ v8::Handle<v8::Object> self(v8::Handle<v8::Object>::Cast(m_value));
+ return self->HasOwnProperty(QJSConverter::toString(name));
+}
+
+inline QJSValuePrivate::PropertyFlags QJSValuePrivate::propertyFlags(const QString& name) const
+{
+ if (!isObject())
+ return QJSValuePrivate::PropertyFlags(0);
+
+ v8::HandleScope handleScope;
+ return engine()->getPropertyFlags(v8::Handle<v8::Object>::Cast(m_value), QJSConverter::toString(name));
+}
+
+inline QJSValuePrivate::PropertyFlags QJSValuePrivate::propertyFlags(v8::Handle<v8::String> name) const
+{
+ if (!isObject())
+ return QJSValuePrivate::PropertyFlags(0);
+
+ v8::HandleScope handleScope;
+ return engine()->getPropertyFlags(v8::Handle<v8::Object>::Cast(m_value), name);
+}
+
+inline QScriptPassPointer<QJSValuePrivate> QJSValuePrivate::call(QJSValuePrivate* thisObject, const QJSValueList& args)
+{
+ if (!isCallable())
+ return new QJSValuePrivate();
+
+ v8::HandleScope handleScope;
+
+ // Convert all arguments and bind to the engine.
+ int argc = args.size();
+ QVarLengthArray<v8::Handle<v8::Value>, 8> argv(argc);
+ if (!prepareArgumentsForCall(argv.data(), args)) {
+ qWarning("QJSValue::call() failed: cannot call function with argument created in a different engine");
+ return new QJSValuePrivate(engine());
+ }
+
+ return call(thisObject, argc, argv.data());
+}
+
+QScriptPassPointer<QJSValuePrivate> QJSValuePrivate::call(QJSValuePrivate* thisObject, int argc, v8::Handle<v8::Value> *argv)
+{
+ QV8Engine *e = engine();
+
+ v8::Handle<v8::Object> recv;
+
+ if (!thisObject || !thisObject->isObject()) {
+ recv = v8::Handle<v8::Object>(v8::Object::Cast(*e->global()));
+ } else {
+ if (!thisObject->assignEngine(e)) {
+ qWarning("QJSValue::call() failed: cannot call function with thisObject created in a different engine");
+ return new QJSValuePrivate(engine());
+ }
+
+ recv = v8::Handle<v8::Object>(v8::Object::Cast(*thisObject->m_value));
+ }
+
+ if (argc < 0) {
+ v8::Local<v8::Value> exeption = v8::Exception::TypeError(v8::String::New("Arguments must be an array"));
+ e->setException(exeption);
+ return new QJSValuePrivate(e, exeption);
+ }
+
+ v8::TryCatch tryCatch;
+ v8::Handle<v8::Value> result = v8::Object::Cast(*m_value)->CallAsFunction(recv, argc, argv);
+
+ if (result.IsEmpty()) {
+ result = tryCatch.Exception();
+ // TODO: figure out why v8 doesn't always produce an exception value.
+ //Q_ASSERT(!result.IsEmpty());
+ if (result.IsEmpty())
+ result = v8::Exception::Error(v8::String::New("missing exception value"));
+ e->setException(result, tryCatch.Message());
+ }
+
+ return new QJSValuePrivate(e, result);
+}
+
+inline QScriptPassPointer<QJSValuePrivate> QJSValuePrivate::callAsConstructor(int argc, v8::Handle<v8::Value> *argv)
+{
+ QV8Engine *e = engine();
+
+ if (argc < 0) {
+ v8::Local<v8::Value> exeption = v8::Exception::TypeError(v8::String::New("Arguments must be an array"));
+ e->setException(exeption);
+ return new QJSValuePrivate(e, exeption);
+ }
+
+ v8::TryCatch tryCatch;
+ v8::Handle<v8::Value> result = v8::Object::Cast(*m_value)->CallAsConstructor(argc, argv);
+
+ if (result.IsEmpty()) {
+ result = tryCatch.Exception();
+ e->setException(result, tryCatch.Message());
+ }
+
+ return new QJSValuePrivate(e, result);
+}
+
+inline QScriptPassPointer<QJSValuePrivate> QJSValuePrivate::callAsConstructor(const QJSValueList& args)
+{
+ if (!isCallable())
+ return new QJSValuePrivate();
+
+ v8::HandleScope handleScope;
+
+ // Convert all arguments and bind to the engine.
+ int argc = args.size();
+ QVarLengthArray<v8::Handle<v8::Value>, 8> argv(argc);
+ if (!prepareArgumentsForCall(argv.data(), args)) {
+ qWarning("QJSValue::callAsConstructor() failed: cannot construct function with argument created in a different engine");
+ return new QJSValuePrivate(engine());
+ }
+
+ return callAsConstructor(argc, argv.data());
+}
+
+/*! \internal
+ * Make sure this value is associated with a v8 value belonging to this engine.
+ * If the value belongs to another engine, returns false.
+ */
+bool QJSValuePrivate::assignEngine(QV8Engine* engine)
+{
+ Q_ASSERT(engine);
+ v8::HandleScope handleScope;
+ switch (m_state) {
+ case CBool:
+ m_value = v8::Persistent<v8::Value>::New(engine->makeJSValue(u.m_bool));
+ break;
+ case CString:
+ m_value = v8::Persistent<v8::Value>::New(engine->makeJSValue(*u.m_string));
+ delete u.m_string;
+ break;
+ case CNumber:
+ m_value = v8::Persistent<v8::Value>::New(engine->makeJSValue(u.m_number));
+ break;
+ case CNull:
+ m_value = v8::Persistent<v8::Value>::New(engine->makeJSValue(QJSValue::NullValue));
+ break;
+ case CUndefined:
+ m_value = v8::Persistent<v8::Value>::New(engine->makeJSValue(QJSValue::UndefinedValue));
+ break;
+ default:
+ if (this->engine() == engine)
+ return true;
+ else if (!isJSBased())
+ Q_ASSERT_X(!isJSBased(), "assignEngine()", "Not all states are included in the previous switch statement.");
+ else
+ qWarning("JSValue can't be rassigned to an another engine.");
+ return false;
+ }
+ m_engine = engine;
+ m_state = JSValue;
+
+ m_engine->registerValue(this);
+ return true;
+}
+
+/*!
+ \internal
+ Invalidates this value (makes it undefined).
+
+ Does not remove the value from the engine's list of
+ registered values; that's the responsibility of the caller.
+*/
+void QJSValuePrivate::invalidate()
+{
+ if (isJSBased()) {
+ m_value.Dispose();
+ m_value.Clear();
+ } else if (isStringBased()) {
+ delete u.m_string;
+ }
+ m_engine = 0;
+ m_state = CUndefined;
+}
+
+QV8Engine* QJSValuePrivate::engine() const
+{
+ return m_engine;
+}
+
+inline QJSValuePrivate::operator v8::Handle<v8::Value>() const
+{
+ Q_ASSERT(isJSBased());
+ return m_value;
+}
+
+inline QJSValuePrivate::operator v8::Handle<v8::Object>() const
+{
+ Q_ASSERT(isObject());
+ return v8::Handle<v8::Object>::Cast(m_value);
+}
+
+/*!
+ * Return a v8::Handle, assign to the engine if needed.
+ */
+v8::Handle<v8::Value> QJSValuePrivate::asV8Value(QV8Engine* engine)
+{
+ if (!m_engine) {
+ if (!assignEngine(engine))
+ return v8::Handle<v8::Value>();
+ }
+ Q_ASSERT(isJSBased());
+ return m_value;
+}
+
+/*!
+ \internal
+ Returns true if QSV have an engine associated.
+*/
+bool QJSValuePrivate::isJSBased() const
+{
+#ifndef QT_NO_DEBUG
+ // internals check.
+ if (m_state >= JSValue)
+ Q_ASSERT(!m_value.IsEmpty());
+ else
+ Q_ASSERT(m_value.IsEmpty());
+#endif
+ return m_state >= JSValue;
+}
+
+/*!
+ \internal
+ Returns true if current value of QSV is placed in m_number.
+*/
+bool QJSValuePrivate::isNumberBased() const { return m_state == CNumber || m_state == CBool; }
+
+/*!
+ \internal
+ Returns true if current value of QSV is placed in m_string.
+*/
+bool QJSValuePrivate::isStringBased() const { return m_state == CString; }
+
+/*!
+ \internal
+ Converts arguments and bind them to the engine.
+ \attention argv should be big enough
+*/
+inline bool QJSValuePrivate::prepareArgumentsForCall(v8::Handle<v8::Value> argv[], const QJSValueList& args) const
+{
+ QJSValueList::const_iterator i = args.constBegin();
+ for (int j = 0; i != args.constEnd(); j++, i++) {
+ QJSValuePrivate* value = QJSValuePrivate::get(*i);
+ if ((value->isJSBased() && engine() != value->engine())
+ || (!value->isJSBased() && !value->assignEngine(engine())))
+ // Different engines are not allowed!
+ return false;
+ argv[j] = *value;
+ }
+ return true;
+}
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/qml/qml/v8/qjsvalue_p.h b/src/qml/qml/v8/qjsvalue_p.h
new file mode 100644
index 0000000000..3eccba64bd
--- /dev/null
+++ b/src/qml/qml/v8/qjsvalue_p.h
@@ -0,0 +1,195 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtScript module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL-ONLY$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** If you have questions regarding the use of this file, please contact
+** us via http://www.qt-project.org/.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// 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.
+//
+
+#ifndef QJSVALUE_P_H
+#define QJSVALUE_P_H
+
+#include <private/qv8_p.h>
+
+#include <QtCore/qbytearray.h>
+#include <QtCore/qdatetime.h>
+#include <QtCore/qmath.h>
+#include <QtCore/qvarlengtharray.h>
+#include <qdebug.h>
+
+#include <private/qintrusivelist_p.h>
+#include "qscriptshareddata_p.h"
+#include "qjsvalue.h"
+
+QT_BEGIN_NAMESPACE
+
+class QV8Engine;
+
+/*!
+ \internal
+ \class QJSValuePrivate
+*/
+class QJSValuePrivate
+ : public QSharedData
+{
+public:
+ enum PropertyFlag {
+ ReadOnly = 0x00000001,
+ Undeletable = 0x00000002,
+ SkipInEnumeration = 0x00000004
+ };
+ Q_DECLARE_FLAGS(PropertyFlags, PropertyFlag)
+
+ inline static QJSValuePrivate* get(const QJSValue& q);
+ inline static QJSValue get(const QJSValuePrivate* d);
+ inline static QJSValue get(QJSValuePrivate* d);
+ inline static QJSValue get(QScriptPassPointer<QJSValuePrivate> d);
+ inline ~QJSValuePrivate();
+
+ inline QJSValuePrivate(bool value);
+ inline QJSValuePrivate(int value);
+ inline QJSValuePrivate(uint value);
+ inline QJSValuePrivate(double value);
+ inline QJSValuePrivate(const QString& value);
+ inline QJSValuePrivate(QJSValue::SpecialValue value = QJSValue::UndefinedValue);
+
+ inline QJSValuePrivate(QV8Engine *engine, bool value);
+ inline QJSValuePrivate(QV8Engine *engine, int value);
+ inline QJSValuePrivate(QV8Engine *engine, uint value);
+ inline QJSValuePrivate(QV8Engine *engine, double value);
+ inline QJSValuePrivate(QV8Engine *engine, const QString& value);
+ inline QJSValuePrivate(QV8Engine *engine, QJSValue::SpecialValue value = QJSValue::UndefinedValue);
+ inline QJSValuePrivate(QV8Engine *engine, v8::Handle<v8::Value>);
+ inline void invalidate();
+
+ inline bool toBool() const;
+ inline double toNumber() const;
+ inline QString toString() const;
+ inline double toInteger() const;
+ inline qint32 toInt32() const;
+ inline quint32 toUInt32() const;
+ inline quint16 toUInt16() const;
+ inline QDateTime toDataTime() const;
+ inline QObject *toQObject() const;
+ inline QVariant toVariant() const;
+
+ inline bool isArray() const;
+ inline bool isBool() const;
+ inline bool isCallable() const;
+ inline bool isError() const;
+ inline bool isFunction() const;
+ inline bool isNull() const;
+ inline bool isNumber() const;
+ inline bool isObject() const;
+ inline bool isString() const;
+ inline bool isUndefined() const;
+ inline bool isVariant() const;
+ inline bool isDate() const;
+ inline bool isRegExp() const;
+ inline bool isQObject() const;
+
+ inline bool equals(QJSValuePrivate* other);
+ inline bool strictlyEquals(QJSValuePrivate* other);
+ inline bool lessThan(QJSValuePrivate *other) const;
+
+ inline QScriptPassPointer<QJSValuePrivate> prototype() const;
+ inline void setPrototype(QJSValuePrivate* prototype);
+
+ inline void setProperty(const QString &name, QJSValuePrivate *value, uint attribs = 0);
+ inline void setProperty(v8::Handle<v8::String> name, QJSValuePrivate *value, uint attribs = 0);
+ inline void setProperty(quint32 index, QJSValuePrivate* value, uint attribs = 0);
+ inline QScriptPassPointer<QJSValuePrivate> property(const QString& name) const;
+ inline QScriptPassPointer<QJSValuePrivate> property(v8::Handle<v8::String> name) const;
+ inline QScriptPassPointer<QJSValuePrivate> property(quint32 index) const;
+ template<typename T>
+ inline QScriptPassPointer<QJSValuePrivate> property(T name) const;
+ inline bool deleteProperty(const QString& name);
+ inline bool hasProperty(const QString &name) const;
+ inline bool hasOwnProperty(const QString &name) const;
+ inline PropertyFlags propertyFlags(const QString& name) const;
+ inline PropertyFlags propertyFlags(v8::Handle<v8::String> name) const;
+
+ inline QScriptPassPointer<QJSValuePrivate> call(QJSValuePrivate* thisObject, const QJSValueList& args);
+ inline QScriptPassPointer<QJSValuePrivate> call(QJSValuePrivate* thisObject, const QJSValue& arguments);
+ inline QScriptPassPointer<QJSValuePrivate> call(QJSValuePrivate* thisObject, int argc, v8::Handle< v8::Value >* argv);
+ inline QScriptPassPointer<QJSValuePrivate> callAsConstructor(int argc, v8::Handle<v8::Value> *argv);
+ inline QScriptPassPointer<QJSValuePrivate> callAsConstructor(const QJSValueList& args);
+ inline QScriptPassPointer<QJSValuePrivate> callAsConstructor(const QJSValue& arguments);
+
+ inline bool assignEngine(QV8Engine *engine);
+ inline QV8Engine *engine() const;
+
+ inline operator v8::Handle<v8::Value>() const;
+ inline operator v8::Handle<v8::Object>() const;
+ inline v8::Handle<v8::Value> asV8Value(QV8Engine *engine);
+private:
+ QIntrusiveListNode m_node;
+ QV8Engine *m_engine;
+
+ // Please, update class documentation when you change the enum.
+ enum State {
+ CString = 0x1000,
+ CNumber,
+ CBool,
+ CNull,
+ CUndefined,
+ JSValue = 0x2000, // V8 values are equal or higher then this value.
+ // JSPrimitive,
+ // JSObject
+ } m_state;
+
+ union CValue {
+ bool m_bool;
+ double m_number;
+ QString* m_string;
+
+ CValue() : m_number(0) {}
+ CValue(bool value) : m_bool(value) {}
+ CValue(int number) : m_number(number) {}
+ CValue(uint number) : m_number(number) {}
+ CValue(double number) : m_number(number) {}
+ CValue(QString* string) : m_string(string) {}
+ } u;
+ // v8::Persistent is not a POD, so can't be part of the union.
+ v8::Persistent<v8::Value> m_value;
+
+ Q_DISABLE_COPY(QJSValuePrivate)
+ inline bool isJSBased() const;
+ inline bool isNumberBased() const;
+ inline bool isStringBased() const;
+ inline bool prepareArgumentsForCall(v8::Handle<v8::Value> argv[], const QJSValueList& arguments) const;
+
+ friend class QV8Engine;
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QJSValuePrivate::PropertyFlags)
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/qml/qml/v8/qjsvalueiterator.cpp b/src/qml/qml/v8/qjsvalueiterator.cpp
new file mode 100644
index 0000000000..4c3fa15fd3
--- /dev/null
+++ b/src/qml/qml/v8/qjsvalueiterator.cpp
@@ -0,0 +1,157 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtScript module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL-ONLY$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** If you have questions regarding the use of this file, please contact
+** us via http://www.qt-project.org/.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qjsvalueiterator.h"
+#include "qjsvalueiterator_p.h"
+
+#include "qscriptisolate_p.h"
+#include "qjsvalue_p.h"
+#include "qv8engine_p.h"
+#include "qscript_impl_p.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QJSValueIterator
+
+ \brief The QJSValueIterator class provides a Java-style iterator for QJSValue.
+
+ \ingroup qtjavascript
+
+
+ The QJSValueIterator constructor takes a QJSValue as
+ argument. After construction, the iterator is located at the very
+ beginning of the sequence of properties. Here's how to iterate over
+ all the properties of a QJSValue:
+
+ \snippet doc/src/snippets/code/src_script_qjsvalueiterator.cpp 0
+
+ The next() advances the iterator. The name() and value()
+ functions return the name and value of the last item that was
+ jumped over.
+
+ Note that QJSValueIterator only iterates over the QJSValue's
+ own properties; i.e. it does not follow the prototype chain. You can
+ use a loop like this to follow the prototype chain:
+
+ \snippet doc/src/snippets/code/src_script_qjsvalueiterator.cpp 1
+
+ Note that QJSValueIterator will not automatically skip over
+ properties that have the QJSValue::SkipInEnumeration flag set;
+ that flag only affects iteration in script code. If you want, you
+ can skip over such properties with code like the following:
+
+ \snippet doc/src/snippets/code/src_script_qjsvalueiterator.cpp 2
+
+ \sa QJSValue::property()
+*/
+
+/*!
+ Constructs an iterator for traversing \a object. The iterator is
+ set to be at the front of the sequence of properties (before the
+ first property).
+*/
+QJSValueIterator::QJSValueIterator(const QJSValue& object)
+ : d_ptr(new QJSValueIteratorPrivate(QJSValuePrivate::get(object)))
+{}
+
+/*!
+ Destroys the iterator.
+*/
+QJSValueIterator::~QJSValueIterator()
+{}
+
+/*!
+ Returns true if there is at least one item ahead of the iterator
+ (i.e. the iterator is \e not at the back of the property sequence);
+ otherwise returns false.
+
+ \sa next()
+*/
+bool QJSValueIterator::hasNext() const
+{
+ Q_D(const QJSValueIterator);
+ QScriptIsolate api(d->engine());
+ return d->hasNext();
+}
+
+/*!
+ Advances the iterator by one position.
+ Returns true if there is at least one item ahead of the iterator
+ (i.e. the iterator is \e not at the back of the property sequence);
+ otherwise returns false.
+
+ Calling this function on an iterator located at the back of the
+ container leads to undefined results.
+
+ \sa hasNext(), name()
+*/
+bool QJSValueIterator::next()
+{
+ Q_D(QJSValueIterator);
+ QScriptIsolate api(d->engine());
+ return d->next();
+}
+
+/*!
+ Returns the name of the last property that was jumped over using
+ next().
+
+ \sa value()
+*/
+QString QJSValueIterator::name() const
+{
+ Q_D(const QJSValueIterator);
+ QScriptIsolate api(d->engine());
+ return d_ptr->name();
+}
+
+
+/*!
+ Returns the value of the last property that was jumped over using
+ next().
+
+ \sa name()
+*/
+QJSValue QJSValueIterator::value() const
+{
+ Q_D(const QJSValueIterator);
+ QScriptIsolate api(d->engine());
+ return QJSValuePrivate::get(d->value());
+}
+
+
+/*!
+ Makes the iterator operate on \a object. The iterator is set to be
+ at the front of the sequence of properties (before the first
+ property).
+*/
+QJSValueIterator& QJSValueIterator::operator=(QJSValue& object)
+{
+ Q_D(QJSValueIterator);
+ QScriptIsolate api(d->engine());
+ d_ptr.reset(new QJSValueIteratorPrivate(QJSValuePrivate::get(object)));
+ return *this;
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/v8/qjsvalueiterator.h b/src/qml/qml/v8/qjsvalueiterator.h
new file mode 100644
index 0000000000..c47f07d43b
--- /dev/null
+++ b/src/qml/qml/v8/qjsvalueiterator.h
@@ -0,0 +1,63 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtScript module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL-ONLY$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** If you have questions regarding the use of this file, please contact
+** us via http://www.qt-project.org/.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSCRIPTVALUEITERATOR_H
+#define QSCRIPTVALUEITERATOR_H
+
+#include <QtQml/qjsvalue.h>
+#include <QtCore/qscopedpointer.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+
+class QString;
+
+class QJSValueIteratorPrivate;
+class Q_QML_EXPORT QJSValueIterator
+{
+public:
+ QJSValueIterator(const QJSValue &value);
+ ~QJSValueIterator();
+
+ bool hasNext() const;
+ bool next();
+
+ QString name() const;
+
+ QJSValue value() const;
+ QJSValueIterator& operator=(QJSValue &value);
+
+private:
+ QScopedPointer<QJSValueIteratorPrivate> d_ptr;
+
+ Q_DECLARE_PRIVATE(QJSValueIterator)
+ Q_DISABLE_COPY(QJSValueIterator)
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QSCRIPTVALUEITERATOR_H
diff --git a/src/qml/qml/v8/qjsvalueiterator_impl_p.h b/src/qml/qml/v8/qjsvalueiterator_impl_p.h
new file mode 100644
index 0000000000..131296ecac
--- /dev/null
+++ b/src/qml/qml/v8/qjsvalueiterator_impl_p.h
@@ -0,0 +1,121 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL-ONLY$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** If you have questions regarding the use of this file, please contact
+** us via http://www.qt-project.org/.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QJSVALUEITERATOR_IMPL_P_H
+#define QJSVALUEITERATOR_IMPL_P_H
+
+#include "qjsvalueiterator_p.h"
+#include <private/qv8engine_p.h>
+#include "qjsconverter_p.h"
+
+inline QJSValueIteratorPrivate::QJSValueIteratorPrivate(const QJSValuePrivate* value)
+ : m_object(const_cast<QJSValuePrivate*>(value))
+ , m_index(0)
+ , m_count(0)
+{
+ Q_ASSERT(value);
+ QV8Engine *engine = m_object->engine();
+ if (!m_object->isObject())
+ m_object = 0;
+ else {
+ QScriptIsolate api(engine, QScriptIsolate::NotNullEngine);
+ v8::HandleScope scope;
+
+ v8::Handle<v8::Value> tmp = *value;
+ v8::Handle<v8::Object> obj = v8::Handle<v8::Object>::Cast(tmp);
+ v8::Local<v8::Array> names;
+
+ // FIXME we need newer V8!
+ //names = obj->GetOwnPropertyNames();
+ names = engine->getOwnPropertyNames(obj);
+ m_names = v8::Persistent<v8::Array>::New(names);
+ m_count = names->Length();
+
+ engine->registerValueIterator(this);
+ }
+}
+
+inline QJSValueIteratorPrivate::~QJSValueIteratorPrivate()
+{
+ if (isValid()) {
+ engine()->unregisterValueIterator(this);
+ m_names.Dispose();
+ }
+}
+
+inline void QJSValueIteratorPrivate::invalidate()
+{
+ m_names.Dispose();
+ m_object.reset();
+ m_index = 0;
+ m_count = 0;
+}
+
+inline bool QJSValueIteratorPrivate::hasNext() const
+{
+ return isValid() ? m_index < m_count : false;
+}
+
+inline bool QJSValueIteratorPrivate::next()
+{
+ if (hasNext()) {
+ ++m_index;
+ return true;
+ }
+ return false;
+}
+
+inline QString QJSValueIteratorPrivate::name() const
+{
+ if (!isValid())
+ return QString();
+
+ v8::HandleScope handleScope;
+ return QJSConverter::toString(m_names->Get(m_index - 1)->ToString());
+}
+
+inline QScriptPassPointer<QJSValuePrivate> QJSValueIteratorPrivate::value() const
+{
+ if (!isValid())
+ return new QJSValuePrivate();
+
+ v8::HandleScope handleScope;
+ return m_object->property(m_names->Get(m_index - 1)->ToString());
+}
+
+inline bool QJSValueIteratorPrivate::isValid() const
+{
+ bool result = m_object ? !m_object->isUndefined() : false;
+ // We know that if this object is still valid then it is an object
+ // if this assumption is not correct then some other logic in this class
+ // have to be changed too.
+ Q_ASSERT(!result || m_object->isObject());
+ return result;
+}
+
+inline QV8Engine* QJSValueIteratorPrivate::engine() const
+{
+ return m_object ? m_object->engine() : 0;
+}
+
+#endif // QJSVALUEITERATOR_IMPL_P_H
diff --git a/src/qml/qml/v8/qjsvalueiterator_p.h b/src/qml/qml/v8/qjsvalueiterator_p.h
new file mode 100644
index 0000000000..2a5bcdec22
--- /dev/null
+++ b/src/qml/qml/v8/qjsvalueiterator_p.h
@@ -0,0 +1,68 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL-ONLY$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** If you have questions regarding the use of this file, please contact
+** us via http://www.qt-project.org/.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QJSVALUEITERATOR_P_H
+#define QJSVALUEITERATOR_P_H
+
+#include <private/qintrusivelist_p.h>
+#include "qjsvalue_p.h"
+
+#include <private/qv8_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QV8Engine;
+
+class QJSValueIteratorPrivate
+{
+public:
+ inline QJSValueIteratorPrivate(const QJSValuePrivate* value);
+ inline ~QJSValueIteratorPrivate();
+
+ inline bool hasNext() const;
+ inline bool next();
+
+ inline QString name() const;
+
+ inline QScriptPassPointer<QJSValuePrivate> value() const;
+
+ inline bool isValid() const;
+ inline QV8Engine* engine() const;
+
+ inline void invalidate();
+private:
+ Q_DISABLE_COPY(QJSValueIteratorPrivate)
+
+ QIntrusiveListNode m_node;
+ QScriptSharedDataPointer<QJSValuePrivate> m_object;
+ v8::Persistent<v8::Array> m_names;
+ uint32_t m_index;
+ uint32_t m_count;
+
+ friend class QV8Engine;
+};
+
+
+QT_END_NAMESPACE
+
+#endif // QJSVALUEITERATOR_P_H
diff --git a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp
new file mode 100644
index 0000000000..5284832ae1
--- /dev/null
+++ b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp
@@ -0,0 +1,1320 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qqmlbuiltinfunctions_p.h"
+
+#include <QtQml/qqmlcomponent.h>
+#include <private/qqmlengine_p.h>
+#include <private/qqmlcomponent_p.h>
+#include <private/qqmlstringconverters_p.h>
+#include <private/qqmllocale_p.h>
+#include <private/qv8engine_p.h>
+#include <private/qjsconverter_impl_p.h>
+
+#include <private/qv8profilerservice_p.h>
+#include <private/qqmlprofilerservice_p.h>
+
+#include <QtCore/qstring.h>
+#include <QtCore/qdatetime.h>
+#include <QtCore/qcryptographichash.h>
+#include <QtCore/qrect.h>
+#include <QtCore/qsize.h>
+#include <QtCore/qpoint.h>
+#include <QtCore/qurl.h>
+#include <QtCore/qfile.h>
+#include <QtCore/qcoreapplication.h>
+
+#include <QtGui/qcolor.h>
+#include <QtGui/qvector3d.h>
+#include <QtGui/qvector4d.h>
+#include <QtGui/qdesktopservices.h>
+#include <QtGui/qfontdatabase.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace QQmlBuiltinFunctions {
+
+enum ConsoleLogTypes {
+ Log,
+ Warn,
+ Error
+};
+
+static void jsContext(v8::Handle<v8::Value> *file, int *line, v8::Handle<v8::Value> *function) {
+ v8::Local<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(1);
+ if (stackTrace->GetFrameCount()) {
+ v8::Local<v8::StackFrame> frame = stackTrace->GetFrame(0);
+ *file = frame->GetScriptName();
+ *line = frame->GetLineNumber();
+ *function = frame->GetFunctionName();
+ }
+}
+
+static QString jsStack() {
+ QStringList stackFrames;
+
+ //The v8 default is currently 10 stack frames.
+ v8::Handle<v8::StackTrace> stackTrace =
+ v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kOverview);
+ int stackCount = stackTrace->GetFrameCount();
+
+ for (int i = 0; i < stackCount; i++) {
+ v8::Local<v8::StackFrame> frame = stackTrace->GetFrame(i);
+ v8::Handle<v8::String> function(frame->GetFunctionName());
+ v8::Handle<v8::String> script(frame->GetScriptName());
+ int lineNumber = frame->GetLineNumber();
+ int columnNumber = frame->GetColumn();
+
+ QString stackFrame =
+ QString::fromLatin1("%1 (%2:%3:%4)").arg(QJSConverter::toString(function),
+ QJSConverter::toString(script),
+ QString::number(lineNumber),
+ QString::number(columnNumber));
+ stackFrames.append(stackFrame);
+ }
+ return stackFrames.join(QLatin1String("\n"));
+}
+
+v8::Handle<v8::Value> console(ConsoleLogTypes logType, const v8::Arguments &args,
+ bool printStack = false)
+{
+ v8::HandleScope handleScope;
+
+ QString result;
+ for (int i = 0; i < args.Length(); ++i) {
+ if (i != 0)
+ result.append(QLatin1Char(' '));
+
+ v8::Local<v8::Value> value = args[i];
+ //Check for Object Type
+ if (value->IsObject() && !value->IsFunction()
+ && !value->IsArray() && !value->IsDate()
+ && !value->IsRegExp()) {
+ result.append(QLatin1String("Object"));
+ } else {
+ v8::Local<v8::String> jsstr = value->ToString();
+ QString tmp = V8ENGINE()->toString(jsstr);
+ if (value->IsArray())
+ result.append(QString::fromLatin1("[%1]").arg(tmp));
+ else
+ result.append(tmp);
+ }
+ }
+
+ if (printStack) {
+ result.append(QLatin1String("\n"));
+ result.append(jsStack());
+ }
+
+ v8::Handle<v8::Value> fileHandle;
+ v8::Handle<v8::Value> functionHandle;
+ int line;
+
+ jsContext(&fileHandle, &line, &functionHandle);
+
+ switch (logType) {
+ case Log:
+ QMessageLogger(*v8::String::AsciiValue(fileHandle), line,
+ *v8::String::AsciiValue(functionHandle)).debug("%s", qPrintable(result));
+ break;
+ case Warn:
+ QMessageLogger(*v8::String::AsciiValue(fileHandle), line,
+ *v8::String::AsciiValue(functionHandle)).warning("%s", qPrintable(result));
+ break;
+ case Error:
+ QMessageLogger(*v8::String::AsciiValue(fileHandle), line,
+ *v8::String::AsciiValue(functionHandle)).critical("%s", qPrintable(result));
+ break;
+ default:
+ break;
+ }
+
+ return v8::Undefined();
+}
+
+v8::Handle<v8::Value> gc(const v8::Arguments &args)
+{
+ Q_UNUSED(args);
+ QV8Engine::gc();
+ return v8::Undefined();
+}
+
+v8::Handle<v8::Value> consoleError(const v8::Arguments &args)
+{
+ return console(Error, args);
+}
+
+v8::Handle<v8::Value> consoleLog(const v8::Arguments &args)
+{
+ //console.log
+ //console.debug
+ //console.info
+ //print
+ return console(Log, args);
+}
+
+v8::Handle<v8::Value> consoleProfile(const v8::Arguments &args)
+{
+ //DeclarativeDebugTrace cannot handle nested profiling
+ //although v8 can handle several profiling at once,
+ //we do not allow that. Hence, we pass an empty(default) title
+ Q_UNUSED(args);
+ QString title;
+
+
+
+ v8::Handle<v8::Value> file;
+ v8::Handle<v8::Value> function;
+ int line;
+ jsContext(&file, &line, &function);
+
+ if (QQmlProfilerService::startProfiling()) {
+ QV8ProfilerService::instance()->startProfiling(title);
+
+ QMessageLogger(*v8::String::AsciiValue(file), line,
+ *v8::String::AsciiValue(function)).debug("Profiling started.");
+ } else {
+ QMessageLogger(*v8::String::AsciiValue(file), line,
+ *v8::String::AsciiValue(function)).warning(
+ "Profiling is already in progress. First, end current profiling session.");
+ }
+
+ return v8::Undefined();
+}
+
+v8::Handle<v8::Value> consoleProfileEnd(const v8::Arguments &args)
+{
+ //DeclarativeDebugTrace cannot handle nested profiling
+ //although v8 can handle several profiling at once,
+ //we do not allow that. Hence, we pass an empty(default) title
+ Q_UNUSED(args);
+ QString title;
+
+ v8::Handle<v8::Value> file;
+ v8::Handle<v8::Value> function;
+ int line;
+ jsContext(&file, &line, &function);
+
+ if (QQmlProfilerService::stopProfiling()) {
+ QV8ProfilerService *profiler = QV8ProfilerService::instance();
+ profiler->stopProfiling(title);
+ QQmlProfilerService::sendProfilingData();
+ profiler->sendProfilingData();
+
+ QMessageLogger(*v8::String::AsciiValue(file), line,
+ *v8::String::AsciiValue(function)).debug("Profiling ended.");
+ } else {
+ QMessageLogger(*v8::String::AsciiValue(file), line,
+ *v8::String::AsciiValue(function)).warning("Profiling was not started.");
+ }
+
+ return v8::Undefined();
+}
+
+v8::Handle<v8::Value> consoleTime(const v8::Arguments &args)
+{
+ if (args.Length() != 1)
+ V8THROW_ERROR("console.time(): Invalid arguments");
+ QString name = V8ENGINE()->toString(args[0]);
+ V8ENGINE()->startTimer(name);
+ return v8::Undefined();
+}
+
+v8::Handle<v8::Value> consoleTimeEnd(const v8::Arguments &args)
+{
+ if (args.Length() != 1)
+ V8THROW_ERROR("console.time(): Invalid arguments");
+ QString name = V8ENGINE()->toString(args[0]);
+ bool wasRunning;
+ qint64 elapsed = V8ENGINE()->stopTimer(name, &wasRunning);
+ if (wasRunning) {
+ qDebug("%s: %llims", qPrintable(name), elapsed);
+ }
+ return v8::Undefined();
+}
+
+v8::Handle<v8::Value> consoleCount(const v8::Arguments &args)
+{
+ // first argument: name to print. Ignore any additional arguments
+ QString name;
+ if (args.Length() > 0)
+ name = V8ENGINE()->toString(args[0]);
+
+ v8::Handle<v8::StackTrace> stackTrace =
+ v8::StackTrace::CurrentStackTrace(1, v8::StackTrace::kOverview);
+
+ if (stackTrace->GetFrameCount()) {
+ v8::Local<v8::StackFrame> frame = stackTrace->GetFrame(0);
+
+ QString scriptName = V8ENGINE()->toString(frame->GetScriptName());
+ QString functionName = V8ENGINE()->toString(frame->GetFunctionName());
+ int line = frame->GetLineNumber();
+ int column = frame->GetColumn();
+
+ int value = V8ENGINE()->consoleCountHelper(scriptName, line, column);
+ QString message = name + QLatin1String(": ") + QString::number(value);
+
+ QMessageLogger(qPrintable(scriptName), line,
+ qPrintable(functionName)).debug("%s", qPrintable(message));
+ }
+
+ return v8::Undefined();
+}
+
+v8::Handle<v8::Value> consoleTrace(const v8::Arguments &args)
+{
+ if (args.Length() != 0)
+ V8THROW_ERROR("console.trace(): Invalid arguments");
+
+ QString stack = jsStack();
+
+ v8::Handle<v8::Value> file;
+ v8::Handle<v8::Value> function;
+ int line;
+ jsContext(&file, &line, &function);
+
+ QMessageLogger(*v8::String::AsciiValue(file), line, *v8::String::AsciiValue(function)).debug(
+ "%s", qPrintable(stack));
+ return v8::Undefined();
+}
+
+v8::Handle<v8::Value> consoleWarn(const v8::Arguments &args)
+{
+ return console(Warn, args);
+}
+
+v8::Handle<v8::Value> consoleAssert(const v8::Arguments &args)
+{
+ if (args.Length() == 0)
+ V8THROW_ERROR("console.assert(): Missing argument");
+
+ if (!args[0]->ToBoolean()->Value()) {
+ QString message;
+ for (int i = 1; i < args.Length(); ++i) {
+ if (i != 1)
+ message.append(QLatin1Char(' '));
+
+ v8::Local<v8::Value> value = args[i];
+ message.append(V8ENGINE()->toString(value->ToString()));
+ }
+
+ QString stack = jsStack();
+
+ v8::Handle<v8::Value> file;
+ v8::Handle<v8::Value> function;
+ int line;
+ jsContext(&file, &line, &function);
+
+ QMessageLogger(*v8::String::AsciiValue(file), line, *v8::String::AsciiValue(function)).critical(
+ "%s\n%s", qPrintable(message), qPrintable(stack));
+
+ }
+ return v8::Undefined();
+}
+
+v8::Handle<v8::Value> consoleException(const v8::Arguments &args)
+{
+ if (args.Length() == 0)
+ V8THROW_ERROR("console.exception(): Missing argument");
+
+ console(Error, args, true);
+
+ return v8::Undefined();
+}
+
+v8::Handle<v8::Value> stringArg(const v8::Arguments &args)
+{
+ QString value = V8ENGINE()->toString(args.This()->ToString());
+ if (args.Length() != 1)
+ V8THROW_ERROR("String.arg(): Invalid arguments");
+
+ v8::Handle<v8::Value> arg = args[0];
+ if (arg->IsUint32())
+ return V8ENGINE()->toString(value.arg(arg->Uint32Value()));
+ else if (arg->IsInt32())
+ return V8ENGINE()->toString(value.arg(arg->Int32Value()));
+ else if (arg->IsNumber())
+ return V8ENGINE()->toString(value.arg(arg->NumberValue()));
+ else if (arg->IsBoolean())
+ return V8ENGINE()->toString(value.arg(arg->BooleanValue()));
+
+ return V8ENGINE()->toString(value.arg(V8ENGINE()->toString(arg)));
+}
+
+/*!
+\qmlmethod bool Qt::isQtObject(object)
+Returns true if \c object is a valid reference to a Qt or QML object, otherwise false.
+*/
+v8::Handle<v8::Value> isQtObject(const v8::Arguments &args)
+{
+ if (args.Length() == 0)
+ return v8::Boolean::New(false);
+
+ return v8::Boolean::New(0 != V8ENGINE()->toQObject(args[0]));
+}
+
+/*!
+\qmlmethod color Qt::rgba(real red, real green, real blue, real alpha)
+
+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.
+*/
+v8::Handle<v8::Value> rgba(const v8::Arguments &args)
+{
+ int argCount = args.Length();
+ if (argCount < 3 || argCount > 4)
+ V8THROW_ERROR("Qt.rgba(): Invalid arguments");
+
+ double r = args[0]->NumberValue();
+ double g = args[1]->NumberValue();
+ double b = args[2]->NumberValue();
+ double a = (argCount == 4) ? args[3]->NumberValue() : 1;
+
+ if (r < 0.0) r=0.0;
+ if (r > 1.0) r=1.0;
+ if (g < 0.0) g=0.0;
+ if (g > 1.0) g=1.0;
+ if (b < 0.0) b=0.0;
+ if (b > 1.0) b=1.0;
+ if (a < 0.0) a=0.0;
+ if (a > 1.0) a=1.0;
+
+ return V8ENGINE()->fromVariant(QVariant::fromValue(QColor::fromRgbF(r, g, b, a)));
+}
+
+/*!
+\qmlmethod color Qt::hsla(real hue, real saturation, real lightness, real alpha)
+
+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.
+*/
+v8::Handle<v8::Value> hsla(const v8::Arguments &args)
+{
+ int argCount = args.Length();
+ if (argCount < 3 || argCount > 4)
+ V8THROW_ERROR("Qt.hsla(): Invalid arguments");
+
+ double h = args[0]->NumberValue();
+ double s = args[1]->NumberValue();
+ double l = args[2]->NumberValue();
+ double a = (argCount == 4) ? args[3]->NumberValue() : 1;
+
+ if (h < 0.0) h=0.0;
+ if (h > 1.0) h=1.0;
+ if (s < 0.0) s=0.0;
+ if (s > 1.0) s=1.0;
+ if (l < 0.0) l=0.0;
+ if (l > 1.0) l=1.0;
+ if (a < 0.0) a=0.0;
+ if (a > 1.0) a=1.0;
+
+ return V8ENGINE()->fromVariant(QVariant::fromValue(QColor::fromHslF(h, s, l, a)));
+}
+
+/*!
+\qmlmethod rect Qt::rect(int x, int y, int width, int height)
+
+Returns a \c rect with the top-left corner at \c x, \c y and the specified \c width and \c height.
+
+The returned object has \c x, \c y, \c width and \c height attributes with the given values.
+*/
+v8::Handle<v8::Value> rect(const v8::Arguments &args)
+{
+ if (args.Length() != 4)
+ V8THROW_ERROR("Qt.rect(): Invalid arguments");
+
+ double x = args[0]->NumberValue();
+ double y = args[1]->NumberValue();
+ double w = args[2]->NumberValue();
+ double h = args[3]->NumberValue();
+
+ return V8ENGINE()->fromVariant(QVariant::fromValue(QRectF(x, y, w, h)));
+}
+
+/*!
+\qmlmethod point Qt::point(int x, int y)
+Returns a Point with the specified \c x and \c y coordinates.
+*/
+v8::Handle<v8::Value> point(const v8::Arguments &args)
+{
+ if (args.Length() != 2)
+ V8THROW_ERROR("Qt.point(): Invalid arguments");
+
+ double x = args[0]->ToNumber()->Value();
+ double y = args[1]->ToNumber()->Value();
+
+ return V8ENGINE()->fromVariant(QVariant::fromValue(QPointF(x, y)));
+}
+
+/*!
+\qmlmethod Qt::size(int width, int height)
+Returns a Size with the specified \c width and \c height.
+*/
+v8::Handle<v8::Value> size(const v8::Arguments &args)
+{
+ if (args.Length() != 2)
+ V8THROW_ERROR("Qt.size(): Invalid arguments");
+
+ double w = args[0]->ToNumber()->Value();
+ double h = args[1]->ToNumber()->Value();
+
+ return V8ENGINE()->fromVariant(QVariant::fromValue(QSizeF(w, h)));
+}
+
+/*!
+\qmlmethod Qt::vector3d(real x, real y, real z)
+Returns a Vector3D with the specified \c x, \c y and \c z.
+*/
+v8::Handle<v8::Value> vector3d(const v8::Arguments &args)
+{
+ if (args.Length() != 3)
+ V8THROW_ERROR("Qt.vector(): Invalid arguments");
+
+ double x = args[0]->ToNumber()->Value();
+ double y = args[1]->ToNumber()->Value();
+ double z = args[2]->ToNumber()->Value();
+
+ return V8ENGINE()->fromVariant(QVariant::fromValue(QVector3D(x, y, z)));
+}
+
+/*!
+\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.
+*/
+v8::Handle<v8::Value> vector4d(const v8::Arguments &args)
+{
+ if (args.Length() != 4)
+ V8THROW_ERROR("Qt.vector4d(): Invalid arguments");
+
+ double x = args[0]->NumberValue();
+ double y = args[1]->NumberValue();
+ double z = args[2]->NumberValue();
+ double w = args[3]->NumberValue();
+
+ return V8ENGINE()->fromVariant(QVariant::fromValue(QVector4D(x, y, z, w)));
+}
+
+/*!
+\qmlmethod color Qt::lighter(color baseColor, real factor)
+Returns a color lighter than \c baseColor by the \c factor provided.
+
+If the factor is greater than 1.0, this functions returns a lighter color.
+Setting factor to 1.5 returns a color that is 50% brighter. If the factor is less than 1.0,
+the return color is darker, but we recommend using the Qt.darker() function for this purpose.
+If the factor is 0 or negative, the return value is unspecified.
+
+The function converts the current RGB color to HSV, multiplies the value (V) component
+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).
+*/
+v8::Handle<v8::Value> lighter(const v8::Arguments &args)
+{
+ if (args.Length() != 1 && args.Length() != 2)
+ V8THROW_ERROR("Qt.lighter(): Invalid arguments");
+
+ QColor color;
+ QVariant v = V8ENGINE()->toVariant(args[0], -1);
+ if (v.userType() == QVariant::Color) {
+ color = v.value<QColor>();
+ } else if (v.userType() == QVariant::String) {
+ bool ok = false;
+ color = QQmlStringConverters::colorFromString(v.toString(), &ok);
+ if (!ok) {
+ return v8::Null();
+ }
+ } else {
+ return v8::Null();
+ }
+
+ qreal factor = 1.5;
+ if (args.Length() == 2)
+ factor = args[1]->ToNumber()->Value();
+
+ color = color.lighter(int(qRound(factor*100.)));
+ return V8ENGINE()->fromVariant(QVariant::fromValue(color));
+}
+
+/*!
+\qmlmethod color Qt::darker(color baseColor, real factor)
+Returns a color darker than \c baseColor by the \c factor provided.
+
+If the factor is greater than 1.0, this function returns a darker color.
+Setting factor to 3.0 returns a color that has one-third the brightness.
+If the factor is less than 1.0, the return color is lighter, but we recommend using
+the Qt.lighter() function for this purpose. If the factor is 0 or negative, the return
+value is unspecified.
+
+The function converts the current RGB color to HSV, divides the value (V) component
+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).
+*/
+v8::Handle<v8::Value> darker(const v8::Arguments &args)
+{
+ if (args.Length() != 1 && args.Length() != 2)
+ V8THROW_ERROR("Qt.darker(): Invalid arguments");
+
+ QColor color;
+ QVariant v = V8ENGINE()->toVariant(args[0], -1);
+ if (v.userType() == QVariant::Color) {
+ color = v.value<QColor>();
+ } else if (v.userType() == QVariant::String) {
+ bool ok = false;
+ color = QQmlStringConverters::colorFromString(v.toString(), &ok);
+ if (!ok) {
+ return v8::Null();
+ }
+ } else {
+ return v8::Null();
+ }
+
+ qreal factor = 2.0;
+ if (args.Length() == 2)
+ factor = args[1]->ToNumber()->Value();
+
+ color = color.darker(int(qRound(factor*100.)));
+ return V8ENGINE()->fromVariant(QVariant::fromValue(color));
+}
+
+/*!
+ \qmlmethod color Qt::tint(color baseColor, color tintColor)
+ This function allows tinting one color with another.
+
+ The tint color should usually be mostly transparent, or you will not be
+ able to see the underlying color. The below example provides a slight red
+ tint by having the tint color be pure red which is only 1/16th opaque.
+
+ \qml
+ Item {
+ Rectangle {
+ x: 0; width: 80; height: 80
+ color: "lightsteelblue"
+ }
+ Rectangle {
+ x: 100; width: 80; height: 80
+ color: Qt.tint("lightsteelblue", "#10FF0000")
+ }
+ }
+ \endqml
+ \image declarative-rect_tint.png
+
+ 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.
+*/
+v8::Handle<v8::Value> tint(const v8::Arguments &args)
+{
+ if (args.Length() != 2)
+ V8THROW_ERROR("Qt.tint(): Invalid arguments");
+
+ // base color
+ QColor color;
+ QVariant v = V8ENGINE()->toVariant(args[0], -1);
+ if (v.userType() == QVariant::Color) {
+ color = v.value<QColor>();
+ } else if (v.userType() == QVariant::String) {
+ bool ok = false;
+ color = QQmlStringConverters::colorFromString(v.toString(), &ok);
+ if (!ok) {
+ return v8::Null();
+ }
+ } else {
+ return v8::Null();
+ }
+
+ // tint color
+ QColor tintColor;
+ v = V8ENGINE()->toVariant(args[1], -1);
+ if (v.userType() == QVariant::Color) {
+ tintColor = v.value<QColor>();
+ } else if (v.userType() == QVariant::String) {
+ bool ok = false;
+ tintColor = QQmlStringConverters::colorFromString(v.toString(), &ok);
+ if (!ok) {
+ return v8::Null();
+ }
+ } else {
+ return v8::Null();
+ }
+
+ // tint the base color and return the final color
+ QColor finalColor;
+ int a = tintColor.alpha();
+ if (a == 0xFF)
+ finalColor = tintColor;
+ else if (a == 0x00)
+ finalColor = color;
+ else {
+ qreal a = tintColor.alphaF();
+ qreal inv_a = 1.0 - a;
+
+ finalColor.setRgbF(tintColor.redF() * a + color.redF() * inv_a,
+ tintColor.greenF() * a + color.greenF() * inv_a,
+ tintColor.blueF() * a + color.blueF() * inv_a,
+ a + inv_a * color.alphaF());
+ }
+
+ return V8ENGINE()->fromVariant(QVariant::fromValue(finalColor));
+}
+
+/*!
+\qmlmethod string Qt::formatDate(datetime date, variant format)
+
+Returns a string representation of \c date, optionally formatted according
+to \c format.
+
+The \a date parameter may be a JavaScript \c Date object, a \l{date}{date}
+property, a QDate, or QDateTime value. The \a format parameter may be any of
+the possible format values as described for
+\l{QML:Qt::formatDateTime()}{Qt.formatDateTime()}.
+
+If \a format is not specified, \a date is formatted using
+\l {Qt::DefaultLocaleShortDate}{Qt.DefaultLocaleShortDate}.
+
+\sa Locale
+*/
+v8::Handle<v8::Value> formatDate(const v8::Arguments &args)
+{
+ if (args.Length() < 1 || args.Length() > 2)
+ V8THROW_ERROR("Qt.formatDate(): Invalid arguments");
+
+ Qt::DateFormat enumFormat = Qt::DefaultLocaleShortDate;
+ QDate date = V8ENGINE()->toVariant(args[0], -1).toDateTime().date();
+ QString formattedDate;
+ if (args.Length() == 2) {
+ if (args[1]->IsString()) {
+ QString format = V8ENGINE()->toVariant(args[1], -1).toString();
+ formattedDate = date.toString(format);
+ } else if (args[1]->IsNumber()) {
+ quint32 intFormat = args[1]->ToNumber()->Value();
+ Qt::DateFormat format = Qt::DateFormat(intFormat);
+ formattedDate = date.toString(format);
+ } else {
+ V8THROW_ERROR("Qt.formatDate(): Invalid date format");
+ }
+ } else {
+ formattedDate = date.toString(enumFormat);
+ }
+
+ return V8ENGINE()->fromVariant(QVariant::fromValue(formattedDate));
+}
+
+/*!
+\qmlmethod string Qt::formatTime(datetime time, variant format)
+
+Returns a string representation of \c time, optionally formatted according to
+\c format.
+
+The \a time parameter may be a JavaScript \c Date object, a QTime, or QDateTime
+value. The \a format parameter may be any of the possible format values as
+described for \l{QML:Qt::formatDateTime()}{Qt.formatDateTime()}.
+
+If \a format is not specified, \a time is formatted using
+\l {Qt::DefaultLocaleShortDate}{Qt.DefaultLocaleShortDate}.
+
+\sa Locale
+*/
+v8::Handle<v8::Value> formatTime(const v8::Arguments &args)
+{
+ if (args.Length() < 1 || args.Length() > 2)
+ V8THROW_ERROR("Qt.formatTime(): Invalid arguments");
+
+ QVariant argVariant = V8ENGINE()->toVariant(args[0], -1);
+ QTime time;
+ if (args[0]->IsDate() || (argVariant.type() == QVariant::String))
+ time = argVariant.toDateTime().time();
+ else // if (argVariant.type() == QVariant::Time), or invalid.
+ time = argVariant.toTime();
+
+ Qt::DateFormat enumFormat = Qt::DefaultLocaleShortDate;
+ QString formattedTime;
+ if (args.Length() == 2) {
+ if (args[1]->IsString()) {
+ QString format = V8ENGINE()->toVariant(args[1], -1).toString();
+ formattedTime = time.toString(format);
+ } else if (args[1]->IsNumber()) {
+ quint32 intFormat = args[1]->ToNumber()->Value();
+ Qt::DateFormat format = Qt::DateFormat(intFormat);
+ formattedTime = time.toString(format);
+ } else {
+ V8THROW_ERROR("Qt.formatTime(): Invalid time format");
+ }
+ } else {
+ formattedTime = time.toString(enumFormat);
+ }
+
+ return V8ENGINE()->fromVariant(QVariant::fromValue(formattedTime));
+}
+
+/*!
+\qmlmethod string Qt::formatDateTime(datetime dateTime, variant format)
+
+Returns a string representation of \c datetime, optionally formatted according to
+\c format.
+
+The \a date parameter may be a JavaScript \c Date object, a \l{date}{date}
+property, a QDate, QTime, or QDateTime value.
+
+If \a format is not provided, \a dateTime is formatted using
+\l {Qt::DefaultLocaleShortDate}{Qt.DefaultLocaleShortDate}. Otherwise,
+\a format should be either:
+
+\list
+\o One of the Qt::DateFormat enumeration values, such as
+ \c Qt.DefaultLocaleShortDate or \c Qt.ISODate
+\o A string that specifies the format of the returned string, as detailed below.
+\endlist
+
+If \a format specifies a format string, it should use the following expressions
+to specify the date:
+
+ \table
+ \header \i Expression \i Output
+ \row \i d \i the day as number without a leading zero (1 to 31)
+ \row \i dd \i the day as number with a leading zero (01 to 31)
+ \row \i ddd
+ \i the abbreviated localized day name (e.g. 'Mon' to 'Sun').
+ Uses QDate::shortDayName().
+ \row \i dddd
+ \i the long localized day name (e.g. 'Monday' to 'Qt::Sunday').
+ Uses QDate::longDayName().
+ \row \i M \i the month as number without a leading zero (1-12)
+ \row \i MM \i the month as number with a leading zero (01-12)
+ \row \i MMM
+ \i the abbreviated localized month name (e.g. 'Jan' to 'Dec').
+ Uses QDate::shortMonthName().
+ \row \i MMMM
+ \i the long localized month name (e.g. 'January' to 'December').
+ Uses QDate::longMonthName().
+ \row \i yy \i the year as two digit number (00-99)
+ \row \i yyyy \i the year as four digit number
+ \endtable
+
+In addition the following expressions can be used to specify the time:
+
+ \table
+ \header \i Expression \i Output
+ \row \i h
+ \i the hour without a leading zero (0 to 23 or 1 to 12 if AM/PM display)
+ \row \i hh
+ \i the hour with a leading zero (00 to 23 or 01 to 12 if AM/PM display)
+ \row \i m \i the minute without a leading zero (0 to 59)
+ \row \i mm \i the minute with a leading zero (00 to 59)
+ \row \i s \i the second without a leading zero (0 to 59)
+ \row \i ss \i the second with a leading zero (00 to 59)
+ \row \i z \i the milliseconds without leading zeroes (0 to 999)
+ \row \i zzz \i the milliseconds with leading zeroes (000 to 999)
+ \row \i AP
+ \i use AM/PM display. \e AP will be replaced by either "AM" or "PM".
+ \row \i ap
+ \i use am/pm display. \e ap will be replaced by either "am" or "pm".
+ \endtable
+
+ All other input characters will be ignored. Any sequence of characters that
+ are enclosed in single quotes will be treated as text and not be used as an
+ expression. Two consecutive single quotes ("''") are replaced by a single quote
+ in the output.
+
+For example, if the following date/time value was specified:
+
+ \code
+ // 21 May 2001 14:13:09
+ var dateTime = new Date(2001, 5, 21, 14, 13, 09)
+ \endcode
+
+This \a dateTime value could be passed to \c Qt.formatDateTime(),
+\l {QML:Qt::formatDate()}{Qt.formatDate()} or \l {QML:Qt::formatTime()}{Qt.formatTime()}
+with the \a format values below to produce the following results:
+
+ \table
+ \header \i Format \i Result
+ \row \i "dd.MM.yyyy" \i 21.05.2001
+ \row \i "ddd MMMM d yy" \i Tue May 21 01
+ \row \i "hh:mm:ss.zzz" \i 14:13:09.042
+ \row \i "h:m:s ap" \i 2:13:9 pm
+ \endtable
+
+ \sa Locale
+*/
+v8::Handle<v8::Value> formatDateTime(const v8::Arguments &args)
+{
+ if (args.Length() < 1 || args.Length() > 2)
+ V8THROW_ERROR("Qt.formatDateTime(): Invalid arguments");
+
+ Qt::DateFormat enumFormat = Qt::DefaultLocaleShortDate;
+ QDateTime dt = V8ENGINE()->toVariant(args[0], -1).toDateTime();
+ QString formattedDt;
+ if (args.Length() == 2) {
+ if (args[1]->IsString()) {
+ QString format = V8ENGINE()->toVariant(args[1], -1).toString();
+ formattedDt = dt.toString(format);
+ } else if (args[1]->IsNumber()) {
+ quint32 intFormat = args[1]->ToNumber()->Value();
+ Qt::DateFormat format = Qt::DateFormat(intFormat);
+ formattedDt = dt.toString(format);
+ } else {
+ V8THROW_ERROR("Qt.formatDateTime(): Invalid datetime format");
+ }
+ } else {
+ formattedDt = dt.toString(enumFormat);
+ }
+
+ return V8ENGINE()->fromVariant(QVariant::fromValue(formattedDt));
+}
+
+/*!
+\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.
+*/
+v8::Handle<v8::Value> openUrlExternally(const v8::Arguments &args)
+{
+ if (args.Length() != 1)
+ return V8ENGINE()->fromVariant(false);
+
+ bool ret = false;
+#ifndef QT_NO_DESKTOPSERVICES
+ ret = QDesktopServices::openUrl(V8ENGINE()->toVariant(resolvedUrl(args), -1).toUrl());
+#endif
+ return V8ENGINE()->fromVariant(ret);
+}
+
+/*!
+ \qmlmethod url Qt::resolvedUrl(url url)
+ Returns \a url resolved relative to the URL of the caller.
+*/
+v8::Handle<v8::Value> resolvedUrl(const v8::Arguments &args)
+{
+ QUrl url = V8ENGINE()->toVariant(args[0], -1).toUrl();
+ QQmlEngine *e = V8ENGINE()->engine();
+ QQmlEnginePrivate *p = 0;
+ if (e) p = QQmlEnginePrivate::get(e);
+ if (p) {
+ QQmlContextData *ctxt = V8ENGINE()->callingContext();
+ if (ctxt)
+ return V8ENGINE()->toString(ctxt->resolvedUrl(url).toString());
+ else
+ return V8ENGINE()->toString(url.toString());
+ }
+
+ return V8ENGINE()->toString(e->baseUrl().resolved(url).toString());
+}
+
+/*!
+\qmlmethod list<string> Qt::fontFamilies()
+Returns a list of the font families available to the application.
+*/
+v8::Handle<v8::Value> fontFamilies(const v8::Arguments &args)
+{
+ if (args.Length() != 0)
+ V8THROW_ERROR("Qt.fontFamilies(): Invalid arguments");
+
+ QFontDatabase database;
+ return V8ENGINE()->fromVariant(database.families());
+}
+
+/*!
+\qmlmethod string Qt::md5(data)
+Returns a hex string of the md5 hash of \c data.
+*/
+v8::Handle<v8::Value> md5(const v8::Arguments &args)
+{
+ if (args.Length() != 1)
+ V8THROW_ERROR("Qt.md5(): Invalid arguments");
+
+ QByteArray data = V8ENGINE()->toString(args[0]->ToString()).toUtf8();
+ QByteArray result = QCryptographicHash::hash(data, QCryptographicHash::Md5);
+ return V8ENGINE()->toString(QLatin1String(result.toHex()));
+}
+
+/*!
+\qmlmethod string Qt::btoa(data)
+Binary to ASCII - this function returns a base64 encoding of \c data.
+*/
+v8::Handle<v8::Value> btoa(const v8::Arguments &args)
+{
+ if (args.Length() != 1)
+ V8THROW_ERROR("Qt.btoa(): Invalid arguments");
+
+ QByteArray data = V8ENGINE()->toString(args[0]->ToString()).toUtf8();
+
+ return V8ENGINE()->toString(QLatin1String(data.toBase64()));
+}
+
+/*!
+\qmlmethod string Qt::atob(data)
+ASCII to binary - this function returns a base64 decoding of \c data.
+*/
+v8::Handle<v8::Value> atob(const v8::Arguments &args)
+{
+ if (args.Length() != 1)
+ V8THROW_ERROR("Qt.atob(): Invalid arguments");
+
+ QByteArray data = V8ENGINE()->toString(args[0]->ToString()).toUtf8();
+
+ return V8ENGINE()->toString(QLatin1String(QByteArray::fromBase64(data)));
+}
+
+/*!
+\qmlmethod Qt::quit()
+This function causes the QQmlEngine::quit() signal to be emitted.
+Within the \l {QML Viewer}, this causes the launcher application to exit;
+to quit a C++ application when this method is called, connect the
+QQmlEngine::quit() signal to the QCoreApplication::quit() slot.
+*/
+v8::Handle<v8::Value> quit(const v8::Arguments &args)
+{
+ QQmlEnginePrivate::get(V8ENGINE()->engine())->sendQuit();
+ return v8::Undefined();
+}
+
+/*!
+\qmlmethod object Qt::createQmlObject(string qml, object parent, string filepath)
+
+Returns a new object created from the given \a string of QML which will have the specified \a parent,
+or \c null if there was an error in creating the object.
+
+If \a filepath is specified, it will be used for error reporting for the created object.
+
+Example (where \c parentItem is the id of an existing QML item):
+
+\snippet doc/src/snippets/qml/createQmlObject.qml 0
+
+In the case of an error, a QtScript Error object is thrown. This object has an additional property,
+\c qmlErrors, which is an array of the errors encountered.
+Each object in this array has the members \c lineNumber, \c columnNumber, \c fileName and \c message.
+For example, if the above snippet had misspelled color as 'colro' then the array would contain an object like the following:
+{ "lineNumber" : 1, "columnNumber" : 32, "fileName" : "dynamicSnippet1", "message" : "Cannot assign to non-existent property \"colro\""}.
+
+Note that this function returns immediately, and therefore may not work if
+the \a qml string loads new components (that is, external QML files that have not yet been loaded).
+If this is the case, consider using \l{QML:Qt::createComponent()}{Qt.createComponent()} instead.
+
+See \l {Dynamic Object Management in QML} for more information on using this function.
+*/
+v8::Handle<v8::Value> createQmlObject(const v8::Arguments &args)
+{
+ if (args.Length() < 2 || args.Length() > 3)
+ V8THROW_ERROR("Qt.createQmlObject(): Invalid arguments");
+
+ struct Error {
+ static v8::Local<v8::Value> create(QV8Engine *engine, const QList<QQmlError> &errors) {
+ QString errorstr = QLatin1String("Qt.createQmlObject(): failed to create object: ");
+
+ v8::Local<v8::Array> qmlerrors = v8::Array::New(errors.count());
+ for (int ii = 0; ii < errors.count(); ++ii) {
+ const QQmlError &error = errors.at(ii);
+ errorstr += QLatin1String("\n ") + error.toString();
+ v8::Local<v8::Object> qmlerror = v8::Object::New();
+ qmlerror->Set(v8::String::New("lineNumber"), v8::Integer::New(error.line()));
+ qmlerror->Set(v8::String::New("columnNumber"), v8::Integer::New(error.column()));
+ qmlerror->Set(v8::String::New("fileName"), engine->toString(error.url().toString()));
+ qmlerror->Set(v8::String::New("message"), engine->toString(error.description()));
+ qmlerrors->Set(ii, qmlerror);
+ }
+
+ v8::Local<v8::Value> error = v8::Exception::Error(engine->toString(errorstr));
+ v8::Local<v8::Object> errorObject = error->ToObject();
+ errorObject->Set(v8::String::New("qmlErrors"), qmlerrors);
+ return error;
+ }
+ };
+
+ QV8Engine *v8engine = V8ENGINE();
+ QQmlEngine *engine = v8engine->engine();
+
+ QQmlContextData *context = v8engine->callingContext();
+ QQmlContext *effectiveContext = 0;
+ if (context->isPragmaLibraryContext)
+ effectiveContext = engine->rootContext();
+ else
+ effectiveContext = context->asQQmlContext();
+ Q_ASSERT(context && effectiveContext);
+
+ QString qml = v8engine->toString(args[0]->ToString());
+ if (qml.isEmpty())
+ return v8::Null();
+
+ QUrl url;
+ if (args.Length() > 2)
+ url = QUrl(v8engine->toString(args[2]->ToString()));
+ else
+ url = QUrl(QLatin1String("inline"));
+
+ if (url.isValid() && url.isRelative())
+ url = context->resolvedUrl(url);
+
+ QObject *parentArg = v8engine->toQObject(args[1]);
+ if (!parentArg)
+ V8THROW_ERROR("Qt.createQmlObject(): Missing parent object");
+
+ QQmlComponent component(engine);
+ component.setData(qml.toUtf8(), url);
+
+ if (component.isError()) {
+ v8::ThrowException(Error::create(v8engine, component.errors()));
+ return v8::Undefined();
+ }
+
+ if (!component.isReady())
+ V8THROW_ERROR("Qt.createQmlObject(): Component is not ready");
+
+ QObject *obj = component.beginCreate(effectiveContext);
+ if (obj)
+ QQmlData::get(obj, true)->setImplicitDestructible();
+ component.completeCreate();
+
+ if (component.isError()) {
+ v8::ThrowException(Error::create(v8engine, component.errors()));
+ return v8::Undefined();
+ }
+
+ Q_ASSERT(obj);
+
+ obj->setParent(parentArg);
+
+ QList<QQmlPrivate::AutoParentFunction> functions = QQmlMetaType::parentFunctions();
+ for (int ii = 0; ii < functions.count(); ++ii) {
+ if (QQmlPrivate::Parented == functions.at(ii)(obj, parentArg))
+ break;
+ }
+
+ return v8engine->newQObject(obj);
+}
+
+/*!
+\qmlmethod object Qt::createComponent(url)
+
+Returns a \l Component object created using the QML file at the specified \a url,
+or \c null if an empty string was given.
+
+The returned component's \l Component::status property indicates whether the
+component was successfully created. If the status is \c Component.Error,
+see \l Component::errorString() for an error description.
+
+Call \l {Component::createObject()}{Component.createObject()} on the returned
+component to create an object instance of the component.
+
+For example:
+
+\snippet doc/src/snippets/qml/createComponent-simple.qml 0
+
+See \l {Dynamic Object Management in QML} for more information on using this function.
+
+To create a QML object from an arbitrary string of QML (instead of a file),
+use \l{QML:Qt::createQmlObject()}{Qt.createQmlObject()}.
+*/
+v8::Handle<v8::Value> createComponent(const v8::Arguments &args)
+{
+ if (args.Length() != 1)
+ V8THROW_ERROR("Qt.createComponent(): Invalid arguments");
+
+ QV8Engine *v8engine = V8ENGINE();
+ QQmlEngine *engine = v8engine->engine();
+
+ QQmlContextData *context = v8engine->callingContext();
+ QQmlContextData *effectiveContext = context;
+ if (context->isPragmaLibraryContext)
+ effectiveContext = 0;
+ Q_ASSERT(context);
+
+ QString arg = v8engine->toString(args[0]->ToString());
+ if (arg.isEmpty())
+ return v8::Null();
+
+ QUrl url = context->resolvedUrl(QUrl(arg));
+ QQmlComponent *c = new QQmlComponent(engine, url, engine);
+ QQmlComponentPrivate::get(c)->creationContext = effectiveContext;
+ QQmlData::get(c, true)->setImplicitDestructible();
+ return v8engine->newQObject(c);
+}
+
+v8::Handle<v8::Value> qsTranslate(const v8::Arguments &args)
+{
+ if (args.Length() < 2)
+ V8THROW_ERROR("qsTranslate() requires at least two arguments");
+ if (!args[0]->IsString())
+ V8THROW_ERROR("qsTranslate(): first argument (context) must be a string");
+ if (!args[1]->IsString())
+ V8THROW_ERROR("qsTranslate(): second argument (text) must be a string");
+ if ((args.Length() > 2) && !args[2]->IsString())
+ V8THROW_ERROR("qsTranslate(): third argument (comment) must be a string");
+ if ((args.Length() > 3) && !args[3]->IsString())
+ V8THROW_ERROR("qsTranslate(): fourth argument (encoding) must be a string");
+
+ QV8Engine *v8engine = V8ENGINE();
+ QString context = v8engine->toString(args[0]);
+ QString text = v8engine->toString(args[1]);
+ QString comment;
+ if (args.Length() > 2) comment = v8engine->toString(args[2]);
+
+ QCoreApplication::Encoding encoding = QCoreApplication::UnicodeUTF8;
+ if (args.Length() > 3) {
+ QString encStr = v8engine->toString(args[3]);
+ if (encStr == QLatin1String("CodecForTr")) {
+ encoding = QCoreApplication::CodecForTr;
+ } else if (encStr == QLatin1String("UnicodeUTF8")) {
+ encoding = QCoreApplication::UnicodeUTF8;
+ } else {
+ QString msg = QString::fromLatin1("qsTranslate(): invalid encoding '%0'").arg(encStr);
+ V8THROW_ERROR((uint16_t *)msg.constData());
+ }
+ }
+
+ int n = -1;
+ if (args.Length() > 4)
+ n = args[4]->Int32Value();
+
+ QString result = QCoreApplication::translate(context.toUtf8().constData(),
+ text.toUtf8().constData(),
+ comment.toUtf8().constData(),
+ encoding, n);
+
+ return v8engine->toString(result);
+}
+
+v8::Handle<v8::Value> qsTranslateNoOp(const v8::Arguments &args)
+{
+ if (args.Length() < 2)
+ return v8::Undefined();
+ return args[1];
+}
+
+v8::Handle<v8::Value> qsTr(const v8::Arguments &args)
+{
+ if (args.Length() < 1)
+ V8THROW_ERROR("qsTr() requires at least one argument");
+ if (!args[0]->IsString())
+ V8THROW_ERROR("qsTr(): first argument (text) must be a string");
+ if ((args.Length() > 1) && !args[1]->IsString())
+ V8THROW_ERROR("qsTr(): second argument (comment) must be a string");
+ if ((args.Length() > 2) && !args[2]->IsNumber())
+ V8THROW_ERROR("qsTr(): third argument (n) must be a number");
+
+ QV8Engine *v8engine = V8ENGINE();
+ QQmlContextData *ctxt = v8engine->callingContext();
+
+ QString path = ctxt->url.toString();
+ int lastSlash = path.lastIndexOf(QLatin1Char('/'));
+ QString context = (lastSlash > -1) ? path.mid(lastSlash + 1, path.length()-lastSlash-5) : QString();
+
+ QString text = v8engine->toString(args[0]);
+ QString comment;
+ if (args.Length() > 1)
+ comment = v8engine->toString(args[1]);
+ int n = -1;
+ if (args.Length() > 2)
+ n = args[2]->Int32Value();
+
+ QString result = QCoreApplication::translate(context.toUtf8().constData(), text.toUtf8().constData(),
+ comment.toUtf8().constData(), QCoreApplication::UnicodeUTF8, n);
+
+ return v8engine->toString(result);
+}
+
+v8::Handle<v8::Value> qsTrNoOp(const v8::Arguments &args)
+{
+ if (args.Length() < 1)
+ return v8::Undefined();
+ return args[0];
+}
+
+v8::Handle<v8::Value> qsTrId(const v8::Arguments &args)
+{
+ if (args.Length() < 1)
+ V8THROW_ERROR("qsTrId() requires at least one argument");
+ if (!args[0]->IsString())
+ V8THROW_TYPE("qsTrId(): first argument (id) must be a string");
+ if (args.Length() > 1 && !args[1]->IsNumber())
+ V8THROW_TYPE("qsTrId(): second argument (n) must be a number");
+
+ int n = -1;
+ if (args.Length() > 1)
+ n = args[1]->Int32Value();
+
+ QV8Engine *v8engine = V8ENGINE();
+ return v8engine->toString(qtTrId(v8engine->toString(args[0]).toUtf8().constData(), n));
+}
+
+v8::Handle<v8::Value> qsTrIdNoOp(const v8::Arguments &args)
+{
+ if (args.Length() < 1)
+ return v8::Undefined();
+ return args[0];
+}
+
+
+/*!
+ \qmlmethod Qt::locale(name)
+
+ Returns a JS object representing the locale with the specified
+ name, which has the format "language[_territory][.codeset][@modifier]"
+ or "C", where:
+
+ \list
+ \o language is a lowercase, two-letter, ISO 639 language code,
+ \o territory is an uppercase, two-letter, ISO 3166 country code,
+ \o and codeset and modifier are ignored.
+ \endlist
+
+ If the string violates the locale format, or language is not a
+ valid ISO 369 code, the "C" locale is used instead. If country
+ is not present, or is not a valid ISO 3166 code, the most
+ appropriate country is chosen for the specified language.
+
+ \sa QtQuick2::Locale
+*/
+v8::Handle<v8::Value> locale(const v8::Arguments &args)
+{
+ QString code;
+ if (args.Length() > 1)
+ V8THROW_ERROR("locale() requires 0 or 1 argument");
+ if (args.Length() == 1 && !args[0]->IsString())
+ V8THROW_TYPE("locale(): argument (locale code) must be a string");
+
+ QV8Engine *v8engine = V8ENGINE();
+ if (args.Length() == 1)
+ code = v8engine->toString(args[0]);
+
+ return QQmlLocale::locale(v8engine, code);
+}
+
+} // namespace QQmlBuiltinFunctions
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/v8/qqmlbuiltinfunctions_p.h b/src/qml/qml/v8/qqmlbuiltinfunctions_p.h
new file mode 100644
index 0000000000..ddb1c64243
--- /dev/null
+++ b/src/qml/qml/v8/qqmlbuiltinfunctions_p.h
@@ -0,0 +1,110 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLBUILTINFUNCTIONS_P_H
+#define QQMLBUILTINFUNCTIONS_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qglobal.h>
+#include <private/qv8_p.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace QQmlBuiltinFunctions
+{
+v8::Handle<v8::Value> gc(const v8::Arguments &args);
+v8::Handle<v8::Value> consoleError(const v8::Arguments &args);
+v8::Handle<v8::Value> consoleLog(const v8::Arguments &args);
+v8::Handle<v8::Value> consoleProfile(const v8::Arguments &args);
+v8::Handle<v8::Value> consoleProfileEnd(const v8::Arguments &args);
+v8::Handle<v8::Value> consoleTime(const v8::Arguments &args);
+v8::Handle<v8::Value> consoleTimeEnd(const v8::Arguments &args);
+v8::Handle<v8::Value> consoleCount(const v8::Arguments &args);
+v8::Handle<v8::Value> consoleTrace(const v8::Arguments &args);
+v8::Handle<v8::Value> consoleWarn(const v8::Arguments &args);
+v8::Handle<v8::Value> consoleAssert(const v8::Arguments &args);
+v8::Handle<v8::Value> consoleException(const v8::Arguments &args);
+v8::Handle<v8::Value> isQtObject(const v8::Arguments &args);
+v8::Handle<v8::Value> rgba(const v8::Arguments &args);
+v8::Handle<v8::Value> hsla(const v8::Arguments &args);
+v8::Handle<v8::Value> rect(const v8::Arguments &args);
+v8::Handle<v8::Value> point(const v8::Arguments &args);
+v8::Handle<v8::Value> size(const v8::Arguments &args);
+v8::Handle<v8::Value> vector3d(const v8::Arguments &args);
+v8::Handle<v8::Value> vector4d(const v8::Arguments &args);
+v8::Handle<v8::Value> lighter(const v8::Arguments &args);
+v8::Handle<v8::Value> darker(const v8::Arguments &args);
+v8::Handle<v8::Value> tint(const v8::Arguments &args);
+v8::Handle<v8::Value> formatDate(const v8::Arguments &args);
+v8::Handle<v8::Value> formatTime(const v8::Arguments &args);
+v8::Handle<v8::Value> formatDateTime(const v8::Arguments &args);
+v8::Handle<v8::Value> openUrlExternally(const v8::Arguments &args);
+v8::Handle<v8::Value> fontFamilies(const v8::Arguments &args);
+v8::Handle<v8::Value> md5(const v8::Arguments &args);
+v8::Handle<v8::Value> btoa(const v8::Arguments &args);
+v8::Handle<v8::Value> atob(const v8::Arguments &args);
+v8::Handle<v8::Value> quit(const v8::Arguments &args);
+v8::Handle<v8::Value> resolvedUrl(const v8::Arguments &args);
+v8::Handle<v8::Value> createQmlObject(const v8::Arguments &args);
+v8::Handle<v8::Value> createComponent(const v8::Arguments &args);
+v8::Handle<v8::Value> qsTranslate(const v8::Arguments &args);
+v8::Handle<v8::Value> qsTranslateNoOp(const v8::Arguments &args);
+v8::Handle<v8::Value> qsTr(const v8::Arguments &args);
+v8::Handle<v8::Value> qsTrNoOp(const v8::Arguments &args);
+v8::Handle<v8::Value> qsTrId(const v8::Arguments &args);
+v8::Handle<v8::Value> qsTrIdNoOp(const v8::Arguments &args);
+v8::Handle<v8::Value> stringArg(const v8::Arguments &args);
+v8::Handle<v8::Value> locale(const v8::Arguments &args);
+}
+
+QT_END_NAMESPACE
+
+#endif // QQMLBUILTINFUNCTIONS_P_H
diff --git a/src/qml/qml/v8/qscript_impl_p.h b/src/qml/qml/v8/qscript_impl_p.h
new file mode 100644
index 0000000000..fdbf2f0097
--- /dev/null
+++ b/src/qml/qml/v8/qscript_impl_p.h
@@ -0,0 +1,43 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtScript module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL-ONLY$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** If you have questions regarding the use of this file, please contact
+** us via http://www.qt-project.org/.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// 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.
+//
+
+#ifndef QSCRIPT_IMPL_P_H
+#define QSCRIPT_IMPL_P_H
+
+#include "qv8engine_impl_p.h"
+#include "qjsvalue_impl_p.h"
+#include "qjsvalueiterator_impl_p.h"
+#include "qjsconverter_impl_p.h"
+
+#endif //QSCRIPT_IMPL_P_H
diff --git a/src/qml/qml/v8/qscriptisolate_p.h b/src/qml/qml/v8/qscriptisolate_p.h
new file mode 100644
index 0000000000..4afa74756f
--- /dev/null
+++ b/src/qml/qml/v8/qscriptisolate_p.h
@@ -0,0 +1,71 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtScript module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL-ONLY$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** If you have questions regarding the use of this file, please contact
+** us via http://www.qt-project.org/.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef APIPREAMBLE_P_H
+#define APIPREAMBLE_P_H
+
+#include <private/qv8_p.h>
+#include "qv8engine_p.h"
+
+QT_BEGIN_NAMESPACE
+
+/**
+ \internal
+ Class used to switch to the right isolate. It does the same thing as v8::Isolate::Scope but
+ it checks for a null engine.
+ \attention We decided to put context switching "up" which means that it should be as high
+ as possible on call stack. And it should be switched at most once per public API function call.
+*/
+class QScriptIsolate {
+public:
+ // OperationMode was introduced to reduce number of checking for a null engine pointer. If we
+ // know that given pointer is not null than we should pass NotNullEngine as constructor argument
+ // that would nicely remove checking on compilation time.
+ enum OperationMode {Default, NotNullEngine};
+ inline QScriptIsolate(const QV8Engine *engine, const OperationMode mode = Default)
+ : m_engine(engine)
+ , m_mode(mode)
+ {
+ if (m_mode == NotNullEngine || m_engine) {
+ Q_ASSERT(m_engine);
+ m_engine->context()->Enter();
+ }
+ }
+
+ inline ~QScriptIsolate()
+ {
+ if (m_mode == NotNullEngine || m_engine) {
+ m_engine->context()->Exit();
+ }
+ }
+
+private:
+ Q_DISABLE_COPY(QScriptIsolate);
+ const QV8Engine *m_engine;
+ const OperationMode m_mode;
+};
+
+
+QT_END_NAMESPACE
+
+#endif // APIPREAMBLE_P_H
diff --git a/src/qml/qml/v8/qscriptoriginalglobalobject_p.h b/src/qml/qml/v8/qscriptoriginalglobalobject_p.h
new file mode 100644
index 0000000000..12321cc71a
--- /dev/null
+++ b/src/qml/qml/v8/qscriptoriginalglobalobject_p.h
@@ -0,0 +1,159 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtScript module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL-ONLY$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** If you have questions regarding the use of this file, please contact
+** us via http://www.qt-project.org/.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSCRIPTORIGINALGLOBALOBJECT_P_H
+#define QSCRIPTORIGINALGLOBALOBJECT_P_H
+
+#include "QtCore/qglobal.h"
+#include "qjsvalue_p.h"
+
+#include <private/qv8_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QV8Engine;
+
+/*!
+ \internal
+ This class is a workaround for missing V8 API functionality. This class keeps all important
+ properties of an original (default) global object, so we can use it even if the global object was
+ changed.
+
+ FIXME this class is a container for workarounds :-) it should be replaced by proper API calls.
+
+ The class have to be created on the QV8Engine creation time (before any change got applied to
+ global object).
+
+ \attention All methods (apart from constructor) assumes that a context and a scope are prepared correctly.
+*/
+class QScriptOriginalGlobalObject
+{
+public:
+ inline QScriptOriginalGlobalObject() {}
+ inline void init(v8::Handle<v8::Context> context);
+ inline void destroy();
+
+ inline QJSValuePrivate::PropertyFlags getPropertyFlags(v8::Handle<v8::Object> object, v8::Handle<v8::Value> property);
+ inline v8::Local<v8::Object> getOwnPropertyDescriptor(v8::Handle<v8::Object> object, v8::Handle<v8::Value> property) const;
+ inline bool strictlyEquals(v8::Handle<v8::Object> object);
+private:
+ Q_DISABLE_COPY(QScriptOriginalGlobalObject)
+
+ // Copy of constructors and prototypes used in isType functions.
+ v8::Persistent<v8::Function> m_ownPropertyDescriptor;
+ v8::Persistent<v8::Object> m_globalObject;
+};
+
+void QScriptOriginalGlobalObject::init(v8::Handle<v8::Context> context)
+{
+ // Please notice that engine is not fully initialized at this point.
+
+ v8::Context::Scope contextScope(context);
+
+ v8::HandleScope scope;
+
+ m_globalObject = v8::Persistent<v8::Object>::New(context->Global());
+
+ v8::Local<v8::Object> objectConstructor = m_globalObject->Get(v8::String::New("Object"))->ToObject();
+ Q_ASSERT(objectConstructor->IsObject());
+ { // Initialize m_ownPropertyDescriptor.
+ v8::Local<v8::Value> ownPropertyDescriptor = objectConstructor->Get(v8::String::New("getOwnPropertyDescriptor"));
+ Q_ASSERT(!ownPropertyDescriptor.IsEmpty());
+ m_ownPropertyDescriptor = v8::Persistent<v8::Function>::New(v8::Local<v8::Function>::Cast(ownPropertyDescriptor));
+ }
+}
+
+/*!
+ \internal
+ QScriptOriginalGlobalObject lives as long as QV8Engine that keeps it. In ~QSEP
+ the v8 context is removed, so we need to remove our handlers before. to break this dependency
+ destroy method should be called before or insight QSEP destructor.
+*/
+inline void QScriptOriginalGlobalObject::destroy()
+{
+ m_ownPropertyDescriptor.Dispose();
+ m_globalObject.Dispose();
+ // After this line this instance is unusable.
+}
+
+inline QJSValuePrivate::PropertyFlags QScriptOriginalGlobalObject::getPropertyFlags(v8::Handle<v8::Object> object, v8::Handle<v8::Value> property)
+{
+ Q_ASSERT(object->IsObject());
+ Q_ASSERT(!property.IsEmpty());
+ v8::Local<v8::Object> descriptor = getOwnPropertyDescriptor(object, property);
+ if (descriptor.IsEmpty()) {
+// // Property isn't owned by this object.
+// if (!(mode & QScriptValue::ResolvePrototype))
+// return 0;
+ v8::Local<v8::Value> prototype = object->GetPrototype();
+ if (prototype->IsNull())
+ return 0;
+ return getPropertyFlags(v8::Local<v8::Object>::Cast(prototype), property);
+ }
+ v8::Local<v8::String> writableName = v8::String::New("writable");
+ v8::Local<v8::String> configurableName = v8::String::New("configurable");
+ v8::Local<v8::String> enumerableName = v8::String::New("enumerable");
+// v8::Local<v8::String> getName = v8::String::New("get");
+// v8::Local<v8::String> setName = v8::String::New("set");
+
+ unsigned flags = 0;
+
+ if (!descriptor->Get(configurableName)->BooleanValue())
+ flags |= QJSValuePrivate::Undeletable;
+ if (!descriptor->Get(enumerableName)->BooleanValue())
+ flags |= QJSValuePrivate::SkipInEnumeration;
+
+ //"writable" is only a property of the descriptor if it is not an accessor
+ if (descriptor->Has(writableName)) {
+ if (!descriptor->Get(writableName)->BooleanValue())
+ flags |= QJSValuePrivate::ReadOnly;
+ } else {
+// if (descriptor->Get(getName)->IsObject())
+// flags |= QScriptValue::PropertyGetter;
+// if (descriptor->Get(setName)->IsObject())
+// flags |= QScriptValue::PropertySetter;
+ }
+
+ return QJSValuePrivate::PropertyFlag(flags);
+}
+
+inline v8::Local<v8::Object> QScriptOriginalGlobalObject::getOwnPropertyDescriptor(v8::Handle<v8::Object> object, v8::Handle<v8::Value> property) const
+{
+ Q_ASSERT(object->IsObject());
+ Q_ASSERT(!property.IsEmpty());
+ // FIXME do we need try catch here?
+ v8::Handle<v8::Value> argv[] = {object, property};
+ v8::Local<v8::Value> descriptor = m_ownPropertyDescriptor->Call(m_globalObject, /* argc */ 2, argv);
+ if (descriptor.IsEmpty() || !descriptor->IsObject())
+ return v8::Local<v8::Object>();
+ return v8::Local<v8::Object>::Cast(descriptor);
+}
+
+inline bool QScriptOriginalGlobalObject::strictlyEquals(v8::Handle<v8::Object> object)
+{
+ return m_globalObject->GetPrototype()->StrictEquals(object);
+}
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/qml/qml/v8/qscriptshareddata_p.h b/src/qml/qml/v8/qscriptshareddata_p.h
new file mode 100644
index 0000000000..df95b26206
--- /dev/null
+++ b/src/qml/qml/v8/qscriptshareddata_p.h
@@ -0,0 +1,151 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtScript module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL-ONLY$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** If you have questions regarding the use of this file, please contact
+** us via http://www.qt-project.org/.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// 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.
+//
+
+#ifndef QSCRIPTSHAREDDATA_P_H
+#define QSCRIPTSHAREDDATA_P_H
+
+#include "qglobal.h"
+#include "qshareddata.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \internal
+ This class should have the same interface as the QSharedData, but implementation doesn't
+ need to be thread safe, so atomic ref count was replaced by normal integer value.
+*/
+class QScriptSharedData
+{
+public:
+ class ReferenceCounter {
+ // FIXME shouldn't it be uint or something longer?
+ mutable int m_ref;
+ ReferenceCounter(int ref) : m_ref(ref) {}
+ ~ReferenceCounter() { Q_ASSERT_X(!m_ref, Q_FUNC_INFO, "Memory problem found"); }
+ public:
+ bool ref() { return ++m_ref; }
+ bool deref() { return --m_ref; }
+ friend class QScriptSharedData;
+ };
+
+ ReferenceCounter ref;
+ inline QScriptSharedData() : ref(0) { }
+
+private:
+ Q_DISABLE_COPY(QScriptSharedData)
+};
+
+
+template <class T> class QScriptPassPointer;
+
+// FIXME: that could be reimplemented to not check for a null value.
+template<class T>
+class QScriptSharedDataPointer : public QExplicitlySharedDataPointer<T>
+{
+public:
+ inline QScriptSharedDataPointer() {}
+ explicit QScriptSharedDataPointer(QScriptPassPointer<T> data) : QExplicitlySharedDataPointer<T>(data.give()) {}
+ explicit QScriptSharedDataPointer(T *data) : QExplicitlySharedDataPointer<T>(data) {}
+
+ inline QScriptSharedDataPointer<T> &operator=(const QScriptPassPointer<T> &other)
+ {
+ this->QExplicitlySharedDataPointer<T>::operator =(other.give());
+ return *this;
+ }
+ inline QScriptSharedDataPointer<T> &operator=(T *other)
+ {
+ this->QExplicitlySharedDataPointer<T>::operator =(other);
+ return *this;
+ }
+};
+
+// FIXME: that could be reimplemented to not check for a null value.
+template <class T>
+class QScriptPassPointer {
+public:
+ QScriptPassPointer(T *data) : m_ptr(data) {}
+ inline QScriptPassPointer() { m_ptr = 0; }
+ inline QScriptPassPointer(const QScriptPassPointer<T> &other) : m_ptr(other.give()) {}
+ inline ~QScriptPassPointer() { Q_ASSERT_X(!m_ptr, Q_FUNC_INFO, "Ownership of the QScriptPassPointer hasn't been taken"); }
+
+ inline T &operator*() const { return *m_ptr; }
+ inline T *operator->() { return m_ptr; }
+ inline T *operator->() const { return m_ptr; }
+ inline T *data() const { return m_ptr; }
+ inline const T *constData() const { return m_ptr; }
+
+ inline bool operator==(const QScriptPassPointer<T> &other) const { return m_ptr == other.m_ptr; }
+ inline bool operator!=(const QScriptPassPointer<T> &other) const { return m_ptr != other.m_ptr; }
+ inline bool operator==(const QScriptSharedDataPointer<T> &other) const { return m_ptr == other.m_ptr; }
+ inline bool operator!=(const QScriptSharedDataPointer<T> &other) const { return m_ptr != other.m_ptr; }
+ inline bool operator==(const T *ptr) const { return m_ptr == ptr; }
+ inline bool operator!=(const T *ptr) const { return m_ptr != ptr; }
+
+ inline operator bool () const { return m_ptr != 0; }
+ inline bool operator!() const { return !m_ptr; }
+
+ inline QScriptPassPointer<T> & operator=(const QScriptPassPointer<T> &other)
+ {
+ if (other.m_ptr != m_ptr) {
+ if (m_ptr)
+ delete m_ptr;
+ m_ptr = other.give();
+ }
+ return *this;
+ }
+
+ inline QScriptPassPointer &operator=(T *other)
+ {
+ if (other != m_ptr) {
+ if (m_ptr)
+ delete m_ptr;
+ m_ptr = other;
+ }
+ return *this;
+ }
+
+ inline T* give() const
+ {
+ T* result = m_ptr;
+ m_ptr = 0;
+ return result;
+ }
+
+private:
+ mutable T* m_ptr;
+};
+
+QT_END_NAMESPACE
+
+#endif // QSCRIPTSHAREDDATA_P_H
diff --git a/src/qml/qml/v8/qscripttools_p.h b/src/qml/qml/v8/qscripttools_p.h
new file mode 100644
index 0000000000..fcea205f61
--- /dev/null
+++ b/src/qml/qml/v8/qscripttools_p.h
@@ -0,0 +1,68 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtScript module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL-ONLY$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** If you have questions regarding the use of this file, please contact
+** us via http://www.qt-project.org/.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// 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.
+//
+
+
+#ifndef QSCRIPTTOOLS_P_H
+#define QSCRIPTTOOLS_P_H
+
+#include <private/qintrusivelist_p.h>
+
+QT_BEGIN_NAMESPACE
+
+template<class N, QIntrusiveListNode N::*member>
+class QScriptIntrusiveList : public QIntrusiveList<N, member>
+{
+public:
+ inline void insert(N *n);
+ inline void remove(N *n);
+};
+
+template<class N, QIntrusiveListNode N::*member>
+void QScriptIntrusiveList<N, member>::insert(N *n)
+{
+ Q_ASSERT_X(!this->contains(n), Q_FUNC_INFO, "Can't insert a value which is in the list already");
+ Q_ASSERT_X(!(n->*member).isInList(), Q_FUNC_INFO, "Can't insert a value which is in another list");
+ QIntrusiveList<N, member>::insert(n);
+}
+
+template<class N, QIntrusiveListNode N::*member>
+void QScriptIntrusiveList<N, member>::remove(N *n)
+{
+ Q_ASSERT_X(this->contains(n), Q_FUNC_INFO, "Can't remove a value which is not in the list");
+ QIntrusiveList<N, member>::remove(n);
+}
+
+QT_END_NAMESPACE
+
+#endif //QSCRIPTTOOLS_P_H
diff --git a/src/qml/qml/v8/qv8_p.h b/src/qml/qml/v8/qv8_p.h
new file mode 100644
index 0000000000..d6a06593f5
--- /dev/null
+++ b/src/qml/qml/v8/qv8_p.h
@@ -0,0 +1,42 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <private/v8.h>
diff --git a/src/qml/qml/v8/qv8bindings.cpp b/src/qml/qml/v8/qv8bindings.cpp
new file mode 100644
index 0000000000..76fbea137e
--- /dev/null
+++ b/src/qml/qml/v8/qv8bindings.cpp
@@ -0,0 +1,285 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qv8bindings_p.h"
+
+#include <private/qv8_p.h>
+#include <private/qqmlbinding_p.h>
+#include <private/qqmlcompiler_p.h>
+#include <private/qqmlproperty_p.h>
+#include <private/qqmlbinding_p_p.h>
+#include <private/qqmlexpression_p.h>
+#include <private/qobject_p.h>
+#include <private/qqmltrace_p.h>
+#include <private/qqmlprofilerservice_p.h>
+
+QT_BEGIN_NAMESPACE
+
+static QQmlJavaScriptExpression::VTable QV8Bindings_Binding_jsvtable = {
+ QV8Bindings::Binding::expressionIdentifier,
+ QV8Bindings::Binding::expressionChanged
+};
+
+QV8Bindings::Binding::Binding()
+: QQmlJavaScriptExpression(&QV8Bindings_Binding_jsvtable), target(0), parent(0)
+{
+}
+
+void QV8Bindings::Binding::setEnabled(bool e, QQmlPropertyPrivate::WriteFlags flags)
+{
+ if (enabledFlag() != e) {
+ setEnabledFlag(e);
+
+ if (e) update(flags);
+ }
+}
+
+void QV8Bindings::refresh()
+{
+ int count = functions()->Length();
+ for (int ii = 0; ii < count; ++ii)
+ bindings[ii].refresh();
+}
+
+void QV8Bindings::Binding::refresh()
+{
+ update();
+}
+
+int QV8Bindings::Binding::propertyIndex() const
+{
+ return instruction->property.encodedIndex();
+}
+
+QObject *QV8Bindings::Binding::object() const
+{
+ return target;
+}
+
+void QV8Bindings::Binding::update(QQmlPropertyPrivate::WriteFlags flags)
+{
+ if (!enabledFlag())
+ return;
+
+ QQmlTrace trace("V8 Binding Update");
+ trace.addDetail("URL", parent->url());
+ trace.addDetail("Line", instruction->line);
+ trace.addDetail("Column", instruction->column);
+
+ QQmlBindingProfiler prof(parent->urlString(), instruction->line, instruction->column);
+
+ QQmlContextData *context = parent->context();
+ if (!context || !context->isValid())
+ return;
+
+ if (!updatingFlag()) {
+ setUpdatingFlag(true);
+ QQmlEnginePrivate *ep = QQmlEnginePrivate::get(context->engine);
+
+ bool isUndefined = false;
+
+ DeleteWatcher watcher(this);
+ ep->referenceScarceResources();
+
+ v8::HandleScope handle_scope;
+ v8::Context::Scope scope(ep->v8engine()->context());
+ v8::Local<v8::Value> result =
+ evaluate(context,
+ v8::Handle<v8::Function>::Cast(parent->functions()->Get(instruction->value)),
+ &isUndefined);
+
+ trace.event("writing V8 result");
+ bool needsErrorData = false;
+ if (!watcher.wasDeleted() && !hasError()) {
+ typedef QQmlPropertyPrivate PP;
+ needsErrorData = !PP::writeBinding(target, instruction->property, context, this, result,
+ isUndefined, flags);
+ }
+
+ if (!watcher.wasDeleted()) {
+
+ if (needsErrorData) {
+ QUrl url = parent->url();
+ if (url.isEmpty()) url = QUrl(QLatin1String("<Unknown File>"));
+
+ delayedError()->error.setUrl(url);
+ delayedError()->error.setLine(instruction->line);
+ delayedError()->error.setColumn(-1);
+ }
+
+ if (hasError()) {
+ if (!delayedError()->addError(ep)) ep->warning(delayedError()->error);
+ } else {
+ clearError();
+ }
+
+ setUpdatingFlag(false);
+ }
+
+ ep->dereferenceScarceResources();
+
+ } else {
+ QQmlProperty p = QQmlPropertyPrivate::restore(target, instruction->property,
+ context);
+ QQmlBindingPrivate::printBindingLoopError(p);
+ }
+}
+
+QString QV8Bindings::Binding::expressionIdentifier(QQmlJavaScriptExpression *e)
+{
+ Binding *This = static_cast<Binding *>(e);
+ return This->parent->urlString() + QLatin1String(":") +
+ QString::number(This->instruction->line);
+}
+
+void QV8Bindings::Binding::expressionChanged(QQmlJavaScriptExpression *e)
+{
+ Binding *This = static_cast<Binding *>(e);
+ This->update(QQmlPropertyPrivate::DontRemoveBinding);
+}
+
+void QV8Bindings::Binding::destroy()
+{
+ setEnabledFlag(false);
+ removeFromObject();
+ clear();
+ clearError();
+ parent->release();
+}
+
+QV8Bindings::QV8Bindings(QQmlCompiledData::V8Program *program,
+ int line,
+ QQmlContextData *context)
+: program(program), bindings(0), refCount(1)
+{
+ program->cdata->addref();
+
+ QV8Engine *engine = QQmlEnginePrivate::getV8Engine(context->engine);
+
+ if (program->bindings.IsEmpty()) {
+ v8::HandleScope handle_scope;
+ v8::Context::Scope scope(engine->context());
+
+ v8::Local<v8::Script> script;
+ bool compileFailed = false;
+ {
+ v8::TryCatch try_catch;
+ const QByteArray &source = program->program;
+ script = engine->qmlModeCompile(source.constData(), source.length(),
+ program->cdata->name, line);
+ if (try_catch.HasCaught()) {
+ // The binding was not compiled. There are some exceptional cases which the
+ // expression rewriter does not rewrite properly (e.g., \r-terminated lines
+ // are not rewritten correctly but this bug is demed out-of-scope to fix for
+ // performance reasons; see QTBUG-24064).
+ compileFailed = true;
+ QQmlError error;
+ error.setDescription(QString(QLatin1String("Exception occurred during compilation of binding at line: %1")).arg(line));
+ v8::Local<v8::Message> message = try_catch.Message();
+ if (!message.IsEmpty())
+ QQmlExpressionPrivate::exceptionToError(message, error);
+ QQmlEnginePrivate::get(engine->engine())->warning(error);
+ program->bindings = qPersistentNew(v8::Array::New());
+ }
+ }
+
+ if (!compileFailed) {
+ v8::Local<v8::Value> result = script->Run(engine->contextWrapper()->sharedContext());
+ if (result->IsArray()) {
+ program->bindings = qPersistentNew(v8::Local<v8::Array>::Cast(result));
+ program->program.clear(); // We don't need the source anymore
+ }
+ }
+ }
+
+ int bindingsCount = functions()->Length();
+ if (bindingsCount) bindings = new QV8Bindings::Binding[bindingsCount];
+
+ setContext(context);
+}
+
+QV8Bindings::~QV8Bindings()
+{
+ program->cdata->release();
+ program = 0;
+
+ delete [] bindings;
+ bindings = 0;
+}
+
+QQmlAbstractBinding *
+QV8Bindings::configBinding(QObject *target, QObject *scope,
+ const QQmlInstruction::instr_assignBinding *i)
+{
+ if (!bindings) // initialization failed.
+ return 0;
+
+ QV8Bindings::Binding *rv = bindings + i->value;
+
+ rv->instruction = i;
+ rv->target = target;
+ rv->setScopeObject(scope);
+ rv->setUseSharedContext(true);
+ rv->setNotifyOnValueChanged(true);
+ rv->parent = this;
+
+ addref(); // This is decremented in Binding::destroy()
+
+ return rv;
+}
+
+const QUrl &QV8Bindings::url() const
+{
+ return program->cdata->url;
+}
+
+const QString &QV8Bindings::urlString() const
+{
+ return program->cdata->name;
+}
+
+v8::Persistent<v8::Array> &QV8Bindings::functions() const
+{
+ return program->bindings;
+}
+
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/v8/qv8bindings_p.h b/src/qml/qml/v8/qv8bindings_p.h
new file mode 100644
index 0000000000..ad5b2cb8b0
--- /dev/null
+++ b/src/qml/qml/v8/qv8bindings_p.h
@@ -0,0 +1,148 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QV8BINDINGS_P_H
+#define QV8BINDINGS_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qqmlpropertycache_p.h>
+#include <private/qqmlinstruction_p.h>
+#include <private/qqmlexpression_p.h>
+#include <private/qqmlcompiler_p.h>
+#include <private/qqmlbinding_p.h>
+#include <private/qflagpointer_p.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class QQmlCompiledData;
+
+class QV8BindingsPrivate;
+class QV8Bindings : public QQmlAbstractExpression
+{
+public:
+ QV8Bindings(QQmlCompiledData::V8Program *,
+ int line,
+ QQmlContextData *context);
+ virtual ~QV8Bindings();
+
+ QQmlAbstractBinding *configBinding(QObject *target, QObject *scope,
+ const QQmlInstruction::instr_assignBinding *);
+
+ // Inherited from QQmlAbstractExpression
+ virtual void refresh();
+
+ struct Binding : public QQmlJavaScriptExpression,
+ public QQmlAbstractBinding {
+ Binding();
+
+ void update() { QQmlAbstractBinding::update(); }
+ void refresh();
+
+ // "Inherited" from QQmlJavaScriptExpression
+ static QString expressionIdentifier(QQmlJavaScriptExpression *);
+ static void expressionChanged(QQmlJavaScriptExpression *);
+
+ // Inherited from QQmlAbstractBinding
+ virtual void setEnabled(bool, QQmlPropertyPrivate::WriteFlags flags);
+ virtual void update(QQmlPropertyPrivate::WriteFlags flags);
+ virtual void destroy();
+ virtual int propertyIndex() const;
+ virtual QObject *object() const;
+
+ QObject *target;
+ QV8Bindings *parent;
+
+ // To save memory, we store flags inside the instruction pointer.
+ // flag1: enabled
+ // flag2: updating
+ QFlagPointer<const QQmlInstruction::instr_assignBinding> instruction;
+
+ inline bool enabledFlag() const { return instruction.flag(); }
+ inline void setEnabledFlag(bool v) { instruction.setFlagValue(v); }
+ inline bool updatingFlag() const { return instruction.flag2(); }
+ inline void setUpdatingFlag(bool v) { instruction.setFlag2Value(v); }
+ };
+
+ inline void addref();
+ inline void release();
+
+private:
+ Q_DISABLE_COPY(QV8Bindings)
+
+ const QUrl &url() const;
+ const QString &urlString() const;
+ v8::Persistent<v8::Array> &functions() const;
+
+ QQmlCompiledData::V8Program *program;
+ Binding *bindings;
+ int refCount;
+};
+
+void QV8Bindings::addref()
+{
+ ++refCount;
+}
+
+void QV8Bindings::release()
+{
+ if (0 == --refCount)
+ delete this;
+}
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QV8BINDINGS_P_H
+
+
diff --git a/src/qml/qml/v8/qv8contextwrapper.cpp b/src/qml/qml/v8/qv8contextwrapper.cpp
new file mode 100644
index 0000000000..246b716aa0
--- /dev/null
+++ b/src/qml/qml/v8/qv8contextwrapper.cpp
@@ -0,0 +1,455 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qv8contextwrapper_p.h"
+#include "qv8engine_p.h"
+
+#include <private/qqmlengine_p.h>
+#include <private/qqmlcontext_p.h>
+
+QT_BEGIN_NAMESPACE
+
+static QString internal(QLatin1String("You've stumbled onto an internal implementation detail "
+ "that should never have been exposed."));
+
+class QV8ContextResource : public QV8ObjectResource
+{
+ V8_RESOURCE_TYPE(ContextType);
+
+public:
+ QV8ContextResource(QV8Engine *engine, QQmlContextData *context, QObject *scopeObject);
+ ~QV8ContextResource();
+
+ inline QQmlContextData *getContext() const;
+ inline QObject *getScopeObject() const;
+
+ quint32 isSharedContext:1;
+ quint32 hasSubContexts:1;
+ quint32 readOnly:1;
+ quint32 dummy:29;
+
+ QObject *secondaryScope;
+
+ // This is a pretty horrible hack, and an abuse of external strings. When we create a
+ // sub-context (a context created by a Qt.include() in an external javascript file),
+ // we pass a specially crafted SubContext external string as the v8::Script::Data() to
+ // the script, which contains a pointer to the context. We can then access the
+ // v8::Script::Data() later on to resolve names and URLs against the sub-context instead
+ // of the main outer context.
+ struct SubContext : public v8::String::ExternalStringResource {
+ SubContext(QQmlContextData *context) : context(context) {}
+ QQmlGuardedContextData context;
+
+ virtual const uint16_t* data() const { return (const uint16_t *)internal.constData(); }
+ virtual size_t length() const { return internal.length(); }
+ };
+
+private:
+ QQmlGuardedContextData context;
+ QQmlGuard<QObject> scopeObject;
+
+};
+
+QV8ContextResource::QV8ContextResource(QV8Engine *engine, QQmlContextData *context, QObject *scopeObject)
+: QV8ObjectResource(engine), isSharedContext(false), hasSubContexts(false), readOnly(true),
+ secondaryScope(0), context(context), scopeObject(scopeObject)
+{
+}
+
+QV8ContextResource::~QV8ContextResource()
+{
+ if (context && context->isJSContext)
+ context->destroy();
+}
+
+// Returns the scope object
+QObject *QV8ContextResource::getScopeObject() const
+{
+ if (isSharedContext)
+ return QQmlEnginePrivate::get(engine->engine())->sharedScope;
+ else
+ return scopeObject;
+}
+
+// Returns the context, including resolving a subcontext
+QQmlContextData *QV8ContextResource::getContext() const
+{
+ if (isSharedContext)
+ return QQmlEnginePrivate::get(engine->engine())->sharedContext;
+
+ if (!hasSubContexts)
+ return context;
+
+ v8::Local<v8::Value> callingdata = v8::Context::GetCallingScriptData();
+ if (callingdata.IsEmpty() || !callingdata->IsString())
+ return context;
+
+ v8::Local<v8::String> callingstring = callingdata->ToString();
+ Q_ASSERT(callingstring->IsExternal());
+ Q_ASSERT(callingstring->GetExternalStringResource());
+
+ SubContext *sc = static_cast<SubContext *>(callingstring->GetExternalStringResource());
+ return sc->context;
+}
+
+QV8ContextWrapper::QV8ContextWrapper()
+: m_engine(0)
+{
+}
+
+QV8ContextWrapper::~QV8ContextWrapper()
+{
+}
+
+void QV8ContextWrapper::destroy()
+{
+ qPersistentDispose(m_sharedContext);
+ qPersistentDispose(m_urlConstructor);
+ qPersistentDispose(m_constructor);
+}
+
+void QV8ContextWrapper::init(QV8Engine *engine)
+{
+ m_engine = engine;
+ {
+ v8::Local<v8::FunctionTemplate> ft = v8::FunctionTemplate::New();
+ ft->InstanceTemplate()->SetHasExternalResource(true);
+ ft->InstanceTemplate()->SetFallbackPropertyHandler(Getter, Setter);
+ m_constructor = qPersistentNew<v8::Function>(ft->GetFunction());
+ }
+ {
+ v8::Local<v8::FunctionTemplate> ft = v8::FunctionTemplate::New();
+ ft->InstanceTemplate()->SetHasExternalResource(true);
+ ft->InstanceTemplate()->SetFallbackPropertyHandler(NullGetter, NullSetter);
+ m_urlConstructor = qPersistentNew<v8::Function>(ft->GetFunction());
+ }
+ {
+ v8::Local<v8::Object> sharedContext = m_constructor->NewInstance();
+ QV8ContextResource *r = new QV8ContextResource(engine, 0, 0);
+ r->isSharedContext = true;
+ sharedContext->SetExternalResource(r);
+ m_sharedContext = qPersistentNew<v8::Object>(sharedContext);
+ }
+}
+
+v8::Local<v8::Object> QV8ContextWrapper::qmlScope(QQmlContextData *ctxt, QObject *scope)
+{
+ // XXX NewInstance() should be optimized
+ v8::Local<v8::Object> rv = m_constructor->NewInstance();
+ QV8ContextResource *r = new QV8ContextResource(m_engine, ctxt, scope);
+ rv->SetExternalResource(r);
+ return rv;
+}
+
+v8::Local<v8::Object> QV8ContextWrapper::urlScope(const QUrl &url)
+{
+ QQmlContextData *context = new QQmlContextData;
+ context->url = url;
+ context->isInternal = true;
+ context->isJSContext = true;
+
+ // XXX NewInstance() should be optimized
+ v8::Local<v8::Object> rv = m_urlConstructor->NewInstance();
+ QV8ContextResource *r = new QV8ContextResource(m_engine, context, 0);
+ rv->SetExternalResource(r);
+ return rv;
+}
+
+void QV8ContextWrapper::setReadOnly(v8::Handle<v8::Object> qmlglobal, bool readOnly)
+{
+ QV8ContextResource *resource = v8_resource_cast<QV8ContextResource>(qmlglobal);
+ Q_ASSERT(resource);
+ resource->readOnly = readOnly;
+}
+
+void QV8ContextWrapper::addSubContext(v8::Handle<v8::Object> qmlglobal, v8::Handle<v8::Script> script,
+ QQmlContextData *ctxt)
+{
+ QV8ContextResource *resource = v8_resource_cast<QV8ContextResource>(qmlglobal);
+ Q_ASSERT(resource);
+ resource->hasSubContexts = true;
+ script->SetData(v8::String::NewExternal(new QV8ContextResource::SubContext(ctxt)));
+}
+
+QObject *QV8ContextWrapper::setSecondaryScope(v8::Handle<v8::Object> ctxt, QObject *scope)
+{
+ QV8ContextResource *resource = v8_resource_cast<QV8ContextResource>(ctxt);
+ if (!resource) return 0;
+
+ QObject *rv = resource->secondaryScope;
+ resource->secondaryScope = scope;
+ return rv;
+}
+
+QQmlContextData *QV8ContextWrapper::callingContext()
+{
+ v8::Local<v8::Object> qmlglobal = v8::Context::GetCallingQmlGlobal();
+ if (qmlglobal.IsEmpty()) return 0;
+
+ QV8ContextResource *r = v8_resource_cast<QV8ContextResource>(qmlglobal);
+ return r?r->getContext():0;
+}
+
+QQmlContextData *QV8ContextWrapper::context(v8::Handle<v8::Value> value)
+{
+ if (!value->IsObject())
+ return 0;
+
+ v8::Handle<v8::Object> qmlglobal = v8::Handle<v8::Object>::Cast(value);
+ QV8ContextResource *r = v8_resource_cast<QV8ContextResource>(qmlglobal);
+ return r?r->getContext():0;
+}
+
+v8::Handle<v8::Value> QV8ContextWrapper::NullGetter(v8::Local<v8::String> property,
+ const v8::AccessorInfo &info)
+{
+ QV8ContextResource *resource = v8_resource_check<QV8ContextResource>(info.This());
+
+ QV8Engine *engine = resource->engine;
+
+ QString error = QLatin1String("Can't find variable: ") + engine->toString(property);
+ v8::ThrowException(v8::Exception::ReferenceError(engine->toString(error)));
+ return v8::Undefined();
+}
+
+v8::Handle<v8::Value> QV8ContextWrapper::Getter(v8::Local<v8::String> property,
+ const v8::AccessorInfo &info)
+{
+ QV8ContextResource *resource = v8_resource_check<QV8ContextResource>(info.This());
+
+ // Its possible we could delay the calculation of the "actual" context (in the case
+ // of sub contexts) until it is definately needed.
+ QQmlContextData *context = resource->getContext();
+ QQmlContextData *expressionContext = context;
+
+ if (!context)
+ return v8::Undefined();
+
+ if (v8::Context::GetCallingQmlGlobal() != info.This())
+ return v8::Handle<v8::Value>();
+
+ // Search type (attached property/enum/imported scripts) names
+ // Secondary scope object
+ // while (context) {
+ // Search context properties
+ // Search scope object
+ // Search context object
+ // context = context->parent
+ // }
+
+ QV8Engine *engine = resource->engine;
+
+ QObject *scopeObject = resource->getScopeObject();
+
+ QHashedV8String propertystring(property);
+
+ if (context->imports && QV8Engine::startsWithUpper(property)) {
+ // Search for attached properties, enums and imported scripts
+ QQmlTypeNameCache::Result r = context->imports->query(propertystring);
+
+ if (r.isValid()) {
+ if (r.scriptIndex != -1) {
+ int index = r.scriptIndex;
+ if (index < context->importedScripts.count())
+ return context->importedScripts.at(index);
+ else
+ return v8::Undefined();
+ } else if (r.type) {
+ return engine->typeWrapper()->newObject(scopeObject, r.type);
+ } else if (r.importNamespace) {
+ return engine->typeWrapper()->newObject(scopeObject, context->imports, r.importNamespace);
+ }
+ Q_ASSERT(!"Unreachable");
+ }
+
+ // Fall through
+ }
+
+ QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine->engine());
+ QV8QObjectWrapper *qobjectWrapper = engine->qobjectWrapper();
+
+ if (resource->secondaryScope) {
+ v8::Handle<v8::Value> result = qobjectWrapper->getProperty(resource->secondaryScope, propertystring,
+ QV8QObjectWrapper::IgnoreRevision);
+ if (!result.IsEmpty()) return result;
+ }
+
+ while (context) {
+ // Search context properties
+ if (context->propertyNames) {
+ int propertyIdx = context->propertyNames->value(propertystring);
+
+ if (propertyIdx != -1) {
+
+ if (propertyIdx < context->idValueCount) {
+
+ ep->captureProperty(&context->idValues[propertyIdx].bindings);
+ return engine->newQObject(context->idValues[propertyIdx]);
+ } else {
+
+ QQmlContextPrivate *cp = context->asQQmlContextPrivate();
+
+ ep->captureProperty(context->asQQmlContext(), -1,
+ propertyIdx + cp->notifyIndex);
+
+ const QVariant &value = cp->propertyValues.at(propertyIdx);
+ if (value.userType() == qMetaTypeId<QList<QObject*> >()) {
+ QQmlListProperty<QObject> prop(context->asQQmlContext(), (void*)propertyIdx,
+ 0,
+ QQmlContextPrivate::context_count,
+ QQmlContextPrivate::context_at);
+ return engine->listWrapper()->newList(prop, qMetaTypeId<QQmlListProperty<QObject> >());
+ } else {
+ return engine->fromVariant(cp->propertyValues.at(propertyIdx));
+ }
+ }
+ }
+ }
+
+ // Search scope object
+ if (scopeObject) {
+ v8::Handle<v8::Value> result = qobjectWrapper->getProperty(scopeObject, propertystring,
+ QV8QObjectWrapper::CheckRevision);
+ if (!result.IsEmpty()) return result;
+ }
+ scopeObject = 0;
+
+
+ // Search context object
+ if (context->contextObject) {
+ v8::Handle<v8::Value> result = qobjectWrapper->getProperty(context->contextObject, propertystring,
+ QV8QObjectWrapper::CheckRevision);
+ if (!result.IsEmpty()) return result;
+ }
+
+ context = context->parent;
+ }
+
+ expressionContext->unresolvedNames = true;
+
+ QString error = QLatin1String("Can't find variable: ") + engine->toString(property);
+ v8::ThrowException(v8::Exception::ReferenceError(engine->toString(error)));
+ return v8::Undefined();
+}
+
+v8::Handle<v8::Value> QV8ContextWrapper::NullSetter(v8::Local<v8::String> property,
+ v8::Local<v8::Value>,
+ const v8::AccessorInfo &info)
+{
+ QV8ContextResource *resource = v8_resource_check<QV8ContextResource>(info.This());
+
+ QV8Engine *engine = resource->engine;
+
+ if (!resource->readOnly) {
+ return v8::Handle<v8::Value>();
+ } else {
+ QString error = QLatin1String("Invalid write to global property \"") + engine->toString(property) +
+ QLatin1String("\"");
+ v8::ThrowException(v8::Exception::Error(engine->toString(error)));
+ return v8::Handle<v8::Value>();
+ }
+}
+
+v8::Handle<v8::Value> QV8ContextWrapper::Setter(v8::Local<v8::String> property,
+ v8::Local<v8::Value> value,
+ const v8::AccessorInfo &info)
+{
+ QV8ContextResource *resource = v8_resource_check<QV8ContextResource>(info.This());
+
+ // Its possible we could delay the calculation of the "actual" context (in the case
+ // of sub contexts) until it is definately needed.
+ QQmlContextData *context = resource->getContext();
+ QQmlContextData *expressionContext = context;
+
+ if (!context)
+ return v8::Undefined();
+
+ if (v8::Context::GetCallingQmlGlobal() != info.This())
+ return v8::Handle<v8::Value>();
+
+ // See QV8ContextWrapper::Getter for resolution order
+
+ QV8Engine *engine = resource->engine;
+ QObject *scopeObject = resource->getScopeObject();
+
+ QHashedV8String propertystring(property);
+
+ QV8QObjectWrapper *qobjectWrapper = engine->qobjectWrapper();
+
+ // Search scope object
+ if (resource->secondaryScope &&
+ qobjectWrapper->setProperty(resource->secondaryScope, propertystring, value,
+ QV8QObjectWrapper::IgnoreRevision))
+ return value;
+
+ while (context) {
+ // Search context properties
+ if (context->propertyNames && -1 != context->propertyNames->value(propertystring))
+ return value;
+
+ // Search scope object
+ if (scopeObject &&
+ qobjectWrapper->setProperty(scopeObject, propertystring, value, QV8QObjectWrapper::CheckRevision))
+ return value;
+ scopeObject = 0;
+
+ // Search context object
+ if (context->contextObject &&
+ qobjectWrapper->setProperty(context->contextObject, propertystring, value,
+ QV8QObjectWrapper::CheckRevision))
+ return value;
+
+ context = context->parent;
+ }
+
+ expressionContext->unresolvedNames = true;
+
+ if (!resource->readOnly) {
+ return v8::Handle<v8::Value>();
+ } else {
+ QString error = QLatin1String("Invalid write to global property \"") + engine->toString(property) +
+ QLatin1String("\"");
+ v8::ThrowException(v8::Exception::Error(engine->toString(error)));
+ return v8::Undefined();
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/v8/qv8contextwrapper_p.h b/src/qml/qml/v8/qv8contextwrapper_p.h
new file mode 100644
index 0000000000..117f16ab39
--- /dev/null
+++ b/src/qml/qml/v8/qv8contextwrapper_p.h
@@ -0,0 +1,120 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QV8CONTEXTWRAPPER_P_H
+#define QV8CONTEXTWRAPPER_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qglobal.h>
+#include <private/qv8_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QUrl;
+class QObject;
+class QV8Engine;
+class QQmlContextData;
+class QV8ContextWrapper
+{
+public:
+ QV8ContextWrapper();
+ ~QV8ContextWrapper();
+
+ void init(QV8Engine *);
+ void destroy();
+
+ v8::Local<v8::Object> qmlScope(QQmlContextData *ctxt, QObject *scope);
+ v8::Local<v8::Object> urlScope(const QUrl &);
+
+ void setReadOnly(v8::Handle<v8::Object>, bool);
+
+ void addSubContext(v8::Handle<v8::Object> qmlglobal, v8::Handle<v8::Script>,
+ QQmlContextData *ctxt);
+
+ // XXX We only use the secondary scope to pass the "arguments" of the signal to
+ // on<SignalName> properties. Instead of doing this we should rewrite the
+ // JavaScript closure function to accept these arguments as named parameters.
+ // To keep backwards compatibility we have to check that the argument names are
+ // not members of the QV8Engine::illegalNames() set.
+ QObject *setSecondaryScope(v8::Handle<v8::Object>, QObject *);
+
+ QQmlContextData *callingContext();
+ QQmlContextData *context(v8::Handle<v8::Value>);
+
+ inline v8::Handle<v8::Object> sharedContext() const;
+
+private:
+ static v8::Handle<v8::Value> NullGetter(v8::Local<v8::String> property,
+ const v8::AccessorInfo &info);
+ static v8::Handle<v8::Value> NullSetter(v8::Local<v8::String> property,
+ v8::Local<v8::Value> value,
+ const v8::AccessorInfo &info);
+ static v8::Handle<v8::Value> Getter(v8::Local<v8::String> property,
+ const v8::AccessorInfo &info);
+ static v8::Handle<v8::Value> Setter(v8::Local<v8::String> property,
+ v8::Local<v8::Value> value,
+ const v8::AccessorInfo &info);
+
+ QV8Engine *m_engine;
+ v8::Persistent<v8::Function> m_constructor;
+ v8::Persistent<v8::Function> m_urlConstructor;
+ v8::Persistent<v8::Object> m_sharedContext;
+};
+
+v8::Handle<v8::Object> QV8ContextWrapper::sharedContext() const
+{
+ return m_sharedContext;
+}
+
+QT_END_NAMESPACE
+
+#endif // QV8CONTEXTWRAPPER_P_H
+
diff --git a/src/qml/qml/v8/qv8debug_p.h b/src/qml/qml/v8/qv8debug_p.h
new file mode 100644
index 0000000000..4e1ec3e2ca
--- /dev/null
+++ b/src/qml/qml/v8/qv8debug_p.h
@@ -0,0 +1,42 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <private/v8-debug.h>
diff --git a/src/qml/qml/v8/qv8domerrors.cpp b/src/qml/qml/v8/qv8domerrors.cpp
new file mode 100644
index 0000000000..7b8f10a27e
--- /dev/null
+++ b/src/qml/qml/v8/qv8domerrors.cpp
@@ -0,0 +1,73 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qv8domerrors_p.h"
+#include "qv8engine_p.h"
+
+QT_BEGIN_NAMESPACE
+
+void qt_add_domexceptions(QV8Engine *engine)
+{
+ // DOM Exception
+ v8::PropertyAttribute attributes = (v8::PropertyAttribute)(v8::ReadOnly | v8::DontEnum | v8::DontDelete);
+
+ v8::Local<v8::Object> domexception = v8::Object::New();
+ domexception->Set(v8::String::New("INDEX_SIZE_ERR"), v8::Integer::New(DOMEXCEPTION_INDEX_SIZE_ERR), attributes);
+ domexception->Set(v8::String::New("DOMSTRING_SIZE_ERR"), v8::Integer::New(DOMEXCEPTION_DOMSTRING_SIZE_ERR), attributes);
+ domexception->Set(v8::String::New("HIERARCHY_REQUEST_ERR"), v8::Integer::New(DOMEXCEPTION_HIERARCHY_REQUEST_ERR), attributes);
+ domexception->Set(v8::String::New("WRONG_DOCUMENT_ERR"), v8::Integer::New(DOMEXCEPTION_WRONG_DOCUMENT_ERR), attributes);
+ domexception->Set(v8::String::New("INVALID_CHARACTER_ERR"), v8::Integer::New(DOMEXCEPTION_INVALID_CHARACTER_ERR), attributes);
+ domexception->Set(v8::String::New("NO_DATA_ALLOWED_ERR"), v8::Integer::New(DOMEXCEPTION_NO_DATA_ALLOWED_ERR), attributes);
+ domexception->Set(v8::String::New("NO_MODIFICATION_ALLOWED_ERR"), v8::Integer::New(DOMEXCEPTION_NO_MODIFICATION_ALLOWED_ERR), attributes);
+ domexception->Set(v8::String::New("NOT_FOUND_ERR"), v8::Integer::New(DOMEXCEPTION_NOT_FOUND_ERR), attributes);
+ domexception->Set(v8::String::New("NOT_SUPPORTED_ERR"), v8::Integer::New(DOMEXCEPTION_NOT_SUPPORTED_ERR), attributes);
+ domexception->Set(v8::String::New("INUSE_ATTRIBUTE_ERR"), v8::Integer::New(DOMEXCEPTION_INUSE_ATTRIBUTE_ERR), attributes);
+ domexception->Set(v8::String::New("INVALID_STATE_ERR"), v8::Integer::New(DOMEXCEPTION_INVALID_STATE_ERR), attributes);
+ domexception->Set(v8::String::New("SYNTAX_ERR"), v8::Integer::New(DOMEXCEPTION_SYNTAX_ERR), attributes);
+ domexception->Set(v8::String::New("INVALID_MODIFICATION_ERR"), v8::Integer::New(DOMEXCEPTION_INVALID_MODIFICATION_ERR), attributes);
+ domexception->Set(v8::String::New("NAMESPACE_ERR"), v8::Integer::New(DOMEXCEPTION_NAMESPACE_ERR), attributes);
+ domexception->Set(v8::String::New("INVALID_ACCESS_ERR"), v8::Integer::New(DOMEXCEPTION_INVALID_ACCESS_ERR), attributes);
+ domexception->Set(v8::String::New("VALIDATION_ERR"), v8::Integer::New(DOMEXCEPTION_VALIDATION_ERR), attributes);
+ domexception->Set(v8::String::New("TYPE_MISMATCH_ERR"), v8::Integer::New(DOMEXCEPTION_TYPE_MISMATCH_ERR), attributes);
+ engine->global()->Set(v8::String::New("DOMException"), domexception);
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/v8/qv8domerrors_p.h b/src/qml/qml/v8/qv8domerrors_p.h
new file mode 100644
index 0000000000..5d5f277d55
--- /dev/null
+++ b/src/qml/qml/v8/qv8domerrors_p.h
@@ -0,0 +1,94 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QV8DOMERRORS_P_H
+#define QV8DOMERRORS_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qglobal.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+// From DOM-Level-3-Core spec
+// http://www.w3.org/TR/DOM-Level-3-Core/core.html
+#define DOMEXCEPTION_INDEX_SIZE_ERR 1
+#define DOMEXCEPTION_DOMSTRING_SIZE_ERR 2
+#define DOMEXCEPTION_HIERARCHY_REQUEST_ERR 3
+#define DOMEXCEPTION_WRONG_DOCUMENT_ERR 4
+#define DOMEXCEPTION_INVALID_CHARACTER_ERR 5
+#define DOMEXCEPTION_NO_DATA_ALLOWED_ERR 6
+#define DOMEXCEPTION_NO_MODIFICATION_ALLOWED_ERR 7
+#define DOMEXCEPTION_NOT_FOUND_ERR 8
+#define DOMEXCEPTION_NOT_SUPPORTED_ERR 9
+#define DOMEXCEPTION_INUSE_ATTRIBUTE_ERR 10
+#define DOMEXCEPTION_INVALID_STATE_ERR 11
+#define DOMEXCEPTION_SYNTAX_ERR 12
+#define DOMEXCEPTION_INVALID_MODIFICATION_ERR 13
+#define DOMEXCEPTION_NAMESPACE_ERR 14
+#define DOMEXCEPTION_INVALID_ACCESS_ERR 15
+#define DOMEXCEPTION_VALIDATION_ERR 16
+#define DOMEXCEPTION_TYPE_MISMATCH_ERR 17
+
+#define V8THROW_DOM(error, string) { \
+ v8::Local<v8::Value> v = v8::Exception::Error(v8::String::New(string)); \
+ v->ToObject()->Set(v8::String::New("code"), v8::Integer::New(error)); \
+ v8::ThrowException(v); \
+ return v8::Handle<v8::Value>(); \
+}
+class QV8Engine;
+void qt_add_domexceptions(QV8Engine *engine);
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QV8DOMERRORS_P_H
diff --git a/src/qml/qml/v8/qv8engine.cpp b/src/qml/qml/v8/qv8engine.cpp
new file mode 100644
index 0000000000..4c2cce1525
--- /dev/null
+++ b/src/qml/qml/v8/qv8engine.cpp
@@ -0,0 +1,1598 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qv8engine_p.h"
+
+#include <QtGui/QGuiApplication>
+
+#include "qv8contextwrapper_p.h"
+#include "qv8valuetypewrapper_p.h"
+#include "qv8sequencewrapper_p.h"
+#include "qv8include_p.h"
+#include "qjsengine_p.h"
+#include "../../../3rdparty/javascriptcore/DateMath.h"
+
+#include <private/qqmlbuiltinfunctions_p.h>
+#include <private/qqmllist_p.h>
+#include <private/qqmlengine_p.h>
+#include <private/qquickapplication_p.h>
+#include <private/qqmlxmlhttprequest_p.h>
+#include <private/qqmllocale_p.h>
+
+#include "qscript_impl_p.h"
+#include "qv8domerrors_p.h"
+#include "qv8sqlerrors_p.h"
+
+
+Q_DECLARE_METATYPE(QJSValue)
+Q_DECLARE_METATYPE(QList<int>)
+
+
+// XXX TODO: Need to check all the global functions will also work in a worker script where the
+// QQmlEngine is not available
+QT_BEGIN_NAMESPACE
+
+static bool ObjectComparisonCallback(v8::Local<v8::Object> lhs, v8::Local<v8::Object> rhs)
+{
+ if (lhs == rhs)
+ return true;
+
+ QV8ObjectResource *lhsr = static_cast<QV8ObjectResource*>(lhs->GetExternalResource());
+ QV8ObjectResource *rhsr = static_cast<QV8ObjectResource*>(rhs->GetExternalResource());
+
+ Q_ASSERT(lhsr->engine == rhsr->engine);
+
+ if (lhsr && rhsr) {
+ QV8ObjectResource::ResourceType lhst = lhsr->resourceType();
+ QV8ObjectResource::ResourceType rhst = rhsr->resourceType();
+
+ switch (lhst) {
+ case QV8ObjectResource::ValueTypeType:
+ // a value type might be equal to a variant or another value type
+ if (rhst == QV8ObjectResource::ValueTypeType) {
+ return lhsr->engine->valueTypeWrapper()->isEqual(lhsr, lhsr->engine->valueTypeWrapper()->toVariant(rhsr));
+ } else if (rhst == QV8ObjectResource::VariantType) {
+ return lhsr->engine->valueTypeWrapper()->isEqual(lhsr, lhsr->engine->variantWrapper()->toVariant(rhsr));
+ }
+ break;
+ case QV8ObjectResource::VariantType:
+ // a variant might be equal to a value type or other variant.
+ if (rhst == QV8ObjectResource::VariantType) {
+ return lhsr->engine->variantWrapper()->toVariant(lhsr) ==
+ lhsr->engine->variantWrapper()->toVariant(rhsr);
+ } else if (rhst == QV8ObjectResource::ValueTypeType) {
+ return rhsr->engine->valueTypeWrapper()->isEqual(rhsr, rhsr->engine->variantWrapper()->toVariant(lhsr));
+ }
+ break;
+ case QV8ObjectResource::SequenceType:
+ // a sequence might be equal to itself.
+ if (rhst == QV8ObjectResource::SequenceType) {
+ return lhsr->engine->sequenceWrapper()->isEqual(lhsr, rhsr);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ return false;
+}
+
+
+QV8Engine::QV8Engine(QJSEngine* qq, QJSEngine::ContextOwnership ownership)
+ : q(qq)
+ , m_engine(0)
+ , m_ownsV8Context(ownership == QJSEngine::CreateNewContext)
+ , m_xmlHttpRequestData(0)
+ , m_listModelData(0)
+{
+ qMetaTypeId<QJSValue>();
+ qMetaTypeId<QList<int> >();
+
+ QByteArray v8args = qgetenv("V8ARGS");
+ // change default v8 behaviour to not relocate breakpoints across lines
+ if (!v8args.contains("breakpoint_relocation"))
+ v8args.append(" --nobreakpoint_relocation");
+ v8::V8::SetFlagsFromString(v8args.constData(), v8args.length());
+
+ ensurePerThreadIsolate();
+
+ v8::HandleScope handle_scope;
+ m_context = (ownership == QJSEngine::CreateNewContext) ? v8::Context::New() : v8::Persistent<v8::Context>::New(v8::Context::GetCurrent());
+ qPersistentRegister(m_context);
+ m_originalGlobalObject.init(m_context);
+ v8::Context::Scope context_scope(m_context);
+
+ v8::V8::SetUserObjectComparisonCallbackFunction(ObjectComparisonCallback);
+ QV8GCCallback::registerGcPrologueCallback();
+ m_strongReferencer = qPersistentNew(v8::Object::New());
+
+ m_stringWrapper.init();
+ m_contextWrapper.init(this);
+ m_qobjectWrapper.init(this);
+ m_typeWrapper.init(this);
+ m_listWrapper.init(this);
+ m_variantWrapper.init(this);
+ m_valueTypeWrapper.init(this);
+ m_sequenceWrapper.init(this);
+
+ {
+ v8::Handle<v8::Value> v = global()->Get(v8::String::New("Object"))->ToObject()->Get(v8::String::New("getOwnPropertyNames"));
+ m_getOwnPropertyNames = qPersistentNew<v8::Function>(v8::Handle<v8::Function>::Cast(v));
+ }
+}
+
+QV8Engine::~QV8Engine()
+{
+ Q_ASSERT_X(v8::Isolate::GetCurrent(), "QV8Engine::~QV8Engine()", "called after v8::Isolate has exited");
+ for (int ii = 0; ii < m_extensionData.count(); ++ii)
+ delete m_extensionData[ii];
+ m_extensionData.clear();
+
+ qt_rem_qmlxmlhttprequest(this, m_xmlHttpRequestData);
+ m_xmlHttpRequestData = 0;
+ delete m_listModelData;
+ m_listModelData = 0;
+
+ qPersistentDispose(m_freezeObject);
+ qPersistentDispose(m_getOwnPropertyNames);
+
+ invalidateAllValues();
+ clearExceptions();
+
+ qPersistentDispose(m_strongReferencer);
+
+ m_sequenceWrapper.destroy();
+ m_valueTypeWrapper.destroy();
+ m_variantWrapper.destroy();
+ m_listWrapper.destroy();
+ m_typeWrapper.destroy();
+ m_qobjectWrapper.destroy();
+ m_contextWrapper.destroy();
+ m_stringWrapper.destroy();
+
+ m_originalGlobalObject.destroy();
+
+ if (m_ownsV8Context)
+ qPersistentDispose(m_context);
+}
+
+QString QV8Engine::toStringStatic(v8::Handle<v8::Value> jsstr)
+{
+ return toStringStatic(jsstr->ToString());
+}
+
+QString QV8Engine::toStringStatic(v8::Handle<v8::String> jsstr)
+{
+ QString qstr;
+ qstr.resize(jsstr->Length());
+ jsstr->Write((uint16_t*)qstr.data());
+ return qstr;
+}
+
+QVariant QV8Engine::toVariant(v8::Handle<v8::Value> value, int typeHint)
+{
+ if (value.IsEmpty())
+ return QVariant();
+
+ if (typeHint == QVariant::Bool)
+ return QVariant(value->BooleanValue());
+
+ if (value->IsObject()) {
+ QV8ObjectResource *r = (QV8ObjectResource *)value->ToObject()->GetExternalResource();
+ if (r) {
+ switch (r->resourceType()) {
+ case QV8ObjectResource::Context2DStyleType:
+ case QV8ObjectResource::Context2DPixelArrayType:
+ case QV8ObjectResource::SignalHandlerType:
+ case QV8ObjectResource::IncubatorType:
+ case QV8ObjectResource::VisualDataItemType:
+ case QV8ObjectResource::ContextType:
+ case QV8ObjectResource::XMLHttpRequestType:
+ case QV8ObjectResource::DOMNodeType:
+ case QV8ObjectResource::SQLDatabaseType:
+ case QV8ObjectResource::ListModelType:
+ case QV8ObjectResource::Context2DType:
+ case QV8ObjectResource::ParticleDataType:
+ case QV8ObjectResource::LocaleDataType:
+ return QVariant();
+ case QV8ObjectResource::TypeType:
+ return m_typeWrapper.toVariant(r);
+ case QV8ObjectResource::QObjectType:
+ return qVariantFromValue<QObject *>(m_qobjectWrapper.toQObject(r));
+ case QV8ObjectResource::ListType:
+ return m_listWrapper.toVariant(r);
+ case QV8ObjectResource::VariantType:
+ return m_variantWrapper.toVariant(r);
+ case QV8ObjectResource::ValueTypeType:
+ return m_valueTypeWrapper.toVariant(r);
+ case QV8ObjectResource::SequenceType:
+ return m_sequenceWrapper.toVariant(r);
+ }
+ }
+ }
+
+ if (value->IsArray()) {
+ v8::Handle<v8::Array> array = v8::Handle<v8::Array>::Cast(value);
+ if (typeHint == qMetaTypeId<QList<QObject *> >()) {
+ QList<QObject *> list;
+ uint32_t length = array->Length();
+ for (uint32_t ii = 0; ii < length; ++ii) {
+ v8::Local<v8::Value> arrayItem = array->Get(ii);
+ if (arrayItem->IsObject()) {
+ list << toQObject(arrayItem->ToObject());
+ } else {
+ list << 0;
+ }
+ }
+
+ return qVariantFromValue<QList<QObject*> >(list);
+ }
+
+ bool succeeded = false;
+ QVariant retn = m_sequenceWrapper.toVariant(array, typeHint, &succeeded);
+ if (succeeded)
+ return retn;
+ }
+
+ return toBasicVariant(value);
+}
+
+static v8::Handle<v8::Array> arrayFromStringList(QV8Engine *engine, const QStringList &list)
+{
+ v8::Context::Scope scope(engine->context());
+ v8::Local<v8::Array> result = v8::Array::New(list.count());
+ for (int ii = 0; ii < list.count(); ++ii)
+ result->Set(ii, engine->toString(list.at(ii)));
+ return result;
+}
+
+static v8::Handle<v8::Array> arrayFromVariantList(QV8Engine *engine, const QVariantList &list)
+{
+ v8::Context::Scope scope(engine->context());
+ v8::Local<v8::Array> result = v8::Array::New(list.count());
+ for (int ii = 0; ii < list.count(); ++ii)
+ result->Set(ii, engine->fromVariant(list.at(ii)));
+ return result;
+}
+
+static v8::Handle<v8::Object> objectFromVariantMap(QV8Engine *engine, const QVariantMap &map)
+{
+ v8::Context::Scope scope(engine->context());
+ v8::Local<v8::Object> object = v8::Object::New();
+ for (QVariantMap::ConstIterator iter = map.begin(); iter != map.end(); ++iter)
+ object->Set(engine->toString(iter.key()), engine->fromVariant(iter.value()));
+ return object;
+}
+
+Q_CORE_EXPORT QString qt_regexp_toCanonical(const QString &, QRegExp::PatternSyntax);
+
+v8::Handle<v8::Value> QV8Engine::fromVariant(const QVariant &variant)
+{
+ int type = variant.userType();
+ const void *ptr = variant.constData();
+
+ if (type < QMetaType::User) {
+ switch (QMetaType::Type(type)) {
+ case QMetaType::Void:
+ return v8::Undefined();
+ case QMetaType::Bool:
+ return v8::Boolean::New(*reinterpret_cast<const bool*>(ptr));
+ case QMetaType::Int:
+ return v8::Integer::New(*reinterpret_cast<const int*>(ptr));
+ case QMetaType::UInt:
+ return v8::Integer::NewFromUnsigned(*reinterpret_cast<const uint*>(ptr));
+ case QMetaType::LongLong:
+ return v8::Number::New(*reinterpret_cast<const qlonglong*>(ptr));
+ case QMetaType::ULongLong:
+ return v8::Number::New(*reinterpret_cast<const qulonglong*>(ptr));
+ case QMetaType::Double:
+ return v8::Number::New(*reinterpret_cast<const double*>(ptr));
+ case QMetaType::QString:
+ return m_stringWrapper.toString(*reinterpret_cast<const QString*>(ptr));
+ case QMetaType::Float:
+ return v8::Number::New(*reinterpret_cast<const float*>(ptr));
+ case QMetaType::Short:
+ return v8::Integer::New(*reinterpret_cast<const short*>(ptr));
+ case QMetaType::UShort:
+ return v8::Integer::NewFromUnsigned(*reinterpret_cast<const unsigned short*>(ptr));
+ case QMetaType::Char:
+ return v8::Integer::New(*reinterpret_cast<const char*>(ptr));
+ case QMetaType::UChar:
+ return v8::Integer::NewFromUnsigned(*reinterpret_cast<const unsigned char*>(ptr));
+ case QMetaType::QChar:
+ return v8::Integer::New((*reinterpret_cast<const QChar*>(ptr)).unicode());
+ case QMetaType::QDateTime:
+ return v8::Date::New(qtDateTimeToJsDate(*reinterpret_cast<const QDateTime *>(ptr)));
+ case QMetaType::QDate:
+ return v8::Date::New(qtDateTimeToJsDate(QDateTime(*reinterpret_cast<const QDate *>(ptr))));
+ case QMetaType::QTime:
+ return v8::Date::New(qtDateTimeToJsDate(QDateTime(QDate(1970,1,1), *reinterpret_cast<const QTime *>(ptr))));
+ case QMetaType::QRegExp:
+ return QJSConverter::toRegExp(*reinterpret_cast<const QRegExp *>(ptr));
+ case QMetaType::QObjectStar:
+ case QMetaType::QWidgetStar:
+ return newQObject(*reinterpret_cast<QObject* const *>(ptr));
+ case QMetaType::QStringList:
+ {
+ bool succeeded = false;
+ v8::Handle<v8::Value> retn = m_sequenceWrapper.fromVariant(variant, &succeeded);
+ if (succeeded)
+ return retn;
+ return arrayFromStringList(this, *reinterpret_cast<const QStringList *>(ptr));
+ }
+ case QMetaType::QVariantList:
+ return arrayFromVariantList(this, *reinterpret_cast<const QVariantList *>(ptr));
+ case QMetaType::QVariantMap:
+ return objectFromVariantMap(this, *reinterpret_cast<const QVariantMap *>(ptr));
+
+ default:
+ break;
+ }
+
+ if (m_engine) {
+ if (QQmlValueType *vt = QQmlEnginePrivate::get(m_engine)->valueTypes[type])
+ return m_valueTypeWrapper.newValueType(variant, vt);
+ }
+
+ } else {
+ if (type == qMetaTypeId<QQmlListReference>()) {
+ typedef QQmlListReferencePrivate QDLRP;
+ QDLRP *p = QDLRP::get((QQmlListReference*)ptr);
+ if (p->object) {
+ return m_listWrapper.newList(p->property, p->propertyType);
+ } else {
+ return v8::Null();
+ }
+ } else if (type == qMetaTypeId<QJSValue>()) {
+ const QJSValue *value = reinterpret_cast<const QJSValue *>(ptr);
+ QJSValuePrivate *valuep = QJSValuePrivate::get(*value);
+ if (valuep->assignEngine(this))
+ return v8::Local<v8::Value>::New(*valuep);
+ } else if (type == qMetaTypeId<QList<QObject *> >()) {
+ // XXX Can this be made more by using Array as a prototype and implementing
+ // directly against QList<QObject*>?
+ const QList<QObject *> &list = *(QList<QObject *>*)ptr;
+ v8::Local<v8::Array> array = v8::Array::New(list.count());
+ for (int ii = 0; ii < list.count(); ++ii)
+ array->Set(ii, newQObject(list.at(ii)));
+ return array;
+ }
+
+ bool objOk;
+ QObject *obj = QQmlMetaType::toQObject(variant, &objOk);
+ if (objOk)
+ return newQObject(obj);
+
+ bool succeeded = false;
+ v8::Handle<v8::Value> retn = m_sequenceWrapper.fromVariant(variant, &succeeded);
+ if (succeeded)
+ return retn;
+ }
+
+ // XXX TODO: To be compatible, we still need to handle:
+ // + QObjectList
+ // + QList<int>
+
+ return m_variantWrapper.newVariant(variant);
+}
+
+// A handle scope and context must be entered
+v8::Local<v8::Script> QV8Engine::qmlModeCompile(const QString &source,
+ const QString &fileName,
+ int lineNumber)
+{
+ v8::Local<v8::String> v8source = m_stringWrapper.toString(source);
+ v8::Local<v8::String> v8fileName = m_stringWrapper.toString(fileName);
+
+ v8::ScriptOrigin origin(v8fileName, v8::Integer::New(lineNumber - 1));
+
+ v8::Local<v8::Script> script = v8::Script::Compile(v8source, &origin, 0, v8::Handle<v8::String>(),
+ v8::Script::QmlMode);
+
+ return script;
+}
+
+// A handle scope and context must be entered.
+// source can be either ascii or utf8.
+v8::Local<v8::Script> QV8Engine::qmlModeCompile(const char *source, int sourceLength,
+ const QString &fileName,
+ int lineNumber)
+{
+ if (sourceLength == -1)
+ sourceLength = strlen(source);
+
+ v8::Local<v8::String> v8source = v8::String::New(source, sourceLength);
+ v8::Local<v8::String> v8fileName = m_stringWrapper.toString(fileName);
+
+ v8::ScriptOrigin origin(v8fileName, v8::Integer::New(lineNumber - 1));
+
+ v8::Local<v8::Script> script = v8::Script::Compile(v8source, &origin, 0, v8::Handle<v8::String>(),
+ v8::Script::QmlMode);
+
+ return script;
+}
+
+QNetworkAccessManager *QV8Engine::networkAccessManager()
+{
+ return QQmlEnginePrivate::get(m_engine)->getNetworkAccessManager();
+}
+
+const QStringHash<bool> &QV8Engine::illegalNames() const
+{
+ return m_illegalNames;
+}
+
+// Requires a handle scope
+v8::Local<v8::Array> QV8Engine::getOwnPropertyNames(v8::Handle<v8::Object> o)
+{
+ // FIXME Newer v8 have API for this function
+ v8::TryCatch tc;
+ v8::Handle<v8::Value> args[] = { o };
+ v8::Local<v8::Value> r = m_getOwnPropertyNames->Call(global(), 1, args);
+ if (tc.HasCaught())
+ return v8::Array::New();
+ else
+ return v8::Local<v8::Array>::Cast(r);
+}
+
+QQmlContextData *QV8Engine::callingContext()
+{
+ return m_contextWrapper.callingContext();
+}
+
+// Converts a JS value to a QVariant.
+// Null, Undefined -> QVariant() (invalid)
+// Boolean -> QVariant(bool)
+// Number -> QVariant(double)
+// String -> QVariant(QString)
+// Array -> QVariantList(...)
+// Date -> QVariant(QDateTime)
+// RegExp -> QVariant(QRegExp)
+// [Any other object] -> QVariantMap(...)
+QVariant QV8Engine::toBasicVariant(v8::Handle<v8::Value> value)
+{
+ if (value->IsNull() || value->IsUndefined())
+ return QVariant();
+ if (value->IsBoolean())
+ return value->ToBoolean()->Value();
+ if (value->IsInt32())
+ return value->ToInt32()->Value();
+ if (value->IsNumber())
+ return value->ToNumber()->Value();
+ if (value->IsString())
+ return m_stringWrapper.toString(value->ToString());
+ if (value->IsDate())
+ return qtDateTimeFromJsDate(v8::Handle<v8::Date>::Cast(value)->NumberValue());
+ // NOTE: since we convert QTime to JS Date, round trip will change the variant type (to QDateTime)!
+
+ Q_ASSERT(value->IsObject());
+
+ if (value->IsRegExp()) {
+ v8::Context::Scope scope(context());
+ return QJSConverter::toRegExp(v8::Handle<v8::RegExp>::Cast(value));
+ }
+ if (value->IsArray()) {
+ v8::Context::Scope scope(context());
+ QVariantList rv;
+
+ v8::Handle<v8::Array> array = v8::Handle<v8::Array>::Cast(value);
+ int length = array->Length();
+ for (int ii = 0; ii < length; ++ii)
+ rv << toVariant(array->Get(ii), -1);
+ return rv;
+ }
+ if (!value->IsFunction()) {
+ v8::Context::Scope scope(context());
+ v8::Handle<v8::Object> object = value->ToObject();
+ return variantMapFromJS(object);
+ }
+
+ return QVariant();
+}
+
+
+
+#include <QtGui/qvector3d.h>
+#include <QtGui/qvector4d.h>
+
+struct StaticQtMetaObject : public QObject
+{
+ static const QMetaObject *get()
+ { return &static_cast<StaticQtMetaObject*> (0)->staticQtMetaObject; }
+};
+
+void QV8Engine::initializeGlobal(v8::Handle<v8::Object> global)
+{
+ using namespace QQmlBuiltinFunctions;
+
+ v8::Local<v8::Object> console = v8::Object::New();
+ v8::Local<v8::Function> consoleLogFn = V8FUNCTION(consoleLog, this);
+
+ console->Set(v8::String::New("debug"), consoleLogFn);
+ console->Set(v8::String::New("log"), consoleLogFn);
+ console->Set(v8::String::New("info"), consoleLogFn);
+ console->Set(v8::String::New("warn"), V8FUNCTION(consoleWarn, this));
+ console->Set(v8::String::New("error"), V8FUNCTION(consoleError, this));
+ console->Set(v8::String::New("assert"), V8FUNCTION(consoleAssert, this));
+
+ console->Set(v8::String::New("count"), V8FUNCTION(consoleCount, this));
+ console->Set(v8::String::New("profile"), V8FUNCTION(consoleProfile, this));
+ console->Set(v8::String::New("profileEnd"), V8FUNCTION(consoleProfileEnd, this));
+ console->Set(v8::String::New("time"), V8FUNCTION(consoleTime, this));
+ console->Set(v8::String::New("timeEnd"), V8FUNCTION(consoleTimeEnd, this));
+ console->Set(v8::String::New("trace"), V8FUNCTION(consoleTrace, this));
+ console->Set(v8::String::New("exception"), V8FUNCTION(consoleException, this));
+
+ v8::Local<v8::Object> qt = v8::Object::New();
+
+ // Set all the enums from the "Qt" namespace
+ const QMetaObject *qtMetaObject = StaticQtMetaObject::get();
+ for (int ii = 0; ii < qtMetaObject->enumeratorCount(); ++ii) {
+ QMetaEnum enumerator = qtMetaObject->enumerator(ii);
+ for (int jj = 0; jj < enumerator.keyCount(); ++jj) {
+ qt->Set(v8::String::New(enumerator.key(jj)), v8::Integer::New(enumerator.value(jj)));
+ }
+ }
+ qt->Set(v8::String::New("Asynchronous"), v8::Integer::New(0));
+ qt->Set(v8::String::New("Synchronous"), v8::Integer::New(1));
+
+ qt->Set(v8::String::New("include"), V8FUNCTION(QV8Include::include, this));
+ qt->Set(v8::String::New("isQtObject"), V8FUNCTION(isQtObject, this));
+ qt->Set(v8::String::New("rgba"), V8FUNCTION(rgba, this));
+ qt->Set(v8::String::New("hsla"), V8FUNCTION(hsla, this));
+ qt->Set(v8::String::New("rect"), V8FUNCTION(rect, this));
+ qt->Set(v8::String::New("point"), V8FUNCTION(point, this));
+ qt->Set(v8::String::New("size"), V8FUNCTION(size, this));
+ qt->Set(v8::String::New("vector3d"), V8FUNCTION(vector3d, this));
+ qt->Set(v8::String::New("vector4d"), V8FUNCTION(vector4d, this));
+
+ qt->Set(v8::String::New("formatDate"), V8FUNCTION(formatDate, this));
+ qt->Set(v8::String::New("formatTime"), V8FUNCTION(formatTime, this));
+ qt->Set(v8::String::New("formatDateTime"), V8FUNCTION(formatDateTime, this));
+
+ qt->Set(v8::String::New("openUrlExternally"), V8FUNCTION(openUrlExternally, this));
+ qt->Set(v8::String::New("fontFamilies"), V8FUNCTION(fontFamilies, this));
+ qt->Set(v8::String::New("md5"), V8FUNCTION(md5, this));
+ qt->Set(v8::String::New("btoa"), V8FUNCTION(btoa, this));
+ qt->Set(v8::String::New("atob"), V8FUNCTION(atob, this));
+ qt->Set(v8::String::New("resolvedUrl"), V8FUNCTION(resolvedUrl, this));
+ qt->Set(v8::String::New("locale"), V8FUNCTION(locale, this));
+
+ if (m_engine) {
+ qt->Set(v8::String::New("application"), newQObject(new QQuickApplication(m_engine)));
+ qt->Set(v8::String::New("inputMethod"), newQObject(qGuiApp->inputMethod(), CppOwnership));
+ qt->Set(v8::String::New("lighter"), V8FUNCTION(lighter, this));
+ qt->Set(v8::String::New("darker"), V8FUNCTION(darker, this));
+ qt->Set(v8::String::New("tint"), V8FUNCTION(tint, this));
+ qt->Set(v8::String::New("quit"), V8FUNCTION(quit, this));
+ qt->Set(v8::String::New("createQmlObject"), V8FUNCTION(createQmlObject, this));
+ qt->Set(v8::String::New("createComponent"), V8FUNCTION(createComponent, this));
+ }
+
+ global->Set(v8::String::New("qsTranslate"), V8FUNCTION(qsTranslate, this));
+ global->Set(v8::String::New("QT_TRANSLATE_NOOP"), V8FUNCTION(qsTranslateNoOp, this));
+ global->Set(v8::String::New("qsTr"), V8FUNCTION(qsTr, this));
+ global->Set(v8::String::New("QT_TR_NOOP"), V8FUNCTION(qsTrNoOp, this));
+ global->Set(v8::String::New("qsTrId"), V8FUNCTION(qsTrId, this));
+ global->Set(v8::String::New("QT_TRID_NOOP"), V8FUNCTION(qsTrIdNoOp, this));
+
+ global->Set(v8::String::New("print"), consoleLogFn);
+ global->Set(v8::String::New("console"), console);
+ global->Set(v8::String::New("Qt"), qt);
+ global->Set(v8::String::New("gc"), V8FUNCTION(QQmlBuiltinFunctions::gc, this));
+
+ {
+#define STRING_ARG "(function(stringArg) { "\
+ " String.prototype.arg = (function() {"\
+ " return stringArg.apply(this, arguments);"\
+ " })"\
+ "})"
+
+ v8::Local<v8::Script> registerArg = v8::Script::New(v8::String::New(STRING_ARG), 0, 0, v8::Handle<v8::String>(), v8::Script::NativeMode);
+ v8::Local<v8::Value> result = registerArg->Run();
+ Q_ASSERT(result->IsFunction());
+ v8::Local<v8::Function> registerArgFunc = v8::Local<v8::Function>::Cast(result);
+ v8::Handle<v8::Value> args = V8FUNCTION(stringArg, this);
+ registerArgFunc->Call(v8::Local<v8::Object>::Cast(registerArgFunc), 1, &args);
+#undef STRING_ARG
+ }
+
+ QQmlLocale::registerStringLocaleCompare(this);
+ QQmlDateExtension::registerExtension(this);
+ QQmlNumberExtension::registerExtension(this);
+
+ qt_add_domexceptions(this);
+ m_xmlHttpRequestData = qt_add_qmlxmlhttprequest(this);
+
+ qt_add_sqlexceptions(this);
+
+ {
+ v8::Handle<v8::Value> args[] = { global };
+ v8::Local<v8::Value> names = m_getOwnPropertyNames->Call(global, 1, args);
+ v8::Local<v8::Array> namesArray = v8::Local<v8::Array>::Cast(names);
+ for (quint32 ii = 0; ii < namesArray->Length(); ++ii)
+ m_illegalNames.insert(toString(namesArray->Get(ii)), true);
+ }
+
+ {
+#define FREEZE_SOURCE "(function freeze_recur(obj) { "\
+ " if (Qt.isQtObject(obj)) return;"\
+ " if (obj != Function.connect && obj != Function.disconnect && "\
+ " obj instanceof Object) {"\
+ " var properties = Object.getOwnPropertyNames(obj);"\
+ " for (var prop in properties) { "\
+ " if (prop == \"connect\" || prop == \"disconnect\") {"\
+ " Object.freeze(obj[prop]); "\
+ " continue;"\
+ " }"\
+ " freeze_recur(obj[prop]);"\
+ " }"\
+ " }"\
+ " if (obj instanceof Object) {"\
+ " Object.freeze(obj);"\
+ " }"\
+ "})"
+
+ v8::Local<v8::Script> freeze = v8::Script::New(v8::String::New(FREEZE_SOURCE));
+ v8::Local<v8::Value> result = freeze->Run();
+ Q_ASSERT(result->IsFunction());
+ m_freezeObject = qPersistentNew(v8::Local<v8::Function>::Cast(result));
+#undef FREEZE_SOURCE
+ }
+}
+
+void QV8Engine::freezeObject(v8::Handle<v8::Value> value)
+{
+ v8::Handle<v8::Value> args[] = { value };
+ m_freezeObject->Call(global(), 1, args);
+}
+
+void QV8Engine::gc()
+{
+ v8::V8::LowMemoryNotification();
+ while (!v8::V8::IdleNotification()) {}
+}
+
+#ifdef QML_GLOBAL_HANDLE_DEBUGGING
+#include <QtCore/qthreadstorage.h>
+static QThreadStorage<QSet<void *> *> QV8Engine_activeHandles;
+
+void QV8Engine::registerHandle(void *handle)
+{
+ if (!handle) {
+ qWarning("Attempting to register a null handle");
+ return;
+ }
+
+ if (!QV8Engine_activeHandles.hasLocalData())
+ QV8Engine_activeHandles.setLocalData(new QSet<void *>);
+
+ if (QV8Engine_activeHandles.localData()->contains(handle)) {
+ qFatal("Handle %p already alive", handle);
+ } else {
+ QV8Engine_activeHandles.localData()->insert(handle);
+ }
+}
+
+void QV8Engine::releaseHandle(void *handle)
+{
+ if (!handle)
+ return;
+
+ if (!QV8Engine_activeHandles.hasLocalData())
+ QV8Engine_activeHandles.setLocalData(new QSet<void *>);
+
+ if (QV8Engine_activeHandles.localData()->contains(handle)) {
+ QV8Engine_activeHandles.localData()->remove(handle);
+ } else {
+ qFatal("Handle %p already dead", handle);
+ }
+}
+#endif
+
+struct QV8EngineRegistrationData
+{
+ QV8EngineRegistrationData() : extensionCount(0) {}
+
+ QMutex mutex;
+ int extensionCount;
+};
+Q_GLOBAL_STATIC(QV8EngineRegistrationData, registrationData);
+
+QMutex *QV8Engine::registrationMutex()
+{
+ return &registrationData()->mutex;
+}
+
+int QV8Engine::registerExtension()
+{
+ return registrationData()->extensionCount++;
+}
+
+void QV8Engine::setExtensionData(int index, Deletable *data)
+{
+ if (m_extensionData.count() <= index)
+ m_extensionData.resize(index + 1);
+
+ if (m_extensionData.at(index))
+ delete m_extensionData.at(index);
+
+ m_extensionData[index] = data;
+}
+
+double QV8Engine::qtDateTimeToJsDate(const QDateTime &dt)
+{
+ // from QScriptEngine::DateTimeToMs()
+ if (!dt.isValid()) {
+ return qSNaN();
+ }
+ QDateTime utc = dt.toUTC();
+ QDate date = utc.date();
+ QTime time = utc.time();
+ QV8DateConverter::JSC::GregorianDateTime tm;
+ tm.year = date.year() - 1900;
+ tm.month = date.month() - 1;
+ tm.monthDay = date.day();
+ tm.weekDay = date.dayOfWeek();
+ tm.yearDay = date.dayOfYear();
+ tm.hour = time.hour();
+ tm.minute = time.minute();
+ tm.second = time.second();
+ return QV8DateConverter::JSC::gregorianDateTimeToMS(tm, time.msec());
+}
+
+v8::Persistent<v8::Object> *QV8Engine::findOwnerAndStrength(QObject *object, bool *shouldBeStrong)
+{
+ QObject *parent = object->parent();
+ if (!parent) {
+ // if the object has JS ownership, the object's v8object owns the lifetime of the persistent value.
+ if (QQmlEngine::objectOwnership(object) == QQmlEngine::JavaScriptOwnership) {
+ *shouldBeStrong = false;
+ return &(QQmlData::get(object)->v8object);
+ }
+
+ // no parent, and has CPP ownership - doesn't have an implicit parent.
+ *shouldBeStrong = true;
+ return 0;
+ }
+
+ // if it is owned by CPP, it's root parent may still be owned by JS.
+ // in that case, the owner of the persistent handle is the root parent's v8object.
+ while (parent->parent())
+ parent = parent->parent();
+
+ if (QQmlEngine::objectOwnership(parent) == QQmlEngine::JavaScriptOwnership) {
+ // root parent is owned by JS. It's v8object owns the persistent value in question.
+ *shouldBeStrong = false;
+ return &(QQmlData::get(parent)->v8object);
+ } else {
+ // root parent has CPP ownership. The persistent value should not be made weak.
+ *shouldBeStrong = true;
+ return 0;
+ }
+}
+
+QDateTime QV8Engine::qtDateTimeFromJsDate(double jsDate)
+{
+ // from QScriptEngine::MsToDateTime()
+ if (qIsNaN(jsDate))
+ return QDateTime();
+ QV8DateConverter::JSC::GregorianDateTime tm;
+ QV8DateConverter::JSC::msToGregorianDateTime(jsDate, tm);
+
+ // from QScriptEngine::MsFromTime()
+ int ms = int(::fmod(jsDate, 1000.0));
+ if (ms < 0)
+ ms += int(1000.0);
+
+ QDateTime convertedUTC = QDateTime(QDate(tm.year + 1900, tm.month + 1, tm.monthDay),
+ QTime(tm.hour, tm.minute, tm.second, ms), Qt::UTC);
+ return convertedUTC.toLocalTime();
+}
+
+void QV8Engine::addRelationshipForGC(QObject *object, v8::Persistent<v8::Value> handle)
+{
+ if (handle.IsEmpty())
+ return;
+
+ bool handleShouldBeStrong = false;
+ v8::Persistent<v8::Object> *implicitOwner = findOwnerAndStrength(object, &handleShouldBeStrong);
+ if (handleShouldBeStrong) {
+ v8::V8::AddImplicitReferences(m_strongReferencer, &handle, 1);
+ } else if (!implicitOwner->IsEmpty()) {
+ v8::V8::AddImplicitReferences(*implicitOwner, &handle, 1);
+ }
+}
+
+void QV8Engine::addRelationshipForGC(QObject *object, QObject *other)
+{
+ bool handleShouldBeStrong = false;
+ v8::Persistent<v8::Object> *implicitOwner = findOwnerAndStrength(object, &handleShouldBeStrong);
+ v8::Persistent<v8::Value> handle = QQmlData::get(other, true)->v8object;
+ if (handleShouldBeStrong) {
+ v8::V8::AddImplicitReferences(m_strongReferencer, &handle, 1);
+ } else if (!implicitOwner->IsEmpty()) {
+ v8::V8::AddImplicitReferences(*implicitOwner, &handle, 1);
+ }
+}
+
+static QThreadStorage<QV8Engine::ThreadData*> perThreadEngineData;
+
+bool QV8Engine::hasThreadData()
+{
+ return perThreadEngineData.hasLocalData();
+}
+
+QV8Engine::ThreadData *QV8Engine::threadData()
+{
+ Q_ASSERT(perThreadEngineData.hasLocalData());
+ return perThreadEngineData.localData();
+}
+
+void QV8Engine::ensurePerThreadIsolate()
+{
+ if (!perThreadEngineData.hasLocalData())
+ perThreadEngineData.setLocalData(new ThreadData);
+}
+
+void QV8Engine::initDeclarativeGlobalObject()
+{
+ v8::HandleScope handels;
+ v8::Context::Scope contextScope(m_context);
+ initializeGlobal(m_context->Global());
+ freezeObject(m_context->Global());
+}
+
+void QV8Engine::setEngine(QQmlEngine *engine)
+{
+ m_engine = engine;
+ initDeclarativeGlobalObject();
+}
+
+void QV8Engine::setException(v8::Handle<v8::Value> value, v8::Handle<v8::Message> msg)
+{
+ m_exception.set(value, msg);
+}
+
+v8::Handle<v8::Value> QV8Engine::throwException(v8::Handle<v8::Value> value)
+{
+ setException(value);
+ v8::ThrowException(value);
+ return value;
+}
+
+void QV8Engine::clearExceptions()
+{
+ m_exception.clear();
+}
+
+v8::Handle<v8::Value> QV8Engine::uncaughtException() const
+{
+ if (!hasUncaughtException())
+ return v8::Handle<v8::Value>();
+ return m_exception;
+}
+
+bool QV8Engine::hasUncaughtException() const
+{
+ return m_exception;
+}
+
+int QV8Engine::uncaughtExceptionLineNumber() const
+{
+ return m_exception.lineNumber();
+}
+
+QStringList QV8Engine::uncaughtExceptionBacktrace() const
+{
+ return m_exception.backtrace();
+}
+
+/*!
+ \internal
+ Save the current exception on stack so it can be set again later.
+ \sa QV8Engine::restoreException
+*/
+void QV8Engine::saveException()
+{
+ m_exception.push();
+}
+
+/*!
+ \internal
+ Load a saved exception from stack. Current exception, if exists will be dropped
+ \sa QV8Engine::saveException
+*/
+void QV8Engine::restoreException()
+{
+ m_exception.pop();
+}
+
+QV8Engine::Exception::Exception() {}
+
+QV8Engine::Exception::~Exception()
+{
+ Q_ASSERT_X(m_stack.isEmpty(), Q_FUNC_INFO, "Some saved exceptions left. Asymetric pop/push found.");
+ clear();
+}
+
+void QV8Engine::Exception::set(v8::Handle<v8::Value> value, v8::Handle<v8::Message> message)
+{
+ Q_ASSERT_X(!value.IsEmpty(), Q_FUNC_INFO, "Throwing an empty value handle is highly suspected");
+ clear();
+ m_value = v8::Persistent<v8::Value>::New(value);
+ m_message = v8::Persistent<v8::Message>::New(message);
+}
+
+void QV8Engine::Exception::clear()
+{
+ m_value.Dispose();
+ m_value.Clear();
+ m_message.Dispose();
+ m_message.Clear();
+}
+
+QV8Engine::Exception::operator bool() const
+{
+ return !m_value.IsEmpty();
+}
+
+QV8Engine::Exception::operator v8::Handle<v8::Value>() const
+{
+ Q_ASSERT(*this);
+ return m_value;
+}
+
+int QV8Engine::Exception::lineNumber() const
+{
+ if (m_message.IsEmpty())
+ return -1;
+ return m_message->GetLineNumber();
+}
+
+QStringList QV8Engine::Exception::backtrace() const
+{
+ if (m_message.IsEmpty())
+ return QStringList();
+
+ QStringList backtrace;
+ v8::Handle<v8::StackTrace> trace = m_message->GetStackTrace();
+ if (trace.IsEmpty())
+ // FIXME it should not happen (SetCaptureStackTraceForUncaughtExceptions is called).
+ return QStringList();
+
+ for (int i = 0; i < trace->GetFrameCount(); ++i) {
+ v8::Local<v8::StackFrame> frame = trace->GetFrame(i);
+ backtrace.append(QJSConverter::toString(frame->GetFunctionName()));
+ backtrace.append(QJSConverter::toString(frame->GetFunctionName()));
+ backtrace.append(QString::fromAscii("()@"));
+ backtrace.append(QJSConverter::toString(frame->GetScriptName()));
+ backtrace.append(QString::fromAscii(":"));
+ backtrace.append(QString::number(frame->GetLineNumber()));
+ }
+ return backtrace;
+}
+
+void QV8Engine::Exception::push()
+{
+ m_stack.push(qMakePair(m_value, m_message));
+ m_value.Clear();
+ m_message.Clear();
+}
+
+void QV8Engine::Exception::pop()
+{
+ Q_ASSERT_X(!m_stack.empty(), Q_FUNC_INFO, "Attempt to load unsaved exception found");
+ ValueMessagePair pair = m_stack.pop();
+ clear();
+ m_value = pair.first;
+ m_message = pair.second;
+}
+
+
+// Converts a QVariantList to JS.
+// The result is a new Array object with length equal to the length
+// of the QVariantList, and the elements being the QVariantList's
+// elements converted to JS, recursively.
+v8::Local<v8::Array> QV8Engine::variantListToJS(const QVariantList &lst)
+{
+ v8::Local<v8::Array> result = v8::Array::New(lst.size());
+ for (int i = 0; i < lst.size(); ++i)
+ result->Set(i, variantToJS(lst.at(i)));
+ return result;
+}
+
+// Converts a JS Array object to a QVariantList.
+// The result is a QVariantList with length equal to the length
+// of the JS Array, and elements being the JS Array's elements
+// converted to QVariants, recursively.
+QVariantList QV8Engine::variantListFromJS(v8::Handle<v8::Array> jsArray)
+{
+ QVariantList result;
+ int hash = jsArray->GetIdentityHash();
+ if (visitedConversionObjects.contains(hash))
+ return result; // Avoid recursion.
+ v8::HandleScope handleScope;
+ visitedConversionObjects.insert(hash);
+ uint32_t length = jsArray->Length();
+ for (uint32_t i = 0; i < length; ++i)
+ result.append(variantFromJS(jsArray->Get(i)));
+ visitedConversionObjects.remove(hash);
+ return result;
+}
+
+// Converts a QVariantMap to JS.
+// The result is a new Object object with property names being
+// the keys of the QVariantMap, and values being the values of
+// the QVariantMap converted to JS, recursively.
+v8::Local<v8::Object> QV8Engine::variantMapToJS(const QVariantMap &vmap)
+{
+ v8::Local<v8::Object> result = v8::Object::New();
+ QVariantMap::const_iterator it;
+ for (it = vmap.constBegin(); it != vmap.constEnd(); ++it)
+ result->Set(QJSConverter::toString(it.key()), variantToJS(it.value()));
+ return result;
+}
+
+// Converts a JS Object to a QVariantMap.
+// The result is a QVariantMap with keys being the property names
+// of the object, and values being the values of the JS object's
+// properties converted to QVariants, recursively.
+QVariantMap QV8Engine::variantMapFromJS(v8::Handle<v8::Object> jsObject)
+{
+ QVariantMap result;
+
+ v8::HandleScope handleScope;
+ v8::Handle<v8::Array> propertyNames = jsObject->GetPropertyNames();
+ uint32_t length = propertyNames->Length();
+ if (length == 0)
+ return result;
+
+ int hash = jsObject->GetIdentityHash();
+ if (visitedConversionObjects.contains(hash))
+ return result; // Avoid recursion.
+
+ visitedConversionObjects.insert(hash);
+ // TODO: Only object's own property names. Include non-enumerable properties.
+ for (uint32_t i = 0; i < length; ++i) {
+ v8::Handle<v8::Value> name = propertyNames->Get(i);
+ result.insert(QJSConverter::toString(name->ToString()), variantFromJS(jsObject->Get(name)));
+ }
+ visitedConversionObjects.remove(hash);
+ return result;
+}
+
+// Converts the meta-type defined by the given type and data to JS.
+// Returns the value if conversion succeeded, an empty handle otherwise.
+v8::Handle<v8::Value> QV8Engine::metaTypeToJS(int type, const void *data)
+{
+ Q_ASSERT(data != 0);
+ v8::Handle<v8::Value> result;
+
+ // check if it's one of the types we know
+ switch (QMetaType::Type(type)) {
+ case QMetaType::Void:
+ return v8::Undefined();
+ case QMetaType::Bool:
+ return v8::Boolean::New(*reinterpret_cast<const bool*>(data));
+ case QMetaType::Int:
+ return v8::Int32::New(*reinterpret_cast<const int*>(data));
+ case QMetaType::UInt:
+ return v8::Uint32::New(*reinterpret_cast<const uint*>(data));
+ case QMetaType::LongLong:
+ return v8::Number::New(double(*reinterpret_cast<const qlonglong*>(data)));
+ case QMetaType::ULongLong:
+#if defined(Q_OS_WIN) && defined(_MSC_FULL_VER) && _MSC_FULL_VER <= 12008804
+#pragma message("** NOTE: You need the Visual Studio Processor Pack to compile support for 64bit unsigned integers.")
+ return v8::Number::New(double((qlonglong)*reinterpret_cast<const qulonglong*>(data)));
+#elif defined(Q_CC_MSVC) && !defined(Q_CC_MSVC_NET)
+ return v8::Number::New(double((qlonglong)*reinterpret_cast<const qulonglong*>(data)));
+#else
+ return v8::Number::New(double(*reinterpret_cast<const qulonglong*>(data)));
+#endif
+ case QMetaType::Double:
+ return v8::Number::New(double(*reinterpret_cast<const double*>(data)));
+ case QMetaType::QString:
+ return QJSConverter::toString(*reinterpret_cast<const QString*>(data));
+ case QMetaType::Float:
+ return v8::Number::New(*reinterpret_cast<const float*>(data));
+ case QMetaType::Short:
+ return v8::Int32::New(*reinterpret_cast<const short*>(data));
+ case QMetaType::UShort:
+ return v8::Uint32::New(*reinterpret_cast<const unsigned short*>(data));
+ case QMetaType::Char:
+ return v8::Int32::New(*reinterpret_cast<const char*>(data));
+ case QMetaType::UChar:
+ return v8::Uint32::New(*reinterpret_cast<const unsigned char*>(data));
+ case QMetaType::QChar:
+ return v8::Uint32::New((*reinterpret_cast<const QChar*>(data)).unicode());
+ case QMetaType::QStringList:
+ result = QJSConverter::toStringList(*reinterpret_cast<const QStringList *>(data));
+ break;
+ case QMetaType::QVariantList:
+ result = variantListToJS(*reinterpret_cast<const QVariantList *>(data));
+ break;
+ case QMetaType::QVariantMap:
+ result = variantMapToJS(*reinterpret_cast<const QVariantMap *>(data));
+ break;
+ case QMetaType::QDateTime:
+ result = QJSConverter::toDateTime(*reinterpret_cast<const QDateTime *>(data));
+ break;
+ case QMetaType::QDate:
+ result = QJSConverter::toDateTime(QDateTime(*reinterpret_cast<const QDate *>(data)));
+ break;
+ case QMetaType::QRegExp:
+ result = QJSConverter::toRegExp(*reinterpret_cast<const QRegExp *>(data));
+ break;
+ case QMetaType::QObjectStar:
+ case QMetaType::QWidgetStar:
+ result = newQObject(*reinterpret_cast<QObject* const *>(data));
+ break;
+ case QMetaType::QVariant:
+ result = variantToJS(*reinterpret_cast<const QVariant*>(data));
+ break;
+ default:
+ if (type == qMetaTypeId<QJSValue>()) {
+ return QJSValuePrivate::get(*reinterpret_cast<const QJSValue*>(data))->asV8Value(this);
+ } else {
+ QByteArray typeName = QMetaType::typeName(type);
+ if (typeName.endsWith('*') && !*reinterpret_cast<void* const *>(data)) {
+ return v8::Null();
+ } else {
+ // Fall back to wrapping in a QVariant.
+ result = newVariant(QVariant(type, data));
+ }
+ }
+ }
+ return result;
+}
+
+// Converts a JS value to a meta-type.
+// data must point to a place that can store a value of the given type.
+// Returns true if conversion succeeded, false otherwise.
+bool QV8Engine::metaTypeFromJS(v8::Handle<v8::Value> value, int type, void *data) {
+ // check if it's one of the types we know
+ switch (QMetaType::Type(type)) {
+ case QMetaType::Bool:
+ *reinterpret_cast<bool*>(data) = value->ToBoolean()->Value();
+ return true;
+ case QMetaType::Int:
+ *reinterpret_cast<int*>(data) = value->ToInt32()->Value();
+ return true;
+ case QMetaType::UInt:
+ *reinterpret_cast<uint*>(data) = value->ToUint32()->Value();
+ return true;
+ case QMetaType::LongLong:
+ *reinterpret_cast<qlonglong*>(data) = qlonglong(value->ToInteger()->Value());
+ return true;
+ case QMetaType::ULongLong:
+ *reinterpret_cast<qulonglong*>(data) = qulonglong(value->ToInteger()->Value());
+ return true;
+ case QMetaType::Double:
+ *reinterpret_cast<double*>(data) = value->ToNumber()->Value();
+ return true;
+ case QMetaType::QString:
+ if (value->IsUndefined() || value->IsNull())
+ *reinterpret_cast<QString*>(data) = QString();
+ else
+ *reinterpret_cast<QString*>(data) = QJSConverter::toString(value->ToString());
+ return true;
+ case QMetaType::Float:
+ *reinterpret_cast<float*>(data) = value->ToNumber()->Value();
+ return true;
+ case QMetaType::Short:
+ *reinterpret_cast<short*>(data) = short(value->ToInt32()->Value());
+ return true;
+ case QMetaType::UShort:
+ *reinterpret_cast<unsigned short*>(data) = ushort(value->ToInt32()->Value()); // ### QScript::ToUInt16()
+ return true;
+ case QMetaType::Char:
+ *reinterpret_cast<char*>(data) = char(value->ToInt32()->Value());
+ return true;
+ case QMetaType::UChar:
+ *reinterpret_cast<unsigned char*>(data) = (unsigned char)(value->ToInt32()->Value());
+ return true;
+ case QMetaType::QChar:
+ if (value->IsString()) {
+ QString str = QJSConverter::toString(v8::Handle<v8::String>::Cast(value));
+ *reinterpret_cast<QChar*>(data) = str.isEmpty() ? QChar() : str.at(0);
+ } else {
+ *reinterpret_cast<QChar*>(data) = QChar(ushort(value->ToInt32()->Value())); // ### QScript::ToUInt16()
+ }
+ return true;
+ case QMetaType::QDateTime:
+ if (value->IsDate()) {
+ *reinterpret_cast<QDateTime *>(data) = QJSConverter::toDateTime(v8::Handle<v8::Date>::Cast(value));
+ return true;
+ } break;
+ case QMetaType::QDate:
+ if (value->IsDate()) {
+ *reinterpret_cast<QDate *>(data) = QJSConverter::toDateTime(v8::Handle<v8::Date>::Cast(value)).date();
+ return true;
+ } break;
+ case QMetaType::QRegExp:
+ if (value->IsRegExp()) {
+ *reinterpret_cast<QRegExp *>(data) = QJSConverter::toRegExp(v8::Handle<v8::RegExp>::Cast(value));
+ return true;
+ } break;
+ case QMetaType::QObjectStar:
+ if (isQObject(value) || value->IsNull()) {
+ *reinterpret_cast<QObject* *>(data) = qtObjectFromJS(value);
+ return true;
+ } break;
+ case QMetaType::QWidgetStar:
+ if (isQObject(value) || value->IsNull()) {
+ QObject *qo = qtObjectFromJS(value);
+ if (!qo || qo->isWidgetType()) {
+ *reinterpret_cast<QWidget* *>(data) = reinterpret_cast<QWidget*>(qo);
+ return true;
+ }
+ } break;
+ case QMetaType::QStringList:
+ if (value->IsArray()) {
+ *reinterpret_cast<QStringList *>(data) = QJSConverter::toStringList(v8::Handle<v8::Array>::Cast(value));
+ return true;
+ } break;
+ case QMetaType::QVariantList:
+ if (value->IsArray()) {
+ *reinterpret_cast<QVariantList *>(data) = variantListFromJS(v8::Handle<v8::Array>::Cast(value));
+ return true;
+ } break;
+ case QMetaType::QVariantMap:
+ if (value->IsObject()) {
+ *reinterpret_cast<QVariantMap *>(data) = variantMapFromJS(v8::Handle<v8::Object>::Cast(value));
+ return true;
+ } break;
+ case QMetaType::QVariant:
+ *reinterpret_cast<QVariant*>(data) = variantFromJS(value);
+ return true;
+ default:
+ ;
+ }
+
+#if 0
+ if (isQtVariant(value)) {
+ const QVariant &var = variantValue(value);
+ // ### Enable once constructInPlace() is in qt master.
+ if (var.userType() == type) {
+ QMetaType::constructInPlace(type, data, var.constData());
+ return true;
+ }
+ if (var.canConvert(QVariant::Type(type))) {
+ QVariant vv = var;
+ vv.convert(QVariant::Type(type));
+ Q_ASSERT(vv.userType() == type);
+ QMetaType::constructInPlace(type, data, vv.constData());
+ return true;
+ }
+
+ }
+#endif
+
+ // Try to use magic; for compatibility with qscriptvalue_cast.
+
+ QByteArray name = QMetaType::typeName(type);
+ if (convertToNativeQObject(value, name, reinterpret_cast<void* *>(data)))
+ return true;
+ if (isVariant(value) && name.endsWith('*')) {
+ int valueType = QMetaType::type(name.left(name.size()-1));
+ QVariant &var = variantValue(value);
+ if (valueType == var.userType()) {
+ // We have T t, T* is requested, so return &t.
+ *reinterpret_cast<void* *>(data) = var.data();
+ return true;
+ } else {
+ // Look in the prototype chain.
+ v8::Handle<v8::Value> proto = value->ToObject()->GetPrototype();
+ while (proto->IsObject()) {
+ bool canCast = false;
+ if (isVariant(proto)) {
+ canCast = (type == variantValue(proto).userType())
+ || (valueType && (valueType == variantValue(proto).userType()));
+ }
+ else if (isQObject(proto)) {
+ QByteArray className = name.left(name.size()-1);
+ if (QObject *qobject = qtObjectFromJS(proto))
+ canCast = qobject->qt_metacast(className) != 0;
+ }
+ if (canCast) {
+ QByteArray varTypeName = QMetaType::typeName(var.userType());
+ if (varTypeName.endsWith('*'))
+ *reinterpret_cast<void* *>(data) = *reinterpret_cast<void* *>(var.data());
+ else
+ *reinterpret_cast<void* *>(data) = var.data();
+ return true;
+ }
+ proto = proto->ToObject()->GetPrototype();
+ }
+ }
+ } else if (value->IsNull() && name.endsWith('*')) {
+ *reinterpret_cast<void* *>(data) = 0;
+ return true;
+ } else if (type == qMetaTypeId<QJSValue>()) {
+ *reinterpret_cast<QJSValue*>(data) = QJSValuePrivate::get(new QJSValuePrivate(this, value));
+ return true;
+ }
+
+ return false;
+}
+
+// Converts a QVariant to JS.
+v8::Handle<v8::Value> QV8Engine::variantToJS(const QVariant &value)
+{
+ return metaTypeToJS(value.userType(), value.constData());
+}
+
+// Converts a JS value to a QVariant.
+// Null, Undefined -> QVariant() (invalid)
+// Boolean -> QVariant(bool)
+// Number -> QVariant(double)
+// String -> QVariant(QString)
+// Array -> QVariantList(...)
+// Date -> QVariant(QDateTime)
+// RegExp -> QVariant(QRegExp)
+// [Any other object] -> QVariantMap(...)
+QVariant QV8Engine::variantFromJS(v8::Handle<v8::Value> value)
+{
+ Q_ASSERT(!value.IsEmpty());
+ if (value->IsNull() || value->IsUndefined())
+ return QVariant();
+ if (value->IsBoolean())
+ return value->ToBoolean()->Value();
+ if (value->IsInt32())
+ return value->ToInt32()->Value();
+ if (value->IsNumber())
+ return value->ToNumber()->Value();
+ if (value->IsString())
+ return QJSConverter::toString(value->ToString());
+ Q_ASSERT(value->IsObject());
+ if (value->IsArray())
+ return variantListFromJS(v8::Handle<v8::Array>::Cast(value));
+ if (value->IsDate())
+ return QJSConverter::toDateTime(v8::Handle<v8::Date>::Cast(value));
+ if (value->IsRegExp())
+ return QJSConverter::toRegExp(v8::Handle<v8::RegExp>::Cast(value));
+ if (isVariant(value))
+ return variantValue(value);
+ if (isQObject(value))
+ return qVariantFromValue(qtObjectFromJS(value));
+ return variantMapFromJS(value->ToObject());
+}
+
+bool QV8Engine::convertToNativeQObject(v8::Handle<v8::Value> value,
+ const QByteArray &targetType,
+ void **result)
+{
+ if (!targetType.endsWith('*'))
+ return false;
+ if (QObject *qobject = qtObjectFromJS(value)) {
+ int start = targetType.startsWith("const ") ? 6 : 0;
+ QByteArray className = targetType.mid(start, targetType.size()-start-1);
+ if (void *instance = qobject->qt_metacast(className)) {
+ *result = instance;
+ return true;
+ }
+ }
+ return false;
+}
+
+QObject *QV8Engine::qtObjectFromJS(v8::Handle<v8::Value> value)
+{
+ if (!value->IsObject())
+ return 0;
+
+ QV8ObjectResource *r = (QV8ObjectResource *)value->ToObject()->GetExternalResource();
+ if (!r)
+ return 0;
+ QV8ObjectResource::ResourceType type = r->resourceType();
+ if (type == QV8ObjectResource::QObjectType)
+ return qobjectWrapper()->toQObject(r);
+ else if (type == QV8ObjectResource::VariantType) {
+ QVariant variant = variantWrapper()->toVariant(r);
+ int type = variant.userType();
+ if ((type == QMetaType::QObjectStar) || (type == QMetaType::QWidgetStar))
+ return *reinterpret_cast<QObject* const *>(variant.constData());
+ }
+ return 0;
+}
+
+
+QVariant &QV8Engine::variantValue(v8::Handle<v8::Value> value)
+{
+ return variantWrapper()->variantValue(value);
+}
+
+// Creates a QVariant wrapper object.
+v8::Local<v8::Object> QV8Engine::newVariant(const QVariant &value)
+{
+ return variantWrapper()->newVariant(value);
+}
+
+QScriptPassPointer<QJSValuePrivate> QV8Engine::evaluate(v8::Handle<v8::Script> script, v8::TryCatch& tryCatch)
+{
+ v8::HandleScope handleScope;
+
+ clearExceptions();
+ if (script.IsEmpty()) {
+ v8::Handle<v8::Value> exception = tryCatch.Exception();
+ if (exception.IsEmpty()) {
+ // This is possible on syntax errors like { a:12, b:21 } <- missing "(", ")" around expression.
+ return new QJSValuePrivate(this);
+ }
+ setException(exception, tryCatch.Message());
+ return new QJSValuePrivate(this, exception);
+ }
+ v8::Handle<v8::Value> result;
+ result = script->Run();
+ if (result.IsEmpty()) {
+ v8::Handle<v8::Value> exception = tryCatch.Exception();
+ // TODO: figure out why v8 doesn't always produce an exception value
+ //Q_ASSERT(!exception.IsEmpty());
+ if (exception.IsEmpty())
+ exception = v8::Exception::Error(v8::String::New("missing exception value"));
+ setException(exception, tryCatch.Message());
+ return new QJSValuePrivate(this, exception);
+ }
+ return new QJSValuePrivate(this, result);
+}
+
+QJSValue QV8Engine::scriptValueFromInternal(v8::Handle<v8::Value> value) const
+{
+ if (value.IsEmpty())
+ return QJSValuePrivate::get(new QJSValuePrivate(const_cast<QV8Engine*>(this)));
+ return QJSValuePrivate::get(new QJSValuePrivate(const_cast<QV8Engine*>(this), value));
+}
+
+QScriptPassPointer<QJSValuePrivate> QV8Engine::newArray(uint length)
+{
+ return new QJSValuePrivate(this, v8::Array::New(length));
+}
+
+void QV8Engine::emitSignalHandlerException()
+{
+ emit q->signalHandlerException(scriptValueFromInternal(uncaughtException()));
+}
+
+void QV8Engine::startTimer(const QString &timerName)
+{
+ if (!m_time.isValid())
+ m_time.start();
+ m_startedTimers[timerName] = m_time.elapsed();
+}
+
+qint64 QV8Engine::stopTimer(const QString &timerName, bool *wasRunning)
+{
+ if (!m_startedTimers.contains(timerName)) {
+ *wasRunning = false;
+ return 0;
+ }
+ *wasRunning = true;
+ qint64 startedAt = m_startedTimers.take(timerName);
+ return m_time.elapsed() - startedAt;
+}
+
+int QV8Engine::consoleCountHelper(const QString &file, int line, int column)
+{
+ const QString key = file + QString::number(line) + QString::number(column);
+ int number = m_consoleCount.value(key, 0);
+ number++;
+ m_consoleCount.insert(key, number);
+ return number;
+}
+
+void QV8GCCallback::registerGcPrologueCallback()
+{
+ QV8Engine::ThreadData *td = QV8Engine::threadData();
+ if (!td->gcPrologueCallbackRegistered) {
+ td->gcPrologueCallbackRegistered = true;
+ v8::V8::AddGCPrologueCallback(QV8GCCallback::garbageCollectorPrologueCallback, v8::kGCTypeMarkSweepCompact);
+ }
+}
+
+QV8GCCallback::Node::Node(PrologueCallback callback)
+ : prologueCallback(callback)
+{
+}
+
+QV8GCCallback::Node::~Node()
+{
+ node.remove();
+}
+
+/*
+ Ensure that each persistent handle is strong if it has CPP ownership
+ and has no implicitly JS owned object owner in its parent chain, and
+ weak otherwise.
+
+ Any weak handle whose parent object is still alive will have an implicit
+ reference (between the parent and the handle) added, so that it will
+ not be collected.
+
+ Note that this callback is registered only for kGCTypeMarkSweepCompact
+ collection cycles, as it is during collection cycles of that type
+ in which weak persistent handle callbacks are called when required.
+ */
+void QV8GCCallback::garbageCollectorPrologueCallback(v8::GCType, v8::GCCallbackFlags)
+{
+ if (!QV8Engine::hasThreadData())
+ return;
+
+ QV8Engine::ThreadData *td = QV8Engine::threadData();
+ QV8GCCallback::Node *currNode = td->gcCallbackNodes.first();
+
+ while (currNode) {
+ // The client which adds itself to the list is responsible
+ // for maintaining the correct implicit references in the
+ // specified callback.
+ currNode->prologueCallback(currNode);
+ currNode = td->gcCallbackNodes.next(currNode);
+ }
+}
+
+void QV8GCCallback::addGcCallbackNode(QV8GCCallback::Node *node)
+{
+ QV8Engine::ThreadData *td = QV8Engine::threadData();
+ td->gcCallbackNodes.insert(node);
+}
+
+QV8Engine::ThreadData::ThreadData()
+ : gcPrologueCallbackRegistered(false)
+{
+ if (!v8::Isolate::GetCurrent()) {
+ isolate = v8::Isolate::New();
+ isolate->Enter();
+ } else {
+ isolate = 0;
+ }
+}
+
+QV8Engine::ThreadData::~ThreadData()
+{
+ if (isolate) {
+ isolate->Exit();
+ isolate->Dispose();
+ isolate = 0;
+ }
+}
+
+QT_END_NAMESPACE
+
diff --git a/src/qml/qml/v8/qv8engine_impl_p.h b/src/qml/qml/v8/qv8engine_impl_p.h
new file mode 100644
index 0000000000..ebb21f851c
--- /dev/null
+++ b/src/qml/qml/v8/qv8engine_impl_p.h
@@ -0,0 +1,155 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL-ONLY$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** If you have questions regarding the use of this file, please contact
+** us via http://www.qt-project.org/.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QV8ENGINE_IMPL_P_H
+#define QV8ENGINE_IMPL_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 "qv8engine_p.h"
+#include "qjsvalue_p.h"
+#include "qjsconverter_p.h"
+#include "qjsvalueiterator_p.h"
+
+QT_BEGIN_NAMESPACE
+
+inline v8::Handle<v8::Value> QV8Engine::makeJSValue(bool value)
+{
+ return value ? v8::True() : v8::False();
+}
+
+inline v8::Local<v8::Value> QV8Engine::makeJSValue(int value)
+{
+ return v8::Integer::New(value);
+}
+
+inline v8::Local<v8::Value> QV8Engine::makeJSValue(uint value)
+{
+ return v8::Integer::NewFromUnsigned(value);
+}
+
+inline v8::Local<v8::Value> QV8Engine::makeJSValue(double value)
+{
+ return v8::Number::New(value);
+}
+
+inline v8::Handle<v8::Value> QV8Engine::makeJSValue(QJSValue::SpecialValue value) {
+ if (value == QJSValue::NullValue)
+ return v8::Null();
+ return v8::Undefined();
+}
+
+inline v8::Local<v8::Value> QV8Engine::makeJSValue(const QString &value)
+{
+ return QJSConverter::toString(value);
+}
+
+class QtScriptBagCleaner
+{
+public:
+ template<class T>
+ void operator () (T* value) const
+ {
+ value->reinitialize();
+ }
+ void operator () (QJSValueIteratorPrivate *iterator) const
+ {
+ iterator->invalidate();
+ }
+};
+
+inline void QV8Engine::registerValue(QJSValuePrivate *data)
+{
+ m_values.insert(data);
+}
+
+inline void QV8Engine::unregisterValue(QJSValuePrivate *data)
+{
+ m_values.remove(data);
+}
+
+inline void QV8Engine::invalidateAllValues()
+{
+ ValueList::iterator it;
+ for (it = m_values.begin(); it != m_values.end(); it = it.erase())
+ (*it)->invalidate();
+ Q_ASSERT(m_values.isEmpty());
+}
+
+inline void QV8Engine::registerValueIterator(QJSValueIteratorPrivate *data)
+{
+ m_valueIterators.insert(data);
+}
+
+inline void QV8Engine::unregisterValueIterator(QJSValueIteratorPrivate *data)
+{
+ m_valueIterators.remove(data);
+}
+
+inline void QV8Engine::invalidateAllIterators()
+{
+ ValueIteratorList::iterator it;
+ for (it = m_valueIterators.begin(); it != m_valueIterators.end(); it = it.erase())
+ (*it)->invalidate();
+ Q_ASSERT(m_valueIterators.isEmpty());
+}
+
+/*!
+ \internal
+ \note property can be index (v8::Integer) or a property (v8::String) name, according to ECMA script
+ property would be converted to a string.
+*/
+inline QJSValuePrivate::PropertyFlags QV8Engine::getPropertyFlags(v8::Handle<v8::Object> object, v8::Handle<v8::Value> property)
+{
+ QJSValuePrivate::PropertyFlags flags = m_originalGlobalObject.getPropertyFlags(object, property);
+ return flags;
+}
+
+QScriptPassPointer<QJSValuePrivate> QV8Engine::evaluate(const QString& program, const QString& fileName, int lineNumber)
+{
+ v8::TryCatch tryCatch;
+ v8::ScriptOrigin scriptOrigin(QJSConverter::toString(fileName), v8::Integer::New(lineNumber - 1));
+ v8::Handle<v8::Script> script;
+ script = v8::Script::Compile(QJSConverter::toString(program), &scriptOrigin);
+ if (script.IsEmpty()) {
+ // TODO: Why don't we get the exception, as with Script::Compile()?
+ // Q_ASSERT(tryCatch.HasCaught());
+ v8::Handle<v8::Value> error = v8::Exception::SyntaxError(v8::String::New(""));
+ setException(error);
+ return new QJSValuePrivate(this, error);
+ }
+ return evaluate(script, tryCatch);
+}
+
+QT_END_NAMESPACE
+
+#endif // QV8ENGINE_IMPL_P_H
diff --git a/src/qml/qml/v8/qv8engine_p.h b/src/qml/qml/v8/qv8engine_p.h
new file mode 100644
index 0000000000..22a8d7599f
--- /dev/null
+++ b/src/qml/qml/v8/qv8engine_p.h
@@ -0,0 +1,631 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLV8ENGINE_P_H
+#define QQMLV8ENGINE_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qglobal.h>
+#include <QtCore/qvariant.h>
+#include <QtCore/qset.h>
+#include <QtCore/qmutex.h>
+#include <QtCore/qstack.h>
+#include <QtCore/qstringlist.h>
+#include <QtCore/QElapsedTimer>
+#include <QtCore/QThreadStorage>
+
+#include <private/qv8_p.h>
+#include <qjsengine.h>
+#include <qjsvalue.h>
+#include "qjsvalue_p.h"
+#include "qjsvalueiterator_p.h"
+#include "qscriptoriginalglobalobject_p.h"
+#include "qscripttools_p.h"
+
+#include <private/qqmlpropertycache_p.h>
+
+#include "qv8contextwrapper_p.h"
+#include "qv8qobjectwrapper_p.h"
+#include "qv8stringwrapper_p.h"
+#include "qv8typewrapper_p.h"
+#include "qv8listwrapper_p.h"
+#include "qv8variantwrapper_p.h"
+#include "qv8valuetypewrapper_p.h"
+#include "qv8sequencewrapper_p.h"
+
+QT_BEGIN_NAMESPACE
+
+
+// Uncomment the following line to enable global handle debugging. When enabled, all the persistent
+// handles allocated using qPersistentNew() (or registered with qPersistentRegsiter()) and disposed
+// with qPersistentDispose() are tracked. If you try and do something illegal, like double disposing
+// a handle, qFatal() is called.
+// #define QML_GLOBAL_HANDLE_DEBUGGING
+
+#define V8_RESOURCE_TYPE(resourcetype) \
+public: \
+ enum { V8ResourceType = QV8ObjectResource:: resourcetype }; \
+ virtual QV8ObjectResource::ResourceType resourceType() const { return QV8ObjectResource:: resourcetype; } \
+private:
+
+#define V8ENGINE() ((QV8Engine *)v8::External::Unwrap(args.Data()))
+#define V8FUNCTION(function, engine) v8::FunctionTemplate::New(function, v8::External::Wrap((QV8Engine*)engine))->GetFunction()
+#define V8THROW_ERROR(string) { \
+ v8::ThrowException(v8::Exception::Error(v8::String::New(string))); \
+ return v8::Handle<v8::Value>(); \
+}
+#define V8THROW_TYPE(string) { \
+ v8::ThrowException(v8::Exception::TypeError(v8::String::New(string))); \
+ return v8::Handle<v8::Value>(); \
+}
+#define V8ENGINE_ACCESSOR() ((QV8Engine *)v8::External::Unwrap(info.Data()));
+#define V8THROW_ERROR_SETTER(string) { \
+ v8::ThrowException(v8::Exception::Error(v8::String::New(string))); \
+ return; \
+}
+
+#define V8_DEFINE_EXTENSION(dataclass, datafunction) \
+ static inline dataclass *datafunction(QV8Engine *engine) \
+ { \
+ static int extensionId = -1; \
+ if (extensionId == -1) { \
+ QV8Engine::registrationMutex()->lock(); \
+ if (extensionId == -1) \
+ extensionId = QV8Engine::registerExtension(); \
+ QV8Engine::registrationMutex()->unlock(); \
+ } \
+ dataclass *rv = (dataclass *)engine->extensionData(extensionId); \
+ if (!rv) { \
+ rv = new dataclass(engine); \
+ engine->setExtensionData(extensionId, rv); \
+ } \
+ return rv; \
+ } \
+
+
+class QV8Engine;
+class QV8ObjectResource : public v8::Object::ExternalResource
+{
+public:
+ QV8ObjectResource(QV8Engine *engine) : engine(engine) { Q_ASSERT(engine); }
+ enum ResourceType { ContextType, QObjectType, TypeType, ListType, VariantType,
+ ValueTypeType, XMLHttpRequestType, DOMNodeType, SQLDatabaseType,
+ ListModelType, Context2DType, Context2DStyleType, Context2DPixelArrayType,
+ ParticleDataType, SignalHandlerType, IncubatorType, VisualDataItemType,
+ SequenceType, LocaleDataType };
+ virtual ResourceType resourceType() const = 0;
+
+ QV8Engine *engine;
+};
+
+template<class T>
+inline T *v8_resource_cast(v8::Handle<v8::Object> object) {
+ QV8ObjectResource *resource = static_cast<QV8ObjectResource *>(object->GetExternalResource());
+ return (resource && (quint32)resource->resourceType() == (quint32)T::V8ResourceType)?static_cast<T *>(resource):0;
+}
+
+template<class T>
+inline T *v8_resource_check(v8::Handle<v8::Object> object) {
+ T *resource = static_cast<T *>(object->GetExternalResource());
+ Q_ASSERT(resource && resource->resourceType() == (quint32)T::V8ResourceType);
+ return resource;
+}
+
+// Used to allow a QObject method take and return raw V8 handles without having to expose
+// v8 in the public API.
+// Use like this:
+// class MyClass : public QObject {
+// Q_OBJECT
+// ...
+// Q_INVOKABLE void myMethod(QQmlV8Function*);
+// };
+// The QQmlV8Function - and consequently the arguments and return value - only remains
+// valid during the call. If the return value isn't set within myMethod(), the will return
+// undefined.
+class QV8Engine;
+class QQmlV8Function
+{
+public:
+ int Length() const { return _ac; }
+ v8::Local<v8::Value> operator[](int idx) { return (*_a)->Get(idx); }
+ QQmlContextData *context() { return _c; }
+ v8::Handle<v8::Object> qmlGlobal() { return *_g; }
+ void returnValue(v8::Handle<v8::Value> rv) { *_r = rv; }
+ QV8Engine *engine() const { return _e; }
+private:
+ friend class QV8QObjectWrapper;
+ QQmlV8Function();
+ QQmlV8Function(const QQmlV8Function &);
+ QQmlV8Function &operator=(const QQmlV8Function &);
+
+ QQmlV8Function(int length, v8::Handle<v8::Object> &args,
+ v8::Handle<v8::Value> &rv, v8::Handle<v8::Object> &global,
+ QQmlContextData *c, QV8Engine *e)
+ : _ac(length), _a(&args), _r(&rv), _g(&global), _c(c), _e(e) {}
+
+ int _ac;
+ v8::Handle<v8::Object> *_a;
+ v8::Handle<v8::Value> *_r;
+ v8::Handle<v8::Object> *_g;
+ QQmlContextData *_c;
+ QV8Engine *_e;
+};
+
+class QQmlV8Handle
+{
+public:
+ QQmlV8Handle() : d(0) {}
+ QQmlV8Handle(const QQmlV8Handle &other) : d(other.d) {}
+ QQmlV8Handle &operator=(const QQmlV8Handle &other) { d = other.d; return *this; }
+
+ static QQmlV8Handle fromHandle(v8::Handle<v8::Value> h) {
+ return QQmlV8Handle(*h);
+ }
+ v8::Handle<v8::Value> toHandle() const {
+ return v8::Handle<v8::Value>((v8::Value *)d);
+ }
+private:
+ QQmlV8Handle(void *d) : d(d) {}
+ void *d;
+};
+
+class QObject;
+class QQmlEngine;
+class QQmlValueType;
+class QNetworkAccessManager;
+class QQmlContextData;
+
+class Q_AUTOTEST_EXPORT QV8GCCallback
+{
+private:
+ class ThreadData;
+public:
+ static void garbageCollectorPrologueCallback(v8::GCType, v8::GCCallbackFlags);
+ static void registerGcPrologueCallback();
+
+ class Q_AUTOTEST_EXPORT Node {
+ public:
+ typedef void (*PrologueCallback)(Node *node);
+ Node(PrologueCallback callback);
+ ~Node();
+
+ QIntrusiveListNode node;
+ PrologueCallback prologueCallback;
+ };
+
+ static void addGcCallbackNode(Node *node);
+};
+
+class Q_QML_EXPORT QV8Engine
+{
+public:
+ static QV8Engine* get(QJSEngine* q) { Q_ASSERT(q); return q->handle(); }
+ static QJSEngine* get(QV8Engine* d) { Q_ASSERT(d); return d->q; }
+
+ QV8Engine(QJSEngine* qq,QJSEngine::ContextOwnership ownership = QJSEngine::CreateNewContext);
+ virtual ~QV8Engine();
+
+ // This enum should be in sync with QQmlEngine::ObjectOwnership
+ enum ObjectOwnership { CppOwnership, JavaScriptOwnership };
+
+ struct Deletable {
+ virtual ~Deletable() {}
+ };
+
+ class Exception
+ {
+ typedef QPair<v8::Persistent<v8::Value>, v8::Persistent<v8::Message> > ValueMessagePair;
+
+ v8::Persistent<v8::Value> m_value;
+ v8::Persistent<v8::Message> m_message;
+ QStack<ValueMessagePair> m_stack;
+
+ Q_DISABLE_COPY(Exception)
+ public:
+ inline Exception();
+ inline ~Exception();
+ inline void set(v8::Handle<v8::Value> value, v8::Handle<v8::Message> message);
+ inline void clear();
+ inline operator bool() const;
+ inline operator v8::Handle<v8::Value>() const;
+ inline int lineNumber() const;
+ inline QStringList backtrace() const;
+
+ inline void push();
+ inline void pop();
+ };
+
+ void initDeclarativeGlobalObject();
+ void setEngine(QQmlEngine *engine);
+ QQmlEngine *engine() { return m_engine; }
+ v8::Local<v8::Object> global() { return m_context->Global(); }
+ v8::Handle<v8::Context> context() const { return m_context; }
+
+ inline void registerValue(QJSValuePrivate *data);
+ inline void unregisterValue(QJSValuePrivate *data);
+ inline void invalidateAllValues();
+
+ inline void registerValueIterator(QJSValueIteratorPrivate *data);
+ inline void unregisterValueIterator(QJSValueIteratorPrivate *data);
+ inline void invalidateAllIterators();
+
+ QV8ContextWrapper *contextWrapper() { return &m_contextWrapper; }
+ QV8QObjectWrapper *qobjectWrapper() { return &m_qobjectWrapper; }
+ QV8TypeWrapper *typeWrapper() { return &m_typeWrapper; }
+ QV8ListWrapper *listWrapper() { return &m_listWrapper; }
+ QV8VariantWrapper *variantWrapper() { return &m_variantWrapper; }
+ QV8ValueTypeWrapper *valueTypeWrapper() { return &m_valueTypeWrapper; }
+ QV8SequenceWrapper *sequenceWrapper() { return &m_sequenceWrapper; }
+
+ void *xmlHttpRequestData() { return m_xmlHttpRequestData; }
+
+ Deletable *listModelData() { return m_listModelData; }
+ void setListModelData(Deletable *d) { if (m_listModelData) delete m_listModelData; m_listModelData = d; }
+
+ QQmlContextData *callingContext();
+
+ v8::Local<v8::Array> getOwnPropertyNames(v8::Handle<v8::Object>);
+ inline QJSValuePrivate::PropertyFlags getPropertyFlags(v8::Handle<v8::Object> object, v8::Handle<v8::Value> property);
+ void freezeObject(v8::Handle<v8::Value>);
+
+ inline QString toString(v8::Handle<v8::Value> string);
+ inline QString toString(v8::Handle<v8::String> string);
+ static QString toStringStatic(v8::Handle<v8::Value>);
+ static QString toStringStatic(v8::Handle<v8::String>);
+ static inline bool startsWithUpper(v8::Handle<v8::String>);
+
+ QVariant toVariant(v8::Handle<v8::Value>, int typeHint);
+ v8::Handle<v8::Value> fromVariant(const QVariant &);
+ inline bool isVariant(v8::Handle<v8::Value>);
+
+ // Compile \a source (from \a fileName at \a lineNumber) in QML mode
+ v8::Local<v8::Script> qmlModeCompile(const QString &source,
+ const QString &fileName = QString(),
+ int lineNumber = 1);
+ v8::Local<v8::Script> qmlModeCompile(const char *source, int sourceLength = -1,
+ const QString &fileName = QString(),
+ int lineNumber = 1);
+
+ // Return the QML global "scope" object for the \a ctxt context and \a scope object.
+ inline v8::Local<v8::Object> qmlScope(QQmlContextData *ctxt, QObject *scope);
+
+ // Return a JS wrapper for the given QObject \a object
+ inline v8::Handle<v8::Value> newQObject(QObject *object);
+ inline v8::Handle<v8::Value> newQObject(QObject *object, const ObjectOwnership ownership);
+ inline bool isQObject(v8::Handle<v8::Value>);
+ inline QObject *toQObject(v8::Handle<v8::Value>);
+
+ // Return a JS string for the given QString \a string
+ inline v8::Local<v8::String> toString(const QString &string);
+
+ // Create a new value type object
+ inline v8::Handle<v8::Value> newValueType(QObject *, int coreIndex, QQmlValueType *);
+ inline v8::Handle<v8::Value> newValueType(const QVariant &, QQmlValueType *);
+
+ // Create a new sequence type object
+ inline v8::Handle<v8::Value> newSequence(int sequenceType, QObject *, int coreIndex, bool *succeeded);
+
+ // Create a new QVariant object. This doesn't examine the type of the variant, but always returns
+ // a QVariant wrapper
+ inline v8::Handle<v8::Value> newQVariant(const QVariant &);
+
+ // Return the network access manager for this engine. By default this returns the network
+ // access manager of the QQmlEngine. It is overridden in the case of a threaded v8
+ // instance (like in WorkerScript).
+ virtual QNetworkAccessManager *networkAccessManager();
+
+ // Return the list of illegal id names (the names of the properties on the global object)
+ const QStringHash<bool> &illegalNames() const;
+
+ inline void collectGarbage() { gc(); }
+ static void gc();
+
+ void clearExceptions();
+ void setException(v8::Handle<v8::Value> value, v8::Handle<v8::Message> message = v8::Handle<v8::Message>());
+ v8::Handle<v8::Value> throwException(v8::Handle<v8::Value> value);
+ bool hasUncaughtException() const;
+ int uncaughtExceptionLineNumber() const;
+ QStringList uncaughtExceptionBacktrace() const;
+ v8::Handle<v8::Value> uncaughtException() const;
+ void saveException();
+ void restoreException();
+
+#ifdef QML_GLOBAL_HANDLE_DEBUGGING
+ // Used for handle debugging
+ static void registerHandle(void *);
+ static void releaseHandle(void *);
+#endif
+
+ static QMutex *registrationMutex();
+ static int registerExtension();
+
+ inline Deletable *extensionData(int) const;
+ void setExtensionData(int, Deletable *);
+
+ inline v8::Handle<v8::Value> makeJSValue(bool value);
+ inline v8::Local<v8::Value> makeJSValue(int value);
+ inline v8::Local<v8::Value> makeJSValue(uint value);
+ inline v8::Local<v8::Value> makeJSValue(double value);
+ inline v8::Handle<v8::Value> makeJSValue(QJSValue::SpecialValue value);
+ inline v8::Local<v8::Value> makeJSValue(const QString &value);
+
+ inline QScriptPassPointer<QJSValuePrivate> evaluate(const QString &program, const QString &fileName = QString(), int lineNumber = 1);
+ QScriptPassPointer<QJSValuePrivate> evaluate(v8::Handle<v8::Script> script, v8::TryCatch& tryCatch);
+
+ QScriptPassPointer<QJSValuePrivate> newArray(uint length);
+ v8::Local<v8::Object> newVariant(const QVariant &variant);
+
+ v8::Local<v8::Array> variantListToJS(const QVariantList &lst);
+ QVariantList variantListFromJS(v8::Handle<v8::Array> jsArray);
+
+ v8::Local<v8::Object> variantMapToJS(const QVariantMap &vmap);
+ QVariantMap variantMapFromJS(v8::Handle<v8::Object> jsObject);
+
+ v8::Handle<v8::Value> variantToJS(const QVariant &value);
+ QVariant variantFromJS(v8::Handle<v8::Value> value);
+
+ v8::Handle<v8::Value> metaTypeToJS(int type, const void *data);
+ bool metaTypeFromJS(v8::Handle<v8::Value> value, int type, void *data);
+
+ bool convertToNativeQObject(v8::Handle<v8::Value> value,
+ const QByteArray &targetType,
+ void **result);
+
+ QVariant &variantValue(v8::Handle<v8::Value> value);
+
+ QJSValue scriptValueFromInternal(v8::Handle<v8::Value>) const;
+
+ void emitSignalHandlerException();
+
+ // used for console.time(), console.timeEnd()
+ void startTimer(const QString &timerName);
+ qint64 stopTimer(const QString &timerName, bool *wasRunning);
+
+ // used for console.count()
+ int consoleCountHelper(const QString &file, int line, int column);
+
+ QObject *qtObjectFromJS(v8::Handle<v8::Value> value);
+ QSet<int> visitedConversionObjects;
+
+ static QDateTime qtDateTimeFromJsDate(double jsDate);
+
+ void addRelationshipForGC(QObject *object, v8::Persistent<v8::Value> handle);
+ void addRelationshipForGC(QObject *object, QObject *other);
+
+ struct ThreadData {
+ ThreadData();
+ ~ThreadData();
+ v8::Isolate* isolate;
+ bool gcPrologueCallbackRegistered;
+ QIntrusiveList<QV8GCCallback::Node, &QV8GCCallback::Node::node> gcCallbackNodes;
+ };
+
+ static bool hasThreadData();
+ static ThreadData* threadData();
+ static void ensurePerThreadIsolate();
+
+ v8::Persistent<v8::Object> m_strongReferencer;
+
+protected:
+ QJSEngine* q;
+ QQmlEngine *m_engine;
+ bool m_ownsV8Context;
+ v8::Persistent<v8::Context> m_context;
+ QScriptOriginalGlobalObject m_originalGlobalObject;
+
+ QV8StringWrapper m_stringWrapper;
+ QV8ContextWrapper m_contextWrapper;
+ QV8QObjectWrapper m_qobjectWrapper;
+ QV8TypeWrapper m_typeWrapper;
+ QV8ListWrapper m_listWrapper;
+ QV8VariantWrapper m_variantWrapper;
+ QV8ValueTypeWrapper m_valueTypeWrapper;
+ QV8SequenceWrapper m_sequenceWrapper;
+
+ v8::Persistent<v8::Function> m_getOwnPropertyNames;
+ v8::Persistent<v8::Function> m_freezeObject;
+
+ void *m_xmlHttpRequestData;
+
+ QVector<Deletable *> m_extensionData;
+ Deletable *m_listModelData;
+
+ QStringHash<bool> m_illegalNames;
+
+ Exception m_exception;
+
+ QElapsedTimer m_time;
+ QHash<QString, qint64> m_startedTimers;
+
+ QHash<QString, quint32> m_consoleCount;
+
+ QVariant toBasicVariant(v8::Handle<v8::Value>);
+
+ void initializeGlobal(v8::Handle<v8::Object>);
+
+ double qtDateTimeToJsDate(const QDateTime &dt);
+
+private:
+ static v8::Persistent<v8::Object> *findOwnerAndStrength(QObject *object, bool *shouldBeStrong);
+
+ typedef QScriptIntrusiveList<QJSValuePrivate, &QJSValuePrivate::m_node> ValueList;
+ ValueList m_values;
+ typedef QScriptIntrusiveList<QJSValueIteratorPrivate, &QJSValueIteratorPrivate::m_node> ValueIteratorList;
+ ValueIteratorList m_valueIterators;
+
+ Q_DISABLE_COPY(QV8Engine)
+};
+
+// Allocate a new Persistent handle. *ALL* persistent handles in QML must be allocated
+// using this method.
+template<class T>
+v8::Persistent<T> qPersistentNew(v8::Handle<T> that)
+{
+ v8::Persistent<T> rv = v8::Persistent<T>::New(that);
+#ifdef QML_GLOBAL_HANDLE_DEBUGGING
+ QV8Engine::registerHandle(*rv);
+#endif
+ return rv;
+}
+
+// Register a Persistent handle that was returned to you by V8 (such as by
+// v8::Context::New). This allows us to do handle tracking on these handles too.
+template<class T>
+void qPersistentRegister(v8::Persistent<T> handle)
+{
+#ifdef QML_GLOBAL_HANDLE_DEBUGGING
+ QV8Engine::registerHandle(*handle);
+#else
+ Q_UNUSED(handle);
+#endif
+}
+
+// Dispose and clear a persistent handle. *ALL* persistent handles in QML must be
+// disposed using this method.
+template<class T>
+void qPersistentDispose(v8::Persistent<T> &that)
+{
+#ifdef QML_GLOBAL_HANDLE_DEBUGGING
+ QV8Engine::releaseHandle(*that);
+#endif
+ that.Dispose();
+ that.Clear();
+}
+
+QString QV8Engine::toString(v8::Handle<v8::Value> string)
+{
+ return m_stringWrapper.toString(string->ToString());
+}
+
+QString QV8Engine::toString(v8::Handle<v8::String> string)
+{
+ return m_stringWrapper.toString(string);
+}
+
+bool QV8Engine::isVariant(v8::Handle<v8::Value> value)
+{
+ return m_variantWrapper.isVariant(value);
+}
+
+v8::Local<v8::Object> QV8Engine::qmlScope(QQmlContextData *ctxt, QObject *scope)
+{
+ return m_contextWrapper.qmlScope(ctxt, scope);
+}
+
+bool QV8Engine::isQObject(v8::Handle<v8::Value> obj)
+{
+ return obj->IsObject()?m_qobjectWrapper.isQObject(v8::Handle<v8::Object>::Cast(obj)):false;
+}
+
+QObject *QV8Engine::toQObject(v8::Handle<v8::Value> obj)
+{
+ return obj->IsObject()?m_qobjectWrapper.toQObject(v8::Handle<v8::Object>::Cast(obj)):0;
+}
+
+v8::Handle<v8::Value> QV8Engine::newQObject(QObject *object)
+{
+ return m_qobjectWrapper.newQObject(object);
+}
+
+v8::Handle<v8::Value> QV8Engine::newQObject(QObject *object, const ObjectOwnership ownership)
+{
+ if (!object)
+ return v8::Null();
+
+ v8::Handle<v8::Value> result = newQObject(object);
+ QQmlData *ddata = QQmlData::get(object, true);
+ if (ownership == JavaScriptOwnership && ddata) {
+ ddata->indestructible = false;
+ ddata->explicitIndestructibleSet = true;
+ }
+ return result;
+}
+
+v8::Local<v8::String> QV8Engine::toString(const QString &string)
+{
+ return m_stringWrapper.toString(string);
+}
+
+v8::Handle<v8::Value> QV8Engine::newValueType(QObject *object, int property, QQmlValueType *type)
+{
+ return m_valueTypeWrapper.newValueType(object, property, type);
+}
+
+v8::Handle<v8::Value> QV8Engine::newValueType(const QVariant &value, QQmlValueType *type)
+{
+ return m_valueTypeWrapper.newValueType(value, type);
+}
+
+v8::Handle<v8::Value> QV8Engine::newSequence(int sequenceType, QObject *object, int property, bool *succeeded)
+{
+ return m_sequenceWrapper.newSequence(sequenceType, object, property, succeeded);
+}
+
+// XXX Can this be made more optimal? It is called prior to resolving each and every
+// unqualified name in QV8ContextWrapper.
+bool QV8Engine::startsWithUpper(v8::Handle<v8::String> string)
+{
+ uint16_t c = string->GetCharacter(0);
+ return (c >= 'A' && c <= 'Z') ||
+ (c > 127 && QChar::category(c) == QChar::Letter_Uppercase);
+}
+
+QV8Engine::Deletable *QV8Engine::extensionData(int index) const
+{
+ if (index < m_extensionData.count())
+ return m_extensionData[index];
+ else
+ return 0;
+}
+
+QT_END_NAMESPACE
+
+#endif // QQMLV8ENGINE_P_H
diff --git a/src/qml/qml/v8/qv8include.cpp b/src/qml/qml/v8/qv8include.cpp
new file mode 100644
index 0000000000..89f60f256e
--- /dev/null
+++ b/src/qml/qml/v8/qv8include.cpp
@@ -0,0 +1,244 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qv8include_p.h"
+
+#include <QtQml/qjsengine.h>
+#include <QtNetwork/qnetworkrequest.h>
+#include <QtNetwork/qnetworkreply.h>
+#include <QtCore/qfile.h>
+
+#include <private/qqmlengine_p.h>
+
+QT_BEGIN_NAMESPACE
+
+QV8Include::QV8Include(const QUrl &url, QV8Engine *engine, QQmlContextData *context,
+ v8::Handle<v8::Object> qmlglobal, v8::Handle<v8::Function> callback)
+: m_engine(engine), m_network(0), m_reply(0), m_url(url), m_redirectCount(0), m_context(context)
+{
+ m_qmlglobal = qPersistentNew<v8::Object>(qmlglobal);
+ if (!callback.IsEmpty())
+ m_callbackFunction = qPersistentNew<v8::Function>(callback);
+
+ m_resultObject = qPersistentNew<v8::Object>(resultValue());
+
+ m_network = engine->networkAccessManager();
+
+ QNetworkRequest request;
+ request.setUrl(url);
+
+ m_reply = m_network->get(request);
+ QObject::connect(m_reply, SIGNAL(finished()), this, SLOT(finished()));
+}
+
+QV8Include::~QV8Include()
+{
+ delete m_reply; m_reply = 0;
+ qPersistentDispose(m_callbackFunction);
+ qPersistentDispose(m_resultObject);
+}
+
+v8::Local<v8::Object> QV8Include::resultValue(Status status)
+{
+ // XXX It seems inefficient to create this object from scratch each time.
+ v8::Local<v8::Object> result = v8::Object::New();
+ result->Set(v8::String::New("OK"), v8::Integer::New(Ok));
+ result->Set(v8::String::New("LOADING"), v8::Integer::New(Loading));
+ result->Set(v8::String::New("NETWORK_ERROR"), v8::Integer::New(NetworkError));
+ result->Set(v8::String::New("EXCEPTION"), v8::Integer::New(Exception));
+
+ result->Set(v8::String::New("status"), v8::Integer::New(status));
+
+ return result;
+}
+
+void QV8Include::callback(QV8Engine *engine, v8::Handle<v8::Function> callback, v8::Handle<v8::Object> status)
+{
+ if (!callback.IsEmpty()) {
+ v8::Handle<v8::Value> args[] = { status };
+ v8::TryCatch tc;
+ callback->Call(engine->global(), 1, args);
+ }
+}
+
+v8::Handle<v8::Object> QV8Include::result()
+{
+ return m_resultObject;
+}
+
+#define INCLUDE_MAXIMUM_REDIRECT_RECURSION 15
+void QV8Include::finished()
+{
+ m_redirectCount++;
+
+ if (m_redirectCount < INCLUDE_MAXIMUM_REDIRECT_RECURSION) {
+ QVariant redirect = m_reply->attribute(QNetworkRequest::RedirectionTargetAttribute);
+ if (redirect.isValid()) {
+ m_url = m_url.resolved(redirect.toUrl());
+ delete m_reply;
+
+ QNetworkRequest request;
+ request.setUrl(m_url);
+
+ m_reply = m_network->get(request);
+ QObject::connect(m_reply, SIGNAL(finished()), this, SLOT(finished()));
+ return;
+ }
+ }
+
+ v8::HandleScope handle_scope;
+
+ if (m_reply->error() == QNetworkReply::NoError) {
+ QByteArray data = m_reply->readAll();
+
+ QString code = QString::fromUtf8(data);
+ QQmlScript::Parser::extractPragmas(code);
+
+ QQmlContextData *importContext = new QQmlContextData;
+ importContext->isInternal = true;
+ importContext->isJSContext = true;
+ importContext->url = m_url;
+ importContext->isPragmaLibraryContext = m_context->isPragmaLibraryContext;
+ importContext->setParent(m_context, true);
+
+ v8::Context::Scope ctxtscope(m_engine->context());
+ v8::TryCatch try_catch;
+
+ v8::Local<v8::Script> script = m_engine->qmlModeCompile(code, m_url.toString());
+
+ if (!try_catch.HasCaught()) {
+ m_engine->contextWrapper()->addSubContext(m_qmlglobal, script, importContext);
+ script->Run(m_qmlglobal);
+ }
+
+ if (try_catch.HasCaught()) {
+ m_resultObject->Set(v8::String::New("status"), v8::Integer::New(Exception));
+ m_resultObject->Set(v8::String::New("exception"), try_catch.Exception());
+ } else {
+ m_resultObject->Set(v8::String::New("status"), v8::Integer::New(Ok));
+ }
+ } else {
+ m_resultObject->Set(v8::String::New("status"), v8::Integer::New(NetworkError));
+ }
+
+ callback(m_engine, m_callbackFunction, m_resultObject);
+
+ disconnect();
+ deleteLater();
+}
+
+/*
+ Documented in qv8engine.cpp
+*/
+v8::Handle<v8::Value> QV8Include::include(const v8::Arguments &args)
+{
+ if (args.Length() == 0)
+ return v8::Undefined();
+
+ QV8Engine *engine = V8ENGINE();
+ QQmlContextData *context = engine->callingContext();
+
+ if (!context || !context->isJSContext)
+ V8THROW_ERROR("Qt.include(): Can only be called from JavaScript files");
+
+ QUrl url(context->resolvedUrl(QUrl(engine->toString(args[0]->ToString()))));
+
+ v8::Local<v8::Function> callbackFunction;
+ if (args.Length() >= 2 && args[1]->IsFunction())
+ callbackFunction = v8::Local<v8::Function>::Cast(args[1]);
+
+ QString localFile = QQmlEnginePrivate::urlToLocalFileOrQrc(url);
+
+ v8::Local<v8::Object> result;
+
+ if (localFile.isEmpty()) {
+
+ QV8Include *i = new QV8Include(url, engine, context,
+ v8::Context::GetCallingQmlGlobal(),
+ callbackFunction);
+ result = v8::Local<v8::Object>::New(i->result());
+
+ } else {
+
+ QFile f(localFile);
+
+ if (f.open(QIODevice::ReadOnly)) {
+ QByteArray data = f.readAll();
+ QString code = QString::fromUtf8(data);
+ QQmlScript::Parser::extractPragmas(code);
+
+ QQmlContextData *importContext = new QQmlContextData;
+ importContext->isInternal = true;
+ importContext->isJSContext = true;
+ importContext->url = url;
+ importContext->setParent(context, true);
+
+ v8::TryCatch try_catch;
+
+ v8::Local<v8::Script> script = engine->qmlModeCompile(code, url.toString());
+
+ if (!try_catch.HasCaught()) {
+ v8::Local<v8::Object> qmlglobal = v8::Context::GetCallingQmlGlobal();
+ engine->contextWrapper()->addSubContext(qmlglobal, script, importContext);
+ script->Run(qmlglobal);
+ }
+
+ if (try_catch.HasCaught()) {
+ result = resultValue(Exception);
+ result->Set(v8::String::New("exception"), try_catch.Exception());
+ } else {
+ result = resultValue(Ok);
+ }
+
+ } else {
+ result = resultValue(NetworkError);
+ }
+
+ callback(engine, callbackFunction, result);
+ }
+
+ if (result.IsEmpty())
+ return v8::Undefined();
+ else
+ return result;
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/v8/qv8include_p.h b/src/qml/qml/v8/qv8include_p.h
new file mode 100644
index 0000000000..f1e57b3eee
--- /dev/null
+++ b/src/qml/qml/v8/qv8include_p.h
@@ -0,0 +1,113 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QV8INCLUDE_P_H
+#define QV8INCLUDE_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qobject.h>
+#include <QtCore/qurl.h>
+
+#include <private/qqmlcontext_p.h>
+#include <private/qqmlguard_p.h>
+
+#include <private/qv8_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQmlEngine;
+class QNetworkAccessManager;
+class QNetworkReply;
+class QV8Engine;
+class QV8Include : public QObject
+{
+ Q_OBJECT
+public:
+ enum Status {
+ Ok = 0,
+ Loading = 1,
+ NetworkError = 2,
+ Exception = 3
+ };
+
+ static v8::Handle<v8::Value> include(const v8::Arguments &args);
+
+private slots:
+ void finished();
+
+private:
+ QV8Include(const QUrl &, QV8Engine *, QQmlContextData *,
+ v8::Handle<v8::Object>, v8::Handle<v8::Function>);
+ ~QV8Include();
+
+ v8::Handle<v8::Object> result();
+
+ static v8::Local<v8::Object> resultValue(Status status = Loading);
+ static void callback(QV8Engine *engine, v8::Handle<v8::Function> callback, v8::Handle<v8::Object> status);
+
+ QV8Engine *m_engine;
+ QNetworkAccessManager *m_network;
+ QQmlGuard<QNetworkReply> m_reply;
+
+ QUrl m_url;
+ int m_redirectCount;
+
+ v8::Persistent<v8::Function> m_callbackFunction;
+ v8::Persistent<v8::Object> m_resultObject;
+
+ QQmlGuardedContextData m_context;
+ v8::Persistent<v8::Object> m_qmlglobal;
+};
+
+QT_END_NAMESPACE
+
+#endif // QV8INCLUDE_P_H
+
diff --git a/src/qml/qml/v8/qv8listwrapper.cpp b/src/qml/qml/v8/qv8listwrapper.cpp
new file mode 100644
index 0000000000..d6eab7af34
--- /dev/null
+++ b/src/qml/qml/v8/qv8listwrapper.cpp
@@ -0,0 +1,194 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qv8listwrapper_p.h"
+#include "qv8engine_p.h"
+#include <private/qqmllist_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QV8ListResource : public QV8ObjectResource
+{
+ V8_RESOURCE_TYPE(ListType);
+public:
+ QV8ListResource(QV8Engine *engine) : QV8ObjectResource(engine) {}
+
+ QQmlGuard<QObject> object;
+ QQmlListProperty<QObject> property;
+ int propertyType;
+};
+
+QV8ListWrapper::QV8ListWrapper()
+: m_engine(0)
+{
+}
+
+QV8ListWrapper::~QV8ListWrapper()
+{
+}
+
+void QV8ListWrapper::init(QV8Engine *engine)
+{
+ m_engine = engine;
+ v8::Local<v8::FunctionTemplate> ft = v8::FunctionTemplate::New();
+ ft->InstanceTemplate()->SetFallbackPropertyHandler(Getter, Setter, 0, 0, Enumerator);
+ ft->InstanceTemplate()->SetIndexedPropertyHandler(IndexedGetter);
+ ft->InstanceTemplate()->SetAccessor(v8::String::New("length"), LengthGetter, 0,
+ v8::Handle<v8::Value>(), v8::DEFAULT,
+ v8::PropertyAttribute(v8::ReadOnly | v8::DontDelete | v8::DontEnum));
+ ft->InstanceTemplate()->SetHasExternalResource(true);
+ m_constructor = qPersistentNew<v8::Function>(ft->GetFunction());
+}
+
+void QV8ListWrapper::destroy()
+{
+ qPersistentDispose(m_constructor);
+}
+
+v8::Handle<v8::Value> QV8ListWrapper::newList(QObject *object, int propId, int propType)
+{
+ if (!object || propId == -1)
+ return v8::Null();
+
+ // XXX NewInstance() should be optimized
+ v8::Local<v8::Object> rv = m_constructor->NewInstance();
+ QV8ListResource *r = new QV8ListResource(m_engine);
+ r->object = object;
+ r->propertyType = propType;
+ void *args[] = { &r->property, 0 };
+ QMetaObject::metacall(object, QMetaObject::ReadProperty, propId, args);
+ rv->SetExternalResource(r);
+ return rv;
+}
+
+v8::Handle<v8::Value> QV8ListWrapper::newList(const QQmlListProperty<QObject> &prop, int propType)
+{
+ // XXX NewInstance() should be optimized
+ v8::Local<v8::Object> rv = m_constructor->NewInstance();
+ QV8ListResource *r = new QV8ListResource(m_engine);
+ r->object = prop.object;
+ r->property = prop;
+ r->propertyType = propType;
+ rv->SetExternalResource(r);
+ return rv;
+}
+
+QVariant QV8ListWrapper::toVariant(v8::Handle<v8::Object> obj)
+{
+ QV8ListResource *resource = v8_resource_cast<QV8ListResource>(obj);
+ if (resource) return toVariant(resource);
+ else return QVariant();
+}
+
+QVariant QV8ListWrapper::toVariant(QV8ObjectResource *r)
+{
+ Q_ASSERT(r->resourceType() == QV8ObjectResource::ListType);
+ QV8ListResource *resource = static_cast<QV8ListResource *>(r);
+
+ if (!resource->object)
+ return QVariant();
+
+ return QVariant::fromValue(QQmlListReferencePrivate::init(resource->property, resource->propertyType,
+ m_engine->engine()));
+}
+
+v8::Handle<v8::Value> QV8ListWrapper::Getter(v8::Local<v8::String> property,
+ const v8::AccessorInfo &info)
+{
+ Q_UNUSED(property);
+ Q_UNUSED(info);
+ return v8::Handle<v8::Value>();
+}
+
+v8::Handle<v8::Value> QV8ListWrapper::Setter(v8::Local<v8::String> property,
+ v8::Local<v8::Value> value,
+ const v8::AccessorInfo &info)
+{
+ Q_UNUSED(property);
+ Q_UNUSED(info);
+ return value;
+}
+
+v8::Handle<v8::Value> QV8ListWrapper::IndexedGetter(uint32_t index, const v8::AccessorInfo &info)
+{
+ QV8ListResource *resource = v8_resource_cast<QV8ListResource>(info.This());
+
+ if (!resource || resource->object.isNull()) return v8::Undefined();
+
+ quint32 count = resource->property.count?resource->property.count(&resource->property):0;
+ if (index < count && resource->property.at) {
+ return resource->engine->newQObject(resource->property.at(&resource->property, index));
+ } else {
+ return v8::Undefined();
+ }
+}
+
+v8::Handle<v8::Value> QV8ListWrapper::LengthGetter(v8::Local<v8::String> property,
+ const v8::AccessorInfo &info)
+{
+ Q_UNUSED(property);
+
+ QV8ListResource *resource = v8_resource_cast<QV8ListResource>(info.This());
+
+ if (!resource || resource->object.isNull()) return v8::Undefined();
+
+ quint32 count = resource->property.count?resource->property.count(&resource->property):0;
+
+ return v8::Integer::NewFromUnsigned(count);
+}
+
+v8::Handle<v8::Array> QV8ListWrapper::Enumerator(const v8::AccessorInfo &info)
+{
+ QV8ListResource *resource = v8_resource_cast<QV8ListResource>(info.This());
+
+ if (!resource || resource->object.isNull()) return v8::Array::New();
+
+ quint32 count = resource->property.count?resource->property.count(&resource->property):0;
+
+ v8::Local<v8::Array> rv = v8::Array::New(count);
+
+ for (uint ii = 0; ii < count; ++ii)
+ rv->Set(ii, v8::Number::New(ii));
+
+ return rv;
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/v8/qv8listwrapper_p.h b/src/qml/qml/v8/qv8listwrapper_p.h
new file mode 100644
index 0000000000..1e4bab06d5
--- /dev/null
+++ b/src/qml/qml/v8/qv8listwrapper_p.h
@@ -0,0 +1,97 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QV8LISTWRAPPER_P_H
+#define QV8LISTWRAPPER_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qglobal.h>
+#include <QtQml/qqmllist.h>
+#include <private/qv8_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QV8Engine;
+class QV8ObjectResource;
+class QV8ListWrapper
+{
+public:
+ QV8ListWrapper();
+ ~QV8ListWrapper();
+
+ void init(QV8Engine *);
+ void destroy();
+
+ v8::Handle<v8::Value> newList(QObject *, int, int);
+ v8::Handle<v8::Value> newList(const QQmlListProperty<QObject> &, int);
+ QVariant toVariant(v8::Handle<v8::Object>);
+ QVariant toVariant(QV8ObjectResource *);
+
+private:
+ static v8::Handle<v8::Value> Getter(v8::Local<v8::String> property,
+ const v8::AccessorInfo &info);
+ static v8::Handle<v8::Value> Setter(v8::Local<v8::String> property,
+ v8::Local<v8::Value> value,
+ const v8::AccessorInfo &info);
+ static v8::Handle<v8::Value> IndexedGetter(uint32_t index,
+ const v8::AccessorInfo &info);
+ static v8::Handle<v8::Value> LengthGetter(v8::Local<v8::String> property,
+ const v8::AccessorInfo &info);
+ static v8::Handle<v8::Array> Enumerator(const v8::AccessorInfo &info);
+
+ QV8Engine *m_engine;
+ v8::Persistent<v8::Function> m_constructor;
+};
+
+QT_END_NAMESPACE
+
+#endif // QV8LISTWRAPPER_P_H
+
diff --git a/src/qml/qml/v8/qv8profiler_p.h b/src/qml/qml/v8/qv8profiler_p.h
new file mode 100644
index 0000000000..45df5a17c4
--- /dev/null
+++ b/src/qml/qml/v8/qv8profiler_p.h
@@ -0,0 +1,42 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <private/v8-profiler.h>
diff --git a/src/qml/qml/v8/qv8qobjectwrapper.cpp b/src/qml/qml/v8/qv8qobjectwrapper.cpp
new file mode 100644
index 0000000000..b84ae339be
--- /dev/null
+++ b/src/qml/qml/v8/qv8qobjectwrapper.cpp
@@ -0,0 +1,2113 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qv8qobjectwrapper_p.h"
+#include "qv8contextwrapper_p.h"
+#include "qv8engine_p.h"
+
+#include <private/qqmlguard_p.h>
+#include <private/qqmlpropertycache_p.h>
+#include <private/qqmlengine_p.h>
+#include <private/qqmlvmemetaobject_p.h>
+#include <private/qqmlbinding_p.h>
+#include <private/qjsvalue_p.h>
+#include <private/qscript_impl_p.h>
+#include <private/qqmlaccessors_p.h>
+#include <private/qqmlexpression_p.h>
+
+#include <QtQml/qjsvalue.h>
+#include <QtCore/qvarlengtharray.h>
+#include <QtCore/qtimer.h>
+#include <QtCore/qatomic.h>
+
+Q_DECLARE_METATYPE(QJSValue);
+Q_DECLARE_METATYPE(QQmlV8Handle);
+
+QT_BEGIN_NAMESPACE
+
+#if defined(__GNUC__)
+# if (__GNUC__ * 100 + __GNUC_MINOR__) >= 405
+// The code in this file does not violate strict aliasing, but GCC thinks it does
+// so turn off the warnings for us to have a clean build
+# pragma GCC diagnostic ignored "-Wstrict-aliasing"
+# endif
+#endif
+
+#define QOBJECT_TOSTRING_INDEX -2
+#define QOBJECT_DESTROY_INDEX -3
+
+// XXX TODO: Need to review all calls to QQmlEngine *engine() to confirm QObjects work
+// correctly in a worker thread
+
+class QV8QObjectResource : public QV8ObjectResource
+{
+ V8_RESOURCE_TYPE(QObjectType);
+
+public:
+ QV8QObjectResource(QV8Engine *engine, QObject *object);
+
+ QQmlGuard<QObject> object;
+};
+
+class QV8QObjectInstance : public QQmlGuard<QObject>
+{
+public:
+ QV8QObjectInstance(QObject *o, QV8QObjectWrapper *w)
+ : QQmlGuard<QObject>(o), wrapper(w)
+ {
+ }
+
+ ~QV8QObjectInstance()
+ {
+ qPersistentDispose(v8object);
+ }
+
+ virtual void objectDestroyed(QObject *o)
+ {
+ if (wrapper)
+ wrapper->m_taintedObjects.remove(o);
+ delete this;
+ }
+
+ v8::Persistent<v8::Object> v8object;
+ QV8QObjectWrapper *wrapper;
+};
+
+class QV8SignalHandlerResource : public QV8ObjectResource
+{
+ V8_RESOURCE_TYPE(SignalHandlerType)
+public:
+ QV8SignalHandlerResource(QV8Engine *engine, QObject *object, int index);
+
+ QQmlGuard<QObject> object;
+ int index;
+};
+
+namespace {
+
+template<typename A, typename B, typename C, typename D, typename E>
+class MaxSizeOf5 {
+ template<typename Z, typename X>
+ struct SMax {
+ static const size_t Size = sizeof(Z) > sizeof(X) ? sizeof(Z) : sizeof(X);
+ };
+public:
+ static const size_t Size = SMax<A, SMax<B, SMax<C, SMax<D, E> > > >::Size;
+};
+
+struct CallArgument {
+ inline CallArgument();
+ inline ~CallArgument();
+ inline void *dataPtr();
+
+ inline void initAsType(int type);
+ inline void fromValue(int type, QV8Engine *, v8::Handle<v8::Value>);
+ inline v8::Handle<v8::Value> toValue(QV8Engine *);
+
+private:
+ CallArgument(const CallArgument &);
+
+ inline void cleanup();
+
+ union {
+ float floatValue;
+ double doubleValue;
+ quint32 intValue;
+ bool boolValue;
+ QObject *qobjectPtr;
+
+ char allocData[MaxSizeOf5<QVariant,
+ QString,
+ QList<QObject *>,
+ QJSValue,
+ QQmlV8Handle>::Size];
+ qint64 q_for_alignment;
+ };
+
+ // Pointers to allocData
+ union {
+ QString *qstringPtr;
+ QVariant *qvariantPtr;
+ QList<QObject *> *qlistPtr;
+ QJSValue *qjsValuePtr;
+ QQmlV8Handle *handlePtr;
+ };
+
+ int type;
+};
+}
+
+QV8QObjectResource::QV8QObjectResource(QV8Engine *engine, QObject *object)
+: QV8ObjectResource(engine), object(object)
+{
+}
+
+QV8SignalHandlerResource::QV8SignalHandlerResource(QV8Engine *engine, QObject *object, int index)
+: QV8ObjectResource(engine), object(object), index(index)
+{
+}
+
+static QAtomicInt objectIdCounter(1);
+
+QV8QObjectWrapper::QV8QObjectWrapper()
+: m_engine(0), m_id(objectIdCounter.fetchAndAddOrdered(1))
+{
+}
+
+QV8QObjectWrapper::~QV8QObjectWrapper()
+{
+ for (TaintedHash::Iterator iter = m_taintedObjects.begin();
+ iter != m_taintedObjects.end();
+ ++iter) {
+ (*iter)->wrapper = 0;
+ }
+ m_taintedObjects.clear();
+}
+
+void QV8QObjectWrapper::destroy()
+{
+ qDeleteAll(m_connections);
+ m_connections.clear();
+
+ qPersistentDispose(m_hiddenObject);
+ qPersistentDispose(m_destroySymbol);
+ qPersistentDispose(m_toStringSymbol);
+ qPersistentDispose(m_signalHandlerConstructor);
+ qPersistentDispose(m_methodConstructor);
+ qPersistentDispose(m_constructor);
+}
+
+struct ReadAccessor {
+ static inline void Indirect(QObject *object, const QQmlPropertyData &property,
+ void *output, QQmlNotifier **n)
+ {
+ Q_ASSERT(n == 0);
+ Q_UNUSED(n);
+
+ void *args[] = { output, 0 };
+ QMetaObject::metacall(object, QMetaObject::ReadProperty, property.coreIndex, args);
+ }
+
+ static inline void Direct(QObject *object, const QQmlPropertyData &property,
+ void *output, QQmlNotifier **n)
+ {
+ Q_ASSERT(n == 0);
+ Q_UNUSED(n);
+
+ void *args[] = { output, 0 };
+ object->qt_metacall(QMetaObject::ReadProperty, property.coreIndex, args);
+ }
+
+ static inline void Accessor(QObject *object, const QQmlPropertyData &property,
+ void *output, QQmlNotifier **n)
+ {
+ Q_ASSERT(property.accessors);
+
+ property.accessors->read(object, property.accessorData, output);
+ if (n) property.accessors->notifier(object, property.accessorData, n);
+ }
+};
+
+static inline v8::Handle<v8::Value> valueToHandle(QV8Engine *, int v)
+{ return v8::Integer::New(v); }
+static inline v8::Handle<v8::Value> valueToHandle(QV8Engine *, uint v)
+{ return v8::Integer::NewFromUnsigned(v); }
+static inline v8::Handle<v8::Value> valueToHandle(QV8Engine *, bool v)
+{ return v8::Boolean::New(v); }
+static inline v8::Handle<v8::Value> valueToHandle(QV8Engine *e, const QString &v)
+{ return e->toString(v); }
+static inline v8::Handle<v8::Value> valueToHandle(QV8Engine *, float v)
+{ return v8::Number::New(v); }
+static inline v8::Handle<v8::Value> valueToHandle(QV8Engine *, double v)
+{ return v8::Number::New(v); }
+static inline v8::Handle<v8::Value> valueToHandle(QV8Engine *e, QObject *v)
+{ return e->newQObject(v); }
+
+template<typename T, void (*ReadFunction)(QObject *, const QQmlPropertyData &,
+ void *, QQmlNotifier **)>
+static v8::Handle<v8::Value> GenericValueGetter(v8::Local<v8::String>, const v8::AccessorInfo &info)
+{
+ v8::Handle<v8::Object> This = info.This();
+ QV8QObjectResource *resource = v8_resource_check<QV8QObjectResource>(This);
+
+ QObject *object = resource->object;
+ if (!object) return v8::Undefined();
+
+ QQmlPropertyData *property =
+ (QQmlPropertyData *)v8::External::Unwrap(info.Data());
+
+ QQmlEngine *engine = resource->engine->engine();
+ QQmlEnginePrivate *ep = engine?QQmlEnginePrivate::get(engine):0;
+
+ T value = T();
+
+ if (ep && ep->propertyCapture) {
+ if (ReadFunction == ReadAccessor::Accessor && property->accessors->notifier) {
+ QQmlNotifier *notifier = 0;
+ ReadFunction(object, *property, &value, &notifier);
+ if (notifier) ep->captureProperty(notifier);
+ } else if (!property->isConstant()) {
+ ep->captureProperty(object, property->coreIndex, property->notifyIndex);
+ ReadFunction(object, *property, &value, 0);
+ } else {
+ ReadFunction(object, *property, &value, 0);
+ }
+ } else {
+ ReadFunction(object, *property, &value, 0);
+ }
+
+ return valueToHandle(resource->engine, value);
+}
+
+#define FAST_GETTER_FUNCTION(property, cpptype) \
+ (property->hasAccessors()?((v8::AccessorGetter)GenericValueGetter<cpptype, &ReadAccessor::Accessor>):(property->isDirect()?((v8::AccessorGetter)GenericValueGetter<cpptype, &ReadAccessor::Direct>):((v8::AccessorGetter)GenericValueGetter<cpptype, &ReadAccessor::Indirect>)))
+
+static quint32 toStringHash = -1;
+static quint32 destroyHash = -1;
+
+void QV8QObjectWrapper::init(QV8Engine *engine)
+{
+ m_engine = engine;
+
+ m_toStringSymbol = qPersistentNew<v8::String>(v8::String::NewSymbol("toString"));
+ m_destroySymbol = qPersistentNew<v8::String>(v8::String::NewSymbol("destroy"));
+ m_hiddenObject = qPersistentNew<v8::Object>(v8::Object::New());
+
+ m_toStringString = QHashedV8String(m_toStringSymbol);
+ m_destroyString = QHashedV8String(m_destroySymbol);
+
+ toStringHash = m_toStringString.hash();
+ destroyHash = m_destroyString.hash();
+
+ {
+ v8::Local<v8::FunctionTemplate> ft = v8::FunctionTemplate::New();
+ ft->InstanceTemplate()->SetFallbackPropertyHandler(Getter, Setter, Query, 0, Enumerator);
+ ft->InstanceTemplate()->SetHasExternalResource(true);
+ m_constructor = qPersistentNew<v8::Function>(ft->GetFunction());
+ }
+ {
+ v8::ScriptOrigin origin(m_hiddenObject); // Hack to allow us to identify these functions
+#define CREATE_FUNCTION_SOURCE \
+ "(function(method) { "\
+ "return (function(object, data, qmlglobal) { "\
+ "return (function() { "\
+ "return method(object, data, qmlglobal, arguments.length, arguments); "\
+ "});"\
+ "});"\
+ "})"
+ v8::Local<v8::Script> script = v8::Script::New(v8::String::New(CREATE_FUNCTION_SOURCE), &origin, 0,
+ v8::Handle<v8::String>(), v8::Script::NativeMode);
+#undef CREATE_FUNCTION_SOURCE
+ v8::Local<v8::Function> fn = v8::Local<v8::Function>::Cast(script->Run());
+ v8::Handle<v8::Value> invokeFn = v8::FunctionTemplate::New(Invoke)->GetFunction();
+ v8::Handle<v8::Value> args[] = { invokeFn };
+ v8::Local<v8::Function> createFn = v8::Local<v8::Function>::Cast(fn->Call(engine->global(), 1, args));
+ m_methodConstructor = qPersistentNew<v8::Function>(createFn);
+ }
+
+ v8::Local<v8::Function> connect = V8FUNCTION(Connect, engine);
+ v8::Local<v8::Function> disconnect = V8FUNCTION(Disconnect, engine);
+
+ {
+ v8::Local<v8::FunctionTemplate> ft = v8::FunctionTemplate::New();
+ ft->InstanceTemplate()->SetHasExternalResource(true);
+ ft->PrototypeTemplate()->Set(v8::String::New("connect"), connect, v8::DontEnum);
+ ft->PrototypeTemplate()->Set(v8::String::New("disconnect"), disconnect, v8::DontEnum);
+ m_signalHandlerConstructor = qPersistentNew<v8::Function>(ft->GetFunction());
+ }
+
+ {
+ v8::Local<v8::Object> prototype = engine->global()->Get(v8::String::New("Function"))->ToObject()->Get(v8::String::New("prototype"))->ToObject();
+ prototype->Set(v8::String::New("connect"), connect, v8::DontEnum);
+ prototype->Set(v8::String::New("disconnect"), disconnect, v8::DontEnum);
+ }
+}
+
+bool QV8QObjectWrapper::isQObject(v8::Handle<v8::Object> obj)
+{
+ return v8_resource_cast<QV8QObjectResource>(obj) != 0;
+}
+
+QObject *QV8QObjectWrapper::toQObject(v8::Handle<v8::Object> obj)
+{
+ QV8QObjectResource *r = v8_resource_cast<QV8QObjectResource>(obj);
+ return r?r->object:0;
+}
+
+// r *MUST* be a QV8ObjectResource (r->type() == QV8ObjectResource::QObjectType)
+QObject *QV8QObjectWrapper::toQObject(QV8ObjectResource *r)
+{
+ Q_ASSERT(r->resourceType() == QV8ObjectResource::QObjectType);
+ return static_cast<QV8QObjectResource *>(r)->object;
+}
+
+// Load value properties
+template<void (*ReadFunction)(QObject *, const QQmlPropertyData &,
+ void *, QQmlNotifier **)>
+static v8::Handle<v8::Value> LoadProperty(QV8Engine *engine, QObject *object,
+ const QQmlPropertyData &property,
+ QQmlNotifier **notifier)
+{
+ Q_ASSERT(!property.isFunction());
+
+ if (property.isQObject()) {
+ QObject *rv = 0;
+ ReadFunction(object, property, &rv, notifier);
+ return engine->newQObject(rv);
+ } else if (property.isQList()) {
+ return engine->listWrapper()->newList(object, property.coreIndex, property.propType);
+ } else if (property.propType == QMetaType::QReal) {
+ qreal v = 0;
+ ReadFunction(object, property, &v, notifier);
+ return valueToHandle(engine, v);
+ } else if (property.propType == QMetaType::Int || property.isEnum()) {
+ int v = 0;
+ ReadFunction(object, property, &v, notifier);
+ return valueToHandle(engine, v);
+ } else if (property.propType == QMetaType::Bool) {
+ bool v = false;
+ ReadFunction(object, property, &v, notifier);
+ return valueToHandle(engine, v);
+ } else if (property.propType == QMetaType::QString) {
+ QString v;
+ ReadFunction(object, property, &v, notifier);
+ return valueToHandle(engine, v);
+ } else if (property.propType == QMetaType::UInt) {
+ uint v = 0;
+ ReadFunction(object, property, &v, notifier);
+ return valueToHandle(engine, v);
+ } else if (property.propType == QMetaType::Float) {
+ float v = 0;
+ ReadFunction(object, property, &v, notifier);
+ return valueToHandle(engine, v);
+ } else if (property.propType == QMetaType::Double) {
+ double v = 0;
+ ReadFunction(object, property, &v, notifier);
+ return valueToHandle(engine, v);
+ } else if (property.isV8Handle()) {
+ QQmlV8Handle handle;
+ ReadFunction(object, property, &handle, notifier);
+ return handle.toHandle();
+ } else if (property.isQVariant()) {
+ QVariant v;
+ ReadFunction(object, property, &v, notifier);
+ return engine->fromVariant(v);
+ } else if (QQmlValueTypeFactory::isValueType((uint)property.propType)
+ && engine->engine()) {
+ Q_ASSERT(notifier == 0);
+
+ QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine->engine());
+ QQmlValueType *valueType = ep->valueTypes[property.propType];
+ if (valueType)
+ return engine->newValueType(object, property.coreIndex, valueType);
+ } else {
+ Q_ASSERT(notifier == 0);
+
+ // see if it's a sequence type
+ bool succeeded = false;
+ v8::Handle<v8::Value> retn = engine->newSequence(property.propType, object, property.coreIndex,
+ &succeeded);
+ if (succeeded)
+ return retn;
+ }
+
+ if (property.propType == QVariant::Invalid) {
+ QMetaProperty p = object->metaObject()->property(property.coreIndex);
+ qWarning("QMetaProperty::read: Unable to handle unregistered datatype '%s' for property "
+ "'%s::%s'", p.typeName(), object->metaObject()->className(), p.name());
+ return v8::Undefined();
+ } else {
+ QVariant v(property.propType, (void *)0);
+ ReadFunction(object, property, v.data(), notifier);
+ return engine->fromVariant(v);
+ }
+}
+
+v8::Handle<v8::Value> QV8QObjectWrapper::GetProperty(QV8Engine *engine, QObject *object,
+ v8::Handle<v8::Value> *objectHandle,
+ const QHashedV8String &property,
+ QV8QObjectWrapper::RevisionMode revisionMode)
+{
+ // XXX More recent versions of V8 introduced "Callable" objects. It is possible that these
+ // will be a faster way of creating QObject method objects.
+ struct MethodClosure {
+ static v8::Handle<v8::Value> create(QV8Engine *engine, QObject *object,
+ v8::Handle<v8::Value> *objectHandle,
+ int index) {
+ v8::Handle<v8::Value> argv[] = {
+ objectHandle?*objectHandle:engine->newQObject(object),
+ v8::Integer::New(index)
+ };
+ return engine->qobjectWrapper()->m_methodConstructor->Call(engine->global(), 2, argv);
+ }
+ static v8::Handle<v8::Value> createWithGlobal(QV8Engine *engine, QObject *object,
+ v8::Handle<v8::Value> *objectHandle,
+ int index) {
+ v8::Handle<v8::Value> argv[] = {
+ objectHandle?*objectHandle:engine->newQObject(object),
+ v8::Integer::New(index),
+ v8::Context::GetCallingQmlGlobal()
+ };
+ return engine->qobjectWrapper()->m_methodConstructor->Call(engine->global(), 3, argv);
+ }
+ };
+
+ {
+ // Comparing the hash first actually makes a measurable difference here, at least on x86
+ quint32 hash = property.hash();
+ if (hash == toStringHash && engine->qobjectWrapper()->m_toStringString == property) {
+ return MethodClosure::create(engine, object, objectHandle, QOBJECT_TOSTRING_INDEX);
+ } else if (hash == destroyHash && engine->qobjectWrapper()->m_destroyString == property) {
+ return MethodClosure::create(engine, object, objectHandle, QOBJECT_DESTROY_INDEX);
+ }
+ }
+
+ QQmlPropertyData local;
+ QQmlPropertyData *result = 0;
+ {
+ QQmlData *ddata = QQmlData::get(object, false);
+ if (ddata && ddata->propertyCache)
+ result = ddata->propertyCache->property(property);
+ else
+ result = QQmlPropertyCache::property(engine->engine(), object, property, local);
+ }
+
+ if (!result)
+ return v8::Handle<v8::Value>();
+
+ if (revisionMode == QV8QObjectWrapper::CheckRevision && result->revision != 0) {
+ QQmlData *ddata = QQmlData::get(object);
+ if (ddata && ddata->propertyCache && !ddata->propertyCache->isAllowedInRevision(result))
+ return v8::Handle<v8::Value>();
+ }
+
+ if (result->isFunction()) {
+ if (result->isVMEFunction()) {
+ return ((QQmlVMEMetaObject *)(object->metaObject()))->vmeMethod(result->coreIndex);
+ } else if (result->isV8Function()) {
+ return MethodClosure::createWithGlobal(engine, object, objectHandle, result->coreIndex);
+ } else if (result->isSignalHandler()) {
+ v8::Local<v8::Object> handler = engine->qobjectWrapper()->m_signalHandlerConstructor->NewInstance();
+ QV8SignalHandlerResource *r = new QV8SignalHandlerResource(engine, object, result->coreIndex);
+ handler->SetExternalResource(r);
+ return handler;
+ } else {
+ return MethodClosure::create(engine, object, objectHandle, result->coreIndex);
+ }
+ }
+
+ QQmlEnginePrivate *ep =
+ engine->engine()?QQmlEnginePrivate::get(engine->engine()):0;
+
+ if (result->hasAccessors()) {
+ QQmlNotifier *n = 0;
+ QQmlNotifier **nptr = 0;
+
+ if (ep && ep->propertyCapture && result->accessors->notifier)
+ nptr = &n;
+
+ v8::Handle<v8::Value> rv = LoadProperty<ReadAccessor::Accessor>(engine, object, *result, nptr);
+
+ if (result->accessors->notifier) {
+ if (n) ep->captureProperty(n);
+ } else {
+ ep->captureProperty(object, result->coreIndex, result->notifyIndex);
+ }
+
+ return rv;
+ }
+
+ if (ep && !result->isConstant()) {
+
+ if (result->coreIndex == 0)
+ ep->captureProperty(QQmlData::get(object, true)->objectNameNotifier());
+ else
+ ep->captureProperty(object, result->coreIndex, result->notifyIndex);
+ }
+
+ if (result->isVMEProperty()) {
+ typedef QQmlVMEMetaObject VMEMO;
+ VMEMO *vmemo = const_cast<VMEMO *>(static_cast<const VMEMO *>(object->metaObject()));
+ return vmemo->vmeProperty(result->coreIndex);
+ } else if (result->isDirect()) {
+ return LoadProperty<ReadAccessor::Direct>(engine, object, *result, 0);
+ } else {
+ return LoadProperty<ReadAccessor::Indirect>(engine, object, *result, 0);
+ }
+}
+
+// Setter for writable properties. Shared between the interceptor and fast property accessor
+static inline void StoreProperty(QV8Engine *engine, QObject *object, QQmlPropertyData *property,
+ v8::Handle<v8::Value> value)
+{
+ QQmlBinding *newBinding = 0;
+
+ if (value->IsFunction()) {
+ QQmlContextData *context = engine->callingContext();
+ v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(value);
+
+ v8::Local<v8::StackTrace> trace =
+ v8::StackTrace::CurrentStackTrace(1, (v8::StackTrace::StackTraceOptions)(v8::StackTrace::kLineNumber |
+ v8::StackTrace::kScriptName));
+ v8::Local<v8::StackFrame> frame = trace->GetFrame(0);
+ int lineNumber = frame->GetLineNumber();
+ int columNumber = frame->GetColumn();
+ QString url = engine->toString(frame->GetScriptName());
+
+ newBinding = new QQmlBinding(&function, object, context);
+ newBinding->setSourceLocation(url, lineNumber, columNumber);
+ newBinding->setTarget(object, *property, context);
+ newBinding->setEvaluateFlags(newBinding->evaluateFlags() |
+ QQmlBinding::RequiresThisObject);
+ }
+
+ QQmlAbstractBinding *oldBinding =
+ QQmlPropertyPrivate::setBinding(object, property->coreIndex, -1, newBinding);
+ if (oldBinding)
+ oldBinding->destroy();
+
+#define PROPERTY_STORE(cpptype, value) \
+ cpptype o = value; \
+ int status = -1; \
+ int flags = 0; \
+ void *argv[] = { &o, 0, &status, &flags }; \
+ QMetaObject::metacall(object, QMetaObject::WriteProperty, property->coreIndex, argv);
+
+
+ if (value->IsNull() && property->isQObject()) {
+ PROPERTY_STORE(QObject*, 0);
+ } else if (value->IsUndefined() && property->isResettable()) {
+ void *a[] = { 0 };
+ QMetaObject::metacall(object, QMetaObject::ResetProperty, property->coreIndex, a);
+ } else if (value->IsUndefined() && property->propType == qMetaTypeId<QVariant>()) {
+ PROPERTY_STORE(QVariant, QVariant());
+ } else if (value->IsUndefined()) {
+ QString error = QLatin1String("Cannot assign [undefined] to ") +
+ QLatin1String(QMetaType::typeName(property->propType));
+ v8::ThrowException(v8::Exception::Error(engine->toString(error)));
+ } else if (value->IsFunction()) {
+ // this is handled by the binding creation above
+ } else if (property->propType == QMetaType::Int && value->IsNumber()) {
+ PROPERTY_STORE(int, qRound(value->ToNumber()->Value()));
+ } else if (property->propType == QMetaType::QReal && value->IsNumber()) {
+ PROPERTY_STORE(qreal, qreal(value->ToNumber()->Value()));
+ } else if (property->propType == QMetaType::Float && value->IsNumber()) {
+ PROPERTY_STORE(float, float(value->ToNumber()->Value()));
+ } else if (property->propType == QMetaType::Double && value->IsNumber()) {
+ PROPERTY_STORE(double, double(value->ToNumber()->Value()));
+ } else if (property->propType == QMetaType::QString && value->IsString()) {
+ PROPERTY_STORE(QString, engine->toString(value->ToString()));
+ } else if (property->isVMEProperty()) {
+ static_cast<QQmlVMEMetaObject *>(const_cast<QMetaObject *>(object->metaObject()))->setVMEProperty(property->coreIndex, value);
+ } else {
+ QVariant v;
+ if (property->isQList())
+ v = engine->toVariant(value, qMetaTypeId<QList<QObject *> >());
+ else
+ v = engine->toVariant(value, property->propType);
+
+ QQmlContextData *context = engine->callingContext();
+ if (!QQmlPropertyPrivate::write(object, *property, v, context)) {
+ const char *valueType = 0;
+ if (v.userType() == QVariant::Invalid) valueType = "null";
+ else valueType = QMetaType::typeName(v.userType());
+
+ QString error = QLatin1String("Cannot assign ") +
+ QLatin1String(valueType) +
+ QLatin1String(" to ") +
+ QLatin1String(QMetaType::typeName(property->propType));
+ v8::ThrowException(v8::Exception::Error(engine->toString(error)));
+ }
+ }
+}
+
+bool QV8QObjectWrapper::SetProperty(QV8Engine *engine, QObject *object, const QHashedV8String &property,
+ v8::Handle<v8::Value> value, QV8QObjectWrapper::RevisionMode revisionMode)
+{
+ if (engine->qobjectWrapper()->m_toStringString == property ||
+ engine->qobjectWrapper()->m_destroyString == property)
+ return true;
+
+ QQmlPropertyData local;
+ QQmlPropertyData *result = 0;
+ result = QQmlPropertyCache::property(engine->engine(), object, property, local);
+
+ if (!result)
+ return false;
+
+ if (revisionMode == QV8QObjectWrapper::CheckRevision && result->revision != 0) {
+ QQmlData *ddata = QQmlData::get(object);
+ if (ddata && ddata->propertyCache && !ddata->propertyCache->isAllowedInRevision(result))
+ return false;
+ }
+
+ if (!result->isWritable() && !result->isQList()) {
+ QString error = QLatin1String("Cannot assign to read-only property \"") +
+ engine->toString(property.string()) + QLatin1Char('\"');
+ v8::ThrowException(v8::Exception::Error(engine->toString(error)));
+ return true;
+ }
+
+ StoreProperty(engine, object, result, value);
+
+ return true;
+}
+
+v8::Handle<v8::Value> QV8QObjectWrapper::Getter(v8::Local<v8::String> property,
+ const v8::AccessorInfo &info)
+{
+ QV8QObjectResource *resource = v8_resource_check<QV8QObjectResource>(info.This());
+
+ if (resource->object.isNull())
+ return v8::Handle<v8::Value>();
+
+ QObject *object = resource->object;
+
+ QHashedV8String propertystring(property);
+
+ QV8Engine *v8engine = resource->engine;
+ v8::Handle<v8::Value> This = info.This();
+ v8::Handle<v8::Value> result = GetProperty(v8engine, object, &This, propertystring,
+ QV8QObjectWrapper::IgnoreRevision);
+ if (!result.IsEmpty())
+ return result;
+
+ if (QV8Engine::startsWithUpper(property)) {
+ // Check for attached properties
+ QQmlContextData *context = v8engine->callingContext();
+
+ if (context && context->imports) {
+ QQmlTypeNameCache::Result r = context->imports->query(propertystring);
+
+ if (r.isValid()) {
+ if (r.scriptIndex != -1) {
+ return v8::Undefined();
+ } else if (r.type) {
+ return v8engine->typeWrapper()->newObject(object, r.type, QV8TypeWrapper::ExcludeEnums);
+ } else if (r.importNamespace) {
+ return v8engine->typeWrapper()->newObject(object, context->imports, r.importNamespace,
+ QV8TypeWrapper::ExcludeEnums);
+ }
+ Q_ASSERT(!"Unreachable");
+ }
+ }
+ }
+
+ return v8::Handle<v8::Value>();
+}
+
+v8::Handle<v8::Value> QV8QObjectWrapper::Setter(v8::Local<v8::String> property,
+ v8::Local<v8::Value> value,
+ const v8::AccessorInfo &info)
+{
+ QV8QObjectResource *resource = v8_resource_check<QV8QObjectResource>(info.This());
+
+ if (resource->object.isNull())
+ return value;
+
+ QObject *object = resource->object;
+
+ QHashedV8String propertystring(property);
+
+ QV8Engine *v8engine = resource->engine;
+ bool result = SetProperty(v8engine, object, propertystring, value, QV8QObjectWrapper::IgnoreRevision);
+
+ if (!result) {
+ QString error = QLatin1String("Cannot assign to non-existent property \"") +
+ v8engine->toString(property) + QLatin1Char('\"');
+ v8::ThrowException(v8::Exception::Error(v8engine->toString(error)));
+ return value;
+ }
+
+ return value;
+}
+
+v8::Handle<v8::Integer> QV8QObjectWrapper::Query(v8::Local<v8::String> property,
+ const v8::AccessorInfo &info)
+{
+ QV8QObjectResource *resource = v8_resource_check<QV8QObjectResource>(info.This());
+
+ if (resource->object.isNull())
+ return v8::Handle<v8::Integer>();
+
+ QV8Engine *engine = resource->engine;
+ QObject *object = resource->object;
+
+ QHashedV8String propertystring(property);
+
+ QQmlPropertyData local;
+ QQmlPropertyData *result = 0;
+ result = QQmlPropertyCache::property(engine->engine(), object, propertystring, local);
+
+ if (!result)
+ return v8::Handle<v8::Integer>();
+ else if (!result->isWritable() && !result->isQList())
+ return v8::Integer::New(v8::ReadOnly | v8::DontDelete);
+ else
+ return v8::Integer::New(v8::DontDelete);
+}
+
+v8::Handle<v8::Array> QV8QObjectWrapper::Enumerator(const v8::AccessorInfo &info)
+{
+ QV8QObjectResource *resource = v8_resource_check<QV8QObjectResource>(info.This());
+
+ if (resource->object.isNull())
+ return v8::Array::New();
+
+ QObject *object = resource->object;
+
+ QStringList result;
+
+ QQmlEnginePrivate *ep = resource->engine->engine()
+ ? QQmlEnginePrivate::get(resource->engine->engine())
+ : 0;
+
+ QQmlPropertyCache *cache = 0;
+ QQmlData *ddata = QQmlData::get(object);
+ if (ddata)
+ cache = ddata->propertyCache;
+
+ if (!cache) {
+ cache = ep ? ep->cache(object) : 0;
+ if (cache) {
+ if (ddata) { cache->addref(); ddata->propertyCache = cache; }
+ } else {
+ // Not cachable - fall back to QMetaObject (eg. dynamic meta object)
+ const QMetaObject *mo = object->metaObject();
+ int pc = mo->propertyCount();
+ int po = mo->propertyOffset();
+ for (int i=po; i<pc; ++i)
+ result << QString::fromUtf8(mo->property(i).name());
+ }
+ } else {
+ result = cache->propertyNames();
+ }
+
+ v8::Local<v8::Array> rv = v8::Array::New(result.count());
+
+ for (int ii = 0; ii < result.count(); ++ii)
+ rv->Set(ii, resource->engine->toString(result.at(ii)));
+
+ return rv;
+}
+
+static void FastValueSetter(v8::Local<v8::String>, v8::Local<v8::Value> value,
+ const v8::AccessorInfo& info)
+{
+ QV8QObjectResource *resource = v8_resource_check<QV8QObjectResource>(info.This());
+
+ if (resource->object.isNull())
+ return;
+
+ QObject *object = resource->object;
+
+ QQmlPropertyData *property =
+ (QQmlPropertyData *)v8::External::Unwrap(info.Data());
+
+ int index = property->coreIndex;
+
+ QQmlData *ddata = QQmlData::get(object, false);
+ Q_ASSERT(ddata);
+ Q_ASSERT(ddata->propertyCache);
+
+ QQmlPropertyData *pdata = ddata->propertyCache->property(index);
+ Q_ASSERT(pdata);
+
+ Q_ASSERT(pdata->isWritable() || pdata->isQList());
+
+ StoreProperty(resource->engine, object, pdata, value);
+}
+
+static void FastValueSetterReadOnly(v8::Local<v8::String> property, v8::Local<v8::Value>,
+ const v8::AccessorInfo& info)
+{
+ QV8QObjectResource *resource = v8_resource_check<QV8QObjectResource>(info.This());
+
+ if (resource->object.isNull())
+ return;
+
+ QV8Engine *v8engine = resource->engine;
+
+ QString error = QLatin1String("Cannot assign to read-only property \"") +
+ v8engine->toString(property) + QLatin1Char('\"');
+ v8::ThrowException(v8::Exception::Error(v8engine->toString(error)));
+}
+
+static void WeakQObjectReferenceCallback(v8::Persistent<v8::Value> handle, void *)
+{
+ Q_ASSERT(handle->IsObject());
+
+ QV8QObjectResource *resource = v8_resource_check<QV8QObjectResource>(handle->ToObject());
+
+ Q_ASSERT(resource);
+
+ QObject *object = resource->object;
+ if (object) {
+ QQmlData *ddata = QQmlData::get(object, false);
+ if (ddata) {
+ ddata->v8object.Clear();
+ if (!object->parent() && !ddata->indestructible)
+ object->deleteLater();
+ }
+ }
+
+ qPersistentDispose(handle);
+}
+
+static void WeakQObjectInstanceCallback(v8::Persistent<v8::Value> handle, void *data)
+{
+ QV8QObjectInstance *instance = (QV8QObjectInstance *)data;
+ instance->v8object.Clear();
+ qPersistentDispose(handle);
+}
+
+v8::Local<v8::Object> QQmlPropertyCache::newQObject(QObject *object, QV8Engine *engine)
+{
+ Q_ASSERT(object);
+ Q_ASSERT(this->engine);
+
+ Q_ASSERT(QQmlData::get(object, false));
+ Q_ASSERT(QQmlData::get(object, false)->propertyCache == this);
+
+ // Setup constructor
+ if (constructor.IsEmpty()) {
+ v8::Local<v8::FunctionTemplate> ft;
+
+ QString toString = QLatin1String("toString");
+ QString destroy = QLatin1String("destroy");
+
+ // As we use hash linking, it is possible that iterating over the values can give duplicates.
+ // To combat this, we must unique'ify our properties.
+ StringCache uniqueHash;
+ if (stringCache.isLinked())
+ uniqueHash.reserve(stringCache.count());
+
+ // XXX TODO: Enables fast property accessors. These more than double the property access
+ // performance, but the cost of setting up this structure hasn't been measured so
+ // its not guarenteed that this is a win overall. We need to try and measure the cost.
+ for (StringCache::ConstIterator iter = stringCache.begin(); iter != stringCache.end(); ++iter) {
+ if (stringCache.isLinked()) {
+ if (uniqueHash.contains(iter))
+ continue;
+ uniqueHash.insert(iter);
+ }
+
+ QQmlPropertyData *property = *iter;
+ if (property->notFullyResolved()) resolve(property);
+
+ if (property->isFunction())
+ continue;
+
+ v8::AccessorGetter fastgetter = 0;
+ v8::AccessorSetter fastsetter = FastValueSetter;
+ if (!property->isWritable())
+ fastsetter = FastValueSetterReadOnly;
+
+ if (property->isQObject())
+ fastgetter = FAST_GETTER_FUNCTION(property, QObject*);
+ else if (property->propType == QMetaType::Int || property->isEnum())
+ fastgetter = FAST_GETTER_FUNCTION(property, int);
+ else if (property->propType == QMetaType::Bool)
+ fastgetter = FAST_GETTER_FUNCTION(property, bool);
+ else if (property->propType == QMetaType::QString)
+ fastgetter = FAST_GETTER_FUNCTION(property, QString);
+ else if (property->propType == QMetaType::UInt)
+ fastgetter = FAST_GETTER_FUNCTION(property, uint);
+ else if (property->propType == QMetaType::Float)
+ fastgetter = FAST_GETTER_FUNCTION(property, float);
+ else if (property->propType == QMetaType::Double)
+ fastgetter = FAST_GETTER_FUNCTION(property, double);
+
+ if (fastgetter) {
+ QString name = iter.key();
+ if (name == toString || name == destroy)
+ continue;
+
+ if (ft.IsEmpty()) {
+ ft = v8::FunctionTemplate::New();
+ ft->InstanceTemplate()->SetFallbackPropertyHandler(QV8QObjectWrapper::Getter,
+ QV8QObjectWrapper::Setter,
+ QV8QObjectWrapper::Query,
+ 0,
+ QV8QObjectWrapper::Enumerator);
+ ft->InstanceTemplate()->SetHasExternalResource(true);
+ }
+
+ // We wrap the raw QQmlPropertyData pointer here. This is safe as the
+ // pointer will remain valid at least as long as the lifetime of any QObject's of
+ // this type and the property accessor checks if the object is 0 (deleted) before
+ // dereferencing the pointer.
+ ft->InstanceTemplate()->SetAccessor(engine->toString(name), fastgetter, fastsetter,
+ v8::External::Wrap(property));
+ }
+ }
+
+ if (ft.IsEmpty()) {
+ constructor = qPersistentNew<v8::Function>(engine->qobjectWrapper()->m_constructor);
+ } else {
+ ft->InstanceTemplate()->SetFallbackPropertyHandler(QV8QObjectWrapper::Getter,
+ QV8QObjectWrapper::Setter,
+ QV8QObjectWrapper::Query,
+ 0,
+ QV8QObjectWrapper::Enumerator);
+ ft->InstanceTemplate()->SetHasExternalResource(true);
+ constructor = qPersistentNew<v8::Function>(ft->GetFunction());
+ }
+
+ QQmlCleanup::addToEngine(this->engine);
+ }
+
+ v8::Local<v8::Object> result = constructor->NewInstance();
+ QV8QObjectResource *r = new QV8QObjectResource(engine, object);
+ result->SetExternalResource(r);
+ return result;
+}
+
+v8::Local<v8::Object> QV8QObjectWrapper::newQObject(QObject *object, QQmlData *ddata, QV8Engine *engine)
+{
+ v8::Local<v8::Object> rv;
+
+ if (!ddata->propertyCache && engine->engine()) {
+ ddata->propertyCache = QQmlEnginePrivate::get(engine->engine())->cache(object);
+ if (ddata->propertyCache) ddata->propertyCache->addref();
+ }
+
+ if (ddata->propertyCache && ddata->propertyCache->qmlEngine() == engine->engine()) {
+ rv = ddata->propertyCache->newQObject(object, engine);
+ } else {
+ // XXX NewInstance() should be optimized
+ rv = m_constructor->NewInstance();
+ QV8QObjectResource *r = new QV8QObjectResource(engine, object);
+ rv->SetExternalResource(r);
+ }
+
+ return rv;
+}
+
+/*
+As V8 doesn't support an equality callback, for QObject's we have to return exactly the same
+V8 handle for subsequent calls to newQObject for the same QObject. To do this we have a two
+pronged strategy:
+ 1. If there is no current outstanding V8 handle to the QObject, we create one and store a
+ persistent handle in QQmlData::v8object. We mark the QV8QObjectWrapper that
+ "owns" this handle by setting the QQmlData::v8objectid to the id of this
+ QV8QObjectWrapper.
+ 2. If another QV8QObjectWrapper has create the handle in QQmlData::v8object we create
+ an entry in the m_taintedObject hash where we store the handle and mark the object as
+ "tainted" in the QQmlData::hasTaintedV8Object flag.
+We have to mark the object as tainted to ensure that we search our m_taintedObject hash even
+in the case that the original QV8QObjectWrapper owner of QQmlData::v8object has
+released the handle.
+*/
+v8::Handle<v8::Value> QV8QObjectWrapper::newQObject(QObject *object)
+{
+ if (!object)
+ return v8::Null();
+
+ if (QObjectPrivate::get(object)->wasDeleted)
+ return v8::Undefined();
+
+ QQmlData *ddata = QQmlData::get(object, true);
+
+ if (!ddata)
+ return v8::Undefined();
+
+ if (ddata->v8objectid == m_id && !ddata->v8object.IsEmpty()) {
+ // We own the v8object
+ return v8::Local<v8::Object>::New(ddata->v8object);
+ } else if (ddata->v8object.IsEmpty() &&
+ (ddata->v8objectid == m_id || // We own the QObject
+ ddata->v8objectid == 0 || // No one owns the QObject
+ !ddata->hasTaintedV8Object)) { // Someone else has used the QObject, but it isn't tainted
+
+ v8::Local<v8::Object> rv = newQObject(object, ddata, m_engine);
+ ddata->v8object = qPersistentNew<v8::Object>(rv);
+ ddata->v8object.MakeWeak(0, WeakQObjectReferenceCallback);
+ ddata->v8objectid = m_id;
+ return rv;
+
+ } else {
+ // If this object is tainted, we have to check to see if it is in our
+ // tainted object list
+ TaintedHash::Iterator iter =
+ ddata->hasTaintedV8Object?m_taintedObjects.find(object):m_taintedObjects.end();
+ bool found = iter != m_taintedObjects.end();
+
+ // If our tainted handle doesn't exist or has been collected, and there isn't
+ // a handle in the ddata, we can assume ownership of the ddata->v8object
+ if ((!found || (*iter)->v8object.IsEmpty()) && ddata->v8object.IsEmpty()) {
+ v8::Local<v8::Object> rv = newQObject(object, ddata, m_engine);
+ ddata->v8object = qPersistentNew<v8::Object>(rv);
+ ddata->v8object.MakeWeak(0, WeakQObjectReferenceCallback);
+ ddata->v8objectid = m_id;
+
+ if (found) {
+ delete (*iter);
+ m_taintedObjects.erase(iter);
+ }
+
+ return rv;
+ } else if (!found) {
+ QV8QObjectInstance *instance = new QV8QObjectInstance(object, this);
+ iter = m_taintedObjects.insert(object, instance);
+ ddata->hasTaintedV8Object = true;
+ }
+
+ if ((*iter)->v8object.IsEmpty()) {
+ v8::Local<v8::Object> rv = newQObject(object, ddata, m_engine);
+ (*iter)->v8object = qPersistentNew<v8::Object>(rv);
+ (*iter)->v8object.MakeWeak((*iter), WeakQObjectInstanceCallback);
+ }
+
+ return v8::Local<v8::Object>::New((*iter)->v8object);
+ }
+}
+
+QPair<QObject *, int> QV8QObjectWrapper::ExtractQtSignal(QV8Engine *engine, v8::Handle<v8::Object> object)
+{
+ if (object->IsFunction())
+ return ExtractQtMethod(engine, v8::Handle<v8::Function>::Cast(object));
+
+ if (QV8SignalHandlerResource *resource = v8_resource_cast<QV8SignalHandlerResource>(object))
+ return qMakePair(resource->object.data(), resource->index);
+
+ return qMakePair((QObject *)0, -1);
+}
+
+QPair<QObject *, int> QV8QObjectWrapper::ExtractQtMethod(QV8Engine *engine, v8::Handle<v8::Function> function)
+{
+ v8::ScriptOrigin origin = function->GetScriptOrigin();
+ if (origin.ResourceName()->StrictEquals(engine->qobjectWrapper()->m_hiddenObject)) {
+
+ // This is one of our special QObject method wrappers
+ v8::Handle<v8::Value> args[] = { engine->qobjectWrapper()->m_hiddenObject };
+ v8::Local<v8::Value> data = function->Call(engine->global(), 1, args);
+
+ if (data->IsArray()) {
+ v8::Local<v8::Array> array = v8::Local<v8::Array>::Cast(data);
+ return qMakePair(engine->toQObject(array->Get(0)), array->Get(1)->Int32Value());
+ }
+
+ // In theory this can't fall through, but I suppose V8 might run out of memory or something
+ }
+
+ return qMakePair((QObject *)0, -1);
+}
+
+class QV8QObjectConnectionList : public QObject, public QQmlGuard<QObject>
+{
+public:
+ QV8QObjectConnectionList(QObject *object, QV8Engine *engine);
+ ~QV8QObjectConnectionList();
+
+ struct Connection {
+ Connection()
+ : needsDestroy(false) {}
+ Connection(const Connection &other)
+ : thisObject(other.thisObject), function(other.function), needsDestroy(false) {}
+ Connection &operator=(const Connection &other) {
+ thisObject = other.thisObject;
+ function = other.function;
+ needsDestroy = other.needsDestroy;
+ return *this;
+ }
+
+ v8::Persistent<v8::Object> thisObject;
+ v8::Persistent<v8::Function> function;
+
+ void dispose() {
+ qPersistentDispose(thisObject);
+ qPersistentDispose(function);
+ }
+
+ bool needsDestroy;
+ };
+
+ struct ConnectionList : public QList<Connection> {
+ ConnectionList() : connectionsInUse(0), connectionsNeedClean(false) {}
+ int connectionsInUse;
+ bool connectionsNeedClean;
+ };
+
+ QV8Engine *engine;
+
+ typedef QHash<int, ConnectionList> SlotHash;
+ SlotHash slotHash;
+ bool needsDestroy;
+ int inUse;
+
+ virtual void objectDestroyed(QObject *);
+ virtual int qt_metacall(QMetaObject::Call, int, void **);
+};
+
+QV8QObjectConnectionList::QV8QObjectConnectionList(QObject *object, QV8Engine *engine)
+: QQmlGuard<QObject>(object), engine(engine), needsDestroy(false), inUse(0)
+{
+}
+
+QV8QObjectConnectionList::~QV8QObjectConnectionList()
+{
+ for (SlotHash::Iterator iter = slotHash.begin(); iter != slotHash.end(); ++iter) {
+ QList<Connection> &connections = *iter;
+ for (int ii = 0; ii < connections.count(); ++ii) {
+ qPersistentDispose(connections[ii].thisObject);
+ qPersistentDispose(connections[ii].function);
+ }
+ }
+ slotHash.clear();
+}
+
+void QV8QObjectConnectionList::objectDestroyed(QObject *object)
+{
+ engine->qobjectWrapper()->m_connections.remove(object);
+
+ if (inUse)
+ needsDestroy = true;
+ else
+ delete this;
+}
+
+int QV8QObjectConnectionList::qt_metacall(QMetaObject::Call method, int index, void **metaArgs)
+{
+ if (method == QMetaObject::InvokeMetaMethod) {
+ SlotHash::Iterator iter = slotHash.find(index);
+ if (iter == slotHash.end())
+ return -1;
+ ConnectionList &connectionList = *iter;
+ if (connectionList.isEmpty())
+ return -1;
+
+ inUse++;
+
+ connectionList.connectionsInUse++;
+
+ QList<Connection> connections = connectionList;
+
+ QVarLengthArray<int, 9> dummy;
+ int *argsTypes = QQmlPropertyCache::methodParameterTypes(data(), index, dummy, 0);
+
+ v8::HandleScope handle_scope;
+ v8::Context::Scope scope(engine->context());
+
+ int argCount = argsTypes?argsTypes[0]:0;
+ QVarLengthArray<v8::Handle<v8::Value>, 9> args(argCount);
+
+ for (int ii = 0; ii < argCount; ++ii) {
+ int type = argsTypes[ii + 1];
+ if (type == qMetaTypeId<QVariant>()) {
+ args[ii] = engine->fromVariant(*((QVariant *)metaArgs[ii + 1]));
+ } else {
+ args[ii] = engine->fromVariant(QVariant(type, metaArgs[ii + 1]));
+ }
+ }
+
+ for (int ii = 0; ii < connections.count(); ++ii) {
+ Connection &connection = connections[ii];
+ if (connection.needsDestroy)
+ continue;
+
+ v8::TryCatch try_catch;
+ if (connection.thisObject.IsEmpty()) {
+ connection.function->Call(engine->global(), argCount, args.data());
+ } else {
+ connection.function->Call(connection.thisObject, argCount, args.data());
+ }
+
+ if (try_catch.HasCaught()) {
+ QQmlError error;
+ error.setDescription(QString(QLatin1String("Unknown exception occurred during evaluation of connected function: %1")).arg(engine->toString(connection.function->GetName())));
+ v8::Local<v8::Message> message = try_catch.Message();
+ if (!message.IsEmpty())
+ QQmlExpressionPrivate::exceptionToError(message, error);
+ QQmlEnginePrivate::get(engine->engine())->warning(error);
+ }
+ }
+
+ connectionList.connectionsInUse--;
+ if (connectionList.connectionsInUse == 0 && connectionList.connectionsNeedClean) {
+ for (QList<Connection>::Iterator iter = connectionList.begin();
+ iter != connectionList.end(); ) {
+ if (iter->needsDestroy) {
+ iter->dispose();
+ iter = connectionList.erase(iter);
+ } else {
+ ++iter;
+ }
+ }
+ }
+
+ inUse--;
+ if (inUse == 0 && needsDestroy)
+ delete this;
+ }
+
+ return -1;
+}
+
+v8::Handle<v8::Value> QV8QObjectWrapper::Connect(const v8::Arguments &args)
+{
+ if (args.Length() == 0)
+ V8THROW_ERROR("Function.prototype.connect: no arguments given");
+
+ QV8Engine *engine = V8ENGINE();
+
+ QPair<QObject *, int> signalInfo = ExtractQtSignal(engine, args.This());
+ QObject *signalObject = signalInfo.first;
+ int signalIndex = signalInfo.second;
+
+ if (signalIndex == -1)
+ V8THROW_ERROR("Function.prototype.connect: this object is not a signal");
+
+ if (!signalObject)
+ V8THROW_ERROR("Function.prototype.connect: cannot connect to deleted QObject");
+
+ if (signalIndex < 0 || signalObject->metaObject()->method(signalIndex).methodType() != QMetaMethod::Signal)
+ V8THROW_ERROR("Function.prototype.connect: this object is not a signal");
+
+ v8::Local<v8::Value> functionValue;
+ v8::Local<v8::Value> functionThisValue;
+
+ if (args.Length() == 1) {
+ functionValue = args[0];
+ } else {
+ functionThisValue = args[0];
+ functionValue = args[1];
+ }
+
+ if (!functionValue->IsFunction())
+ V8THROW_ERROR("Function.prototype.connect: target is not a function");
+
+ if (!functionThisValue.IsEmpty() && !functionThisValue->IsObject())
+ V8THROW_ERROR("Function.prototype.connect: target this is not an object");
+
+ QV8QObjectWrapper *qobjectWrapper = engine->qobjectWrapper();
+ QHash<QObject *, QV8QObjectConnectionList *> &connections = qobjectWrapper->m_connections;
+ QHash<QObject *, QV8QObjectConnectionList *>::Iterator iter = connections.find(signalObject);
+ if (iter == connections.end())
+ iter = connections.insert(signalObject, new QV8QObjectConnectionList(signalObject, engine));
+
+ QV8QObjectConnectionList *connectionList = *iter;
+ QV8QObjectConnectionList::SlotHash::Iterator slotIter = connectionList->slotHash.find(signalIndex);
+ if (slotIter == connectionList->slotHash.end()) {
+ slotIter = connectionList->slotHash.insert(signalIndex, QV8QObjectConnectionList::ConnectionList());
+ QMetaObject::connect(signalObject, signalIndex, connectionList, signalIndex);
+ }
+
+ QV8QObjectConnectionList::Connection connection;
+ if (!functionThisValue.IsEmpty())
+ connection.thisObject = qPersistentNew<v8::Object>(functionThisValue->ToObject());
+ connection.function = qPersistentNew<v8::Function>(v8::Handle<v8::Function>::Cast(functionValue));
+
+ slotIter->append(connection);
+
+ return v8::Undefined();
+}
+
+v8::Handle<v8::Value> QV8QObjectWrapper::Disconnect(const v8::Arguments &args)
+{
+ if (args.Length() == 0)
+ V8THROW_ERROR("Function.prototype.disconnect: no arguments given");
+
+ QV8Engine *engine = V8ENGINE();
+
+ QPair<QObject *, int> signalInfo = ExtractQtSignal(engine, args.This());
+ QObject *signalObject = signalInfo.first;
+ int signalIndex = signalInfo.second;
+
+ if (signalIndex == -1)
+ V8THROW_ERROR("Function.prototype.disconnect: this object is not a signal");
+
+ if (!signalObject)
+ V8THROW_ERROR("Function.prototype.disconnect: cannot disconnect from deleted QObject");
+
+ if (signalIndex < 0 || signalObject->metaObject()->method(signalIndex).methodType() != QMetaMethod::Signal)
+ V8THROW_ERROR("Function.prototype.disconnect: this object is not a signal");
+
+ v8::Local<v8::Value> functionValue;
+ v8::Local<v8::Value> functionThisValue;
+
+ if (args.Length() == 1) {
+ functionValue = args[0];
+ } else {
+ functionThisValue = args[0];
+ functionValue = args[1];
+ }
+
+ if (!functionValue->IsFunction())
+ V8THROW_ERROR("Function.prototype.disconnect: target is not a function");
+
+ if (!functionThisValue.IsEmpty() && !functionThisValue->IsObject())
+ V8THROW_ERROR("Function.prototype.disconnect: target this is not an object");
+
+ QV8QObjectWrapper *qobjectWrapper = engine->qobjectWrapper();
+ QHash<QObject *, QV8QObjectConnectionList *> &connectionsList = qobjectWrapper->m_connections;
+ QHash<QObject *, QV8QObjectConnectionList *>::Iterator iter = connectionsList.find(signalObject);
+ if (iter == connectionsList.end())
+ return v8::Undefined(); // Nothing to disconnect from
+
+ QV8QObjectConnectionList *connectionList = *iter;
+ QV8QObjectConnectionList::SlotHash::Iterator slotIter = connectionList->slotHash.find(signalIndex);
+ if (slotIter == connectionList->slotHash.end())
+ return v8::Undefined(); // Nothing to disconnect from
+
+ QV8QObjectConnectionList::ConnectionList &connections = *slotIter;
+
+ v8::Local<v8::Function> function = v8::Local<v8::Function>::Cast(functionValue);
+ QPair<QObject *, int> functionData = ExtractQtMethod(engine, function);
+
+ if (functionData.second != -1) {
+ // This is a QObject function wrapper
+ for (int ii = 0; ii < connections.count(); ++ii) {
+ QV8QObjectConnectionList::Connection &connection = connections[ii];
+
+ if (connection.thisObject.IsEmpty() == functionThisValue.IsEmpty() &&
+ (connection.thisObject.IsEmpty() || connection.thisObject->StrictEquals(functionThisValue))) {
+
+ QPair<QObject *, int> connectedFunctionData = ExtractQtMethod(engine, connection.function);
+ if (connectedFunctionData == functionData) {
+ // Match!
+ if (connections.connectionsInUse) {
+ connection.needsDestroy = true;
+ connections.connectionsNeedClean = true;
+ } else {
+ connection.dispose();
+ connections.removeAt(ii);
+ }
+ return v8::Undefined();
+ }
+ }
+ }
+
+ } else {
+ // This is a normal JS function
+ for (int ii = 0; ii < connections.count(); ++ii) {
+ QV8QObjectConnectionList::Connection &connection = connections[ii];
+ if (connection.function->StrictEquals(function) &&
+ connection.thisObject.IsEmpty() == functionThisValue.IsEmpty() &&
+ (connection.thisObject.IsEmpty() || connection.thisObject->StrictEquals(functionThisValue))) {
+ // Match!
+ if (connections.connectionsInUse) {
+ connection.needsDestroy = true;
+ connections.connectionsNeedClean = true;
+ } else {
+ connection.dispose();
+ connections.removeAt(ii);
+ }
+ return v8::Undefined();
+ }
+ }
+ }
+
+ return v8::Undefined();
+}
+
+/*!
+ \fn v8::Handle<v8::Value> QV8QObjectWrapper::getProperty(QObject *object, const QHashedV8String &property, QV8QObjectWrapper::RevisionMode revisionMode)
+
+ Get the \a property of \a object. Returns an empty handle if the property doesn't exist.
+
+ Only searches for real properties of \a object (including methods), not attached properties etc.
+*/
+
+/*
+ \fn bool QV8QObjectWrapper::setProperty(QObject *object, const QHashedV8String &property, v8::Handle<v8::Value> value, RevisionMode revisionMode)
+
+ Set the \a property of \a object to \a value.
+
+ Returns true if the property was "set" - even if this results in an exception being thrown -
+ and false if the object has no such property.
+
+ Only searches for real properties of \a object (including methods), not attached properties etc.
+*/
+
+namespace {
+struct CallArgs
+{
+ CallArgs(int length, v8::Handle<v8::Object> *args) : _length(length), _args(args) {}
+ int Length() const { return _length; }
+ v8::Local<v8::Value> operator[](int idx) { return (*_args)->Get(idx); }
+
+private:
+ int _length;
+ v8::Handle<v8::Object> *_args;
+};
+}
+
+static v8::Handle<v8::Value> CallMethod(QObject *object, int index, int returnType, int argCount,
+ int *argTypes, QV8Engine *engine, CallArgs &callArgs)
+{
+ if (argCount > 0) {
+
+ QVarLengthArray<CallArgument, 9> args(argCount + 1);
+ args[0].initAsType(returnType);
+
+ for (int ii = 0; ii < argCount; ++ii)
+ args[ii + 1].fromValue(argTypes[ii], engine, callArgs[ii]);
+
+ QVarLengthArray<void *, 9> argData(args.count());
+ for (int ii = 0; ii < args.count(); ++ii)
+ argData[ii] = args[ii].dataPtr();
+
+ QMetaObject::metacall(object, QMetaObject::InvokeMetaMethod, index, argData.data());
+
+ return args[0].toValue(engine);
+
+ } else if (returnType != 0) {
+
+ CallArgument arg;
+ arg.initAsType(returnType);
+
+ void *args[] = { arg.dataPtr() };
+
+ QMetaObject::metacall(object, QMetaObject::InvokeMetaMethod, index, args);
+
+ return arg.toValue(engine);
+
+ } else {
+
+ void *args[] = { 0 };
+ QMetaObject::metacall(object, QMetaObject::InvokeMetaMethod, index, args);
+ return v8::Undefined();
+
+ }
+}
+
+/*!
+ Returns the match score for converting \a actual to be of type \a conversionType. A
+ zero score means "perfect match" whereas a higher score is worse.
+
+ The conversion table is copied out of the QtScript callQtMethod() function.
+*/
+static int MatchScore(v8::Handle<v8::Value> actual, int conversionType)
+{
+ if (actual->IsNumber()) {
+ switch (conversionType) {
+ case QMetaType::Double:
+ return 0;
+ case QMetaType::Float:
+ return 1;
+ case QMetaType::LongLong:
+ case QMetaType::ULongLong:
+ return 2;
+ case QMetaType::Long:
+ case QMetaType::ULong:
+ return 3;
+ case QMetaType::Int:
+ case QMetaType::UInt:
+ return 4;
+ case QMetaType::Short:
+ case QMetaType::UShort:
+ return 5;
+ break;
+ case QMetaType::Char:
+ case QMetaType::UChar:
+ return 6;
+ default:
+ return 10;
+ }
+ } else if (actual->IsString()) {
+ switch (conversionType) {
+ case QMetaType::QString:
+ return 0;
+ default:
+ return 10;
+ }
+ } else if (actual->IsBoolean()) {
+ switch (conversionType) {
+ case QMetaType::Bool:
+ return 0;
+ default:
+ return 10;
+ }
+ } else if (actual->IsDate()) {
+ switch (conversionType) {
+ case QMetaType::QDateTime:
+ return 0;
+ case QMetaType::QDate:
+ return 1;
+ case QMetaType::QTime:
+ return 2;
+ default:
+ return 10;
+ }
+ } else if (actual->IsRegExp()) {
+ switch (conversionType) {
+ case QMetaType::QRegExp:
+ return 0;
+ default:
+ return 10;
+ }
+ } else if (actual->IsArray()) {
+ switch (conversionType) {
+ case QMetaType::QStringList:
+ case QMetaType::QVariantList:
+ return 5;
+ default:
+ return 10;
+ }
+ } else if (actual->IsNull()) {
+ switch (conversionType) {
+ case QMetaType::VoidStar:
+ case QMetaType::QObjectStar:
+ return 0;
+ default: {
+ const char *typeName = QMetaType::typeName(conversionType);
+ if (typeName && typeName[strlen(typeName) - 1] == '*')
+ return 0;
+ else
+ return 10;
+ }
+ }
+ } else if (actual->IsObject()) {
+ v8::Handle<v8::Object> obj = v8::Handle<v8::Object>::Cast(actual);
+
+ QV8ObjectResource *r = static_cast<QV8ObjectResource *>(obj->GetExternalResource());
+ if (r && r->resourceType() == QV8ObjectResource::QObjectType) {
+ switch (conversionType) {
+ case QMetaType::QObjectStar:
+ return 0;
+ default:
+ return 10;
+ }
+ } else if (r && r->resourceType() == QV8ObjectResource::VariantType) {
+ if (conversionType == qMetaTypeId<QVariant>())
+ return 0;
+ else if (r->engine->toVariant(actual, -1).userType() == conversionType)
+ return 0;
+ else
+ return 10;
+ } else {
+ return 10;
+ }
+
+ } else {
+ return 10;
+ }
+}
+
+static inline int QMetaObject_methods(const QMetaObject *metaObject)
+{
+ struct Private
+ {
+ int revision;
+ int className;
+ int classInfoCount, classInfoData;
+ int methodCount, methodData;
+ };
+
+ return reinterpret_cast<const Private *>(metaObject->d.data)->methodCount;
+}
+
+static QByteArray QMetaMethod_name(const QMetaMethod &m)
+{
+ QByteArray sig = m.signature();
+ int paren = sig.indexOf('(');
+ if (paren == -1)
+ return sig;
+ else
+ return sig.left(paren);
+}
+
+/*!
+Returns the next related method, if one, or 0.
+*/
+static const QQmlPropertyData * RelatedMethod(QObject *object,
+ const QQmlPropertyData *current,
+ QQmlPropertyData &dummy)
+{
+ QQmlPropertyCache *cache = QQmlData::get(object)->propertyCache;
+ if (!current->isOverload())
+ return 0;
+
+ Q_ASSERT(!current->overrideIndexIsProperty);
+
+ if (cache) {
+ return cache->method(current->overrideIndex);
+ } else {
+ const QMetaObject *mo = object->metaObject();
+ int methodOffset = mo->methodCount() - QMetaObject_methods(mo);
+
+ while (methodOffset > current->overrideIndex) {
+ mo = mo->superClass();
+ methodOffset -= QMetaObject_methods(mo);
+ }
+
+ QMetaMethod method = mo->method(current->overrideIndex);
+ dummy.load(method);
+
+ // Look for overloaded methods
+ QByteArray methodName = QMetaMethod_name(method);
+ for (int ii = current->overrideIndex - 1; ii >= methodOffset; --ii) {
+ if (methodName == QMetaMethod_name(mo->method(ii))) {
+ dummy.setFlags(dummy.getFlags() | QQmlPropertyData::IsOverload);
+ dummy.overrideIndexIsProperty = 0;
+ dummy.overrideIndex = ii;
+ return &dummy;
+ }
+ }
+
+ return &dummy;
+ }
+}
+
+static v8::Handle<v8::Value> CallPrecise(QObject *object, const QQmlPropertyData &data,
+ QV8Engine *engine, CallArgs &callArgs)
+{
+ if (data.hasArguments()) {
+
+ int *args = 0;
+ QVarLengthArray<int, 9> dummy;
+ QByteArray unknownTypeError;
+
+ args = QQmlPropertyCache::methodParameterTypes(object, data.coreIndex, dummy,
+ &unknownTypeError);
+
+ if (!args) {
+ QString typeName = QString::fromLatin1(unknownTypeError);
+ QString error = QString::fromLatin1("Unknown method parameter type: %1").arg(typeName);
+ v8::ThrowException(v8::Exception::Error(engine->toString(error)));
+ return v8::Handle<v8::Value>();
+ }
+
+ if (args[0] > callArgs.Length()) {
+ QString error = QLatin1String("Insufficient arguments");
+ v8::ThrowException(v8::Exception::Error(engine->toString(error)));
+ return v8::Handle<v8::Value>();
+ }
+
+ return CallMethod(object, data.coreIndex, data.propType, args[0], args + 1, engine, callArgs);
+
+ } else {
+
+ return CallMethod(object, data.coreIndex, data.propType, 0, 0, engine, callArgs);
+
+ }
+}
+
+/*!
+Resolve the overloaded method to call. The algorithm works conceptually like this:
+ 1. Resolve the set of overloads it is *possible* to call.
+ Impossible overloads include those that have too many parameters or have parameters
+ of unknown type.
+ 2. Filter the set of overloads to only contain those with the closest number of
+ parameters.
+ For example, if we are called with 3 parameters and there are 2 overloads that
+ take 2 parameters and one that takes 3, eliminate the 2 parameter overloads.
+ 3. Find the best remaining overload based on its match score.
+ If two or more overloads have the same match score, call the last one. The match
+ score is constructed by adding the matchScore() result for each of the parameters.
+*/
+static v8::Handle<v8::Value> CallOverloaded(QObject *object, const QQmlPropertyData &data,
+ QV8Engine *engine, CallArgs &callArgs)
+{
+ int argumentCount = callArgs.Length();
+
+ const QQmlPropertyData *best = 0;
+ int bestParameterScore = INT_MAX;
+ int bestMatchScore = INT_MAX;
+
+ QQmlPropertyData dummy;
+ const QQmlPropertyData *attempt = &data;
+
+ do {
+ QVarLengthArray<int, 9> dummy;
+ int methodArgumentCount = 0;
+ int *methodArgTypes = 0;
+ if (attempt->hasArguments()) {
+ typedef QQmlPropertyCache PC;
+ int *args = PC::methodParameterTypes(object, attempt->coreIndex, dummy, 0);
+ if (!args) // Must be an unknown argument
+ continue;
+
+ methodArgumentCount = args[0];
+ methodArgTypes = args + 1;
+ }
+
+ if (methodArgumentCount > argumentCount)
+ continue; // We don't have sufficient arguments to call this method
+
+ int methodParameterScore = argumentCount - methodArgumentCount;
+ if (methodParameterScore > bestParameterScore)
+ continue; // We already have a better option
+
+ int methodMatchScore = 0;
+ for (int ii = 0; ii < methodArgumentCount; ++ii)
+ methodMatchScore += MatchScore(callArgs[ii], methodArgTypes[ii]);
+
+ if (bestParameterScore > methodParameterScore || bestMatchScore > methodMatchScore) {
+ best = attempt;
+ bestParameterScore = methodParameterScore;
+ bestMatchScore = methodMatchScore;
+ }
+
+ if (bestParameterScore == 0 && bestMatchScore == 0)
+ break; // We can't get better than that
+
+ } while((attempt = RelatedMethod(object, attempt, dummy)) != 0);
+
+ if (best) {
+ return CallPrecise(object, *best, engine, callArgs);
+ } else {
+ QString error = QLatin1String("Unable to determine callable overload. Candidates are:");
+ const QQmlPropertyData *candidate = &data;
+ while (candidate) {
+ error += QLatin1String("\n ") +
+ QString::fromUtf8(object->metaObject()->method(candidate->coreIndex).signature());
+ candidate = RelatedMethod(object, candidate, dummy);
+ }
+
+ v8::ThrowException(v8::Exception::Error(engine->toString(error)));
+ return v8::Handle<v8::Value>();
+ }
+}
+
+static v8::Handle<v8::Value> ToString(QV8Engine *engine, QObject *object, int, v8::Handle<v8::Object>)
+{
+ QString result;
+ if (object) {
+ QString objectName = object->objectName();
+
+ result += QString::fromUtf8(object->metaObject()->className());
+ result += QLatin1String("(0x");
+ result += QString::number((quintptr)object,16);
+
+ if (!objectName.isEmpty()) {
+ result += QLatin1String(", \"");
+ result += objectName;
+ result += QLatin1Char('\"');
+ }
+
+ result += QLatin1Char(')');
+ } else {
+ result = QLatin1String("null");
+ }
+
+ return engine->toString(result);
+}
+
+static v8::Handle<v8::Value> Destroy(QV8Engine *, QObject *object, int argCount, v8::Handle<v8::Object> args)
+{
+ QQmlData *ddata = QQmlData::get(object, false);
+ if (!ddata || ddata->indestructible) {
+ const char *error = "Invalid attempt to destroy() an indestructible object";
+ v8::ThrowException(v8::Exception::Error(v8::String::New(error)));
+ return v8::Undefined();
+ }
+
+ int delay = 0;
+ if (argCount > 0)
+ delay = args->Get(0)->Uint32Value();
+
+ if (delay > 0)
+ QTimer::singleShot(delay, object, SLOT(deleteLater()));
+ else
+ object->deleteLater();
+
+ return v8::Undefined();
+}
+
+v8::Handle<v8::Value> QV8QObjectWrapper::Invoke(const v8::Arguments &args)
+{
+ // object, index, qmlglobal, argCount, args
+ Q_ASSERT(args.Length() == 5);
+ Q_ASSERT(args[0]->IsObject());
+
+ QV8QObjectResource *resource = v8_resource_cast<QV8QObjectResource>(args[0]->ToObject());
+
+ if (!resource)
+ return v8::Undefined();
+
+ int argCount = args[3]->Int32Value();
+ v8::Handle<v8::Object> arguments = v8::Handle<v8::Object>::Cast(args[4]);
+
+ // Special hack to return info about this closure.
+ if (argCount == 1 && arguments->Get(0)->StrictEquals(resource->engine->qobjectWrapper()->m_hiddenObject)) {
+ v8::Local<v8::Array> data = v8::Array::New(2);
+ data->Set(0, args[0]);
+ data->Set(1, args[1]);
+ return data;
+ }
+
+ QObject *object = resource->object;
+ int index = args[1]->Int32Value();
+
+ if (!object)
+ return v8::Undefined();
+
+ if (index < 0) {
+ // Builtin functions
+ if (index == QOBJECT_TOSTRING_INDEX) {
+ return ToString(resource->engine, object, argCount, arguments);
+ } else if (index == QOBJECT_DESTROY_INDEX) {
+ return Destroy(resource->engine, object, argCount, arguments);
+ } else {
+ return v8::Undefined();
+ }
+ }
+
+ QQmlPropertyData method;
+
+ if (QQmlData *ddata = static_cast<QQmlData *>(QObjectPrivate::get(object)->declarativeData)) {
+ if (ddata->propertyCache) {
+ QQmlPropertyData *d = ddata->propertyCache->method(index);
+ if (!d)
+ return v8::Undefined();
+ method = *d;
+ }
+ }
+
+ if (method.coreIndex == -1) {
+ method.load(object->metaObject()->method(index));
+
+ if (method.coreIndex == -1)
+ return v8::Undefined();
+ }
+
+ if (method.isV8Function()) {
+ v8::Handle<v8::Value> rv;
+ v8::Handle<v8::Object> qmlglobal = args[2]->ToObject();
+
+ QQmlV8Function func(argCount, arguments, rv, qmlglobal,
+ resource->engine->contextWrapper()->context(qmlglobal),
+ resource->engine);
+ QQmlV8Function *funcptr = &func;
+
+ void *args[] = { 0, &funcptr };
+ QMetaObject::metacall(object, QMetaObject::InvokeMetaMethod, method.coreIndex, args);
+
+ if (rv.IsEmpty()) return v8::Undefined();
+ return rv;
+ }
+
+ CallArgs callArgs(argCount, &arguments);
+ if (!method.isOverload()) {
+ return CallPrecise(object, method, resource->engine, callArgs);
+ } else {
+ return CallOverloaded(object, method, resource->engine, callArgs);
+ }
+}
+
+CallArgument::CallArgument()
+: type(QVariant::Invalid)
+{
+}
+
+CallArgument::~CallArgument()
+{
+ cleanup();
+}
+
+void CallArgument::cleanup()
+{
+ if (type == QMetaType::QString) {
+ qstringPtr->~QString();
+ } else if (type == -1 || type == QMetaType::QVariant) {
+ qvariantPtr->~QVariant();
+ } else if (type == qMetaTypeId<QJSValue>()) {
+ qjsValuePtr->~QJSValue();
+ } else if (type == qMetaTypeId<QList<QObject *> >()) {
+ qlistPtr->~QList<QObject *>();
+ }
+}
+
+void *CallArgument::dataPtr()
+{
+ if (type == -1)
+ return qvariantPtr->data();
+ else
+ return (void *)&allocData;
+}
+
+void CallArgument::initAsType(int callType)
+{
+ if (type != 0) { cleanup(); type = 0; }
+ if (callType == 0) return;
+
+ if (callType == qMetaTypeId<QJSValue>()) {
+ qjsValuePtr = new (&allocData) QJSValue();
+ type = callType;
+ } else if (callType == QMetaType::Int ||
+ callType == QMetaType::UInt ||
+ callType == QMetaType::Bool ||
+ callType == QMetaType::Double ||
+ callType == QMetaType::Float) {
+ type = callType;
+ } else if (callType == QMetaType::QObjectStar) {
+ qobjectPtr = 0;
+ type = callType;
+ } else if (callType == QMetaType::QString) {
+ qstringPtr = new (&allocData) QString();
+ type = callType;
+ } else if (callType == QMetaType::QVariant) {
+ type = callType;
+ qvariantPtr = new (&allocData) QVariant();
+ } else if (callType == qMetaTypeId<QList<QObject *> >()) {
+ type = callType;
+ qlistPtr = new (&allocData) QList<QObject *>();
+ } else if (callType == qMetaTypeId<QQmlV8Handle>()) {
+ type = callType;
+ handlePtr = new (&allocData) QQmlV8Handle;
+ } else {
+ type = -1;
+ qvariantPtr = new (&allocData) QVariant(callType, (void *)0);
+ }
+}
+
+void CallArgument::fromValue(int callType, QV8Engine *engine, v8::Handle<v8::Value> value)
+{
+ if (type != 0) { cleanup(); type = 0; }
+
+ if (callType == qMetaTypeId<QJSValue>()) {
+ qjsValuePtr = new (&allocData) QJSValue(QJSValuePrivate::get(new QJSValuePrivate(engine, value)));
+ type = qMetaTypeId<QJSValue>();
+ } else if (callType == QMetaType::Int) {
+ intValue = quint32(value->Int32Value());
+ type = callType;
+ } else if (callType == QMetaType::UInt) {
+ intValue = quint32(value->Uint32Value());
+ type = callType;
+ } else if (callType == QMetaType::Bool) {
+ boolValue = value->BooleanValue();
+ type = callType;
+ } else if (callType == QMetaType::Double) {
+ doubleValue = double(value->NumberValue());
+ type = callType;
+ } else if (callType == QMetaType::Float) {
+ floatValue = float(value->NumberValue());
+ type = callType;
+ } else if (callType == QMetaType::QString) {
+ if (value->IsNull() || value->IsUndefined())
+ qstringPtr = new (&allocData) QString();
+ else
+ qstringPtr = new (&allocData) QString(engine->toString(value->ToString()));
+ type = callType;
+ } else if (callType == QMetaType::QObjectStar) {
+ qobjectPtr = engine->toQObject(value);
+ type = callType;
+ } else if (callType == qMetaTypeId<QVariant>()) {
+ qvariantPtr = new (&allocData) QVariant(engine->toVariant(value, -1));
+ type = callType;
+ } else if (callType == qMetaTypeId<QList<QObject*> >()) {
+ qlistPtr = new (&allocData) QList<QObject *>();
+ if (value->IsArray()) {
+ v8::Handle<v8::Array> array = v8::Handle<v8::Array>::Cast(value);
+ uint32_t length = array->Length();
+ for (uint32_t ii = 0; ii < length; ++ii)
+ qlistPtr->append(engine->toQObject(array->Get(ii)));
+ } else {
+ qlistPtr->append(engine->toQObject(value));
+ }
+ type = callType;
+ } else if (callType == qMetaTypeId<QQmlV8Handle>()) {
+ handlePtr = new (&allocData) QQmlV8Handle(QQmlV8Handle::fromHandle(value));
+ type = callType;
+ } else {
+ qvariantPtr = new (&allocData) QVariant();
+ type = -1;
+
+ QQmlEnginePrivate *ep = engine->engine() ? QQmlEnginePrivate::get(engine->engine()) : 0;
+ QVariant v = engine->toVariant(value, -1);
+
+ if (v.userType() == callType) {
+ *qvariantPtr = v;
+ } else if (v.canConvert((QVariant::Type)callType)) {
+ *qvariantPtr = v;
+ qvariantPtr->convert((QVariant::Type)callType);
+ } else if (const QMetaObject *mo = ep ? ep->rawMetaObjectForType(callType) : 0) {
+ QObject *obj = ep->toQObject(v);
+
+ if (obj) {
+ const QMetaObject *objMo = obj->metaObject();
+ while (objMo && objMo != mo) objMo = objMo->superClass();
+ if (!objMo) obj = 0;
+ }
+
+ *qvariantPtr = QVariant(callType, &obj);
+ } else {
+ *qvariantPtr = QVariant(callType, (void *)0);
+ }
+ }
+}
+
+v8::Handle<v8::Value> CallArgument::toValue(QV8Engine *engine)
+{
+ if (type == qMetaTypeId<QJSValue>()) {
+ return QJSValuePrivate::get(*qjsValuePtr)->asV8Value(engine);
+ } else if (type == QMetaType::Int) {
+ return v8::Integer::New(int(intValue));
+ } else if (type == QMetaType::UInt) {
+ return v8::Integer::NewFromUnsigned(intValue);
+ } else if (type == QMetaType::Bool) {
+ return v8::Boolean::New(boolValue);
+ } else if (type == QMetaType::Double) {
+ return v8::Number::New(doubleValue);
+ } else if (type == QMetaType::Float) {
+ return v8::Number::New(floatValue);
+ } else if (type == QMetaType::QString) {
+ return engine->toString(*qstringPtr);
+ } else if (type == QMetaType::QObjectStar) {
+ QObject *object = qobjectPtr;
+ if (object)
+ QQmlData::get(object, true)->setImplicitDestructible();
+ return engine->newQObject(object);
+ } else if (type == qMetaTypeId<QList<QObject *> >()) {
+ // XXX Can this be made more by using Array as a prototype and implementing
+ // directly against QList<QObject*>?
+ QList<QObject *> &list = *qlistPtr;
+ v8::Local<v8::Array> array = v8::Array::New(list.count());
+ for (int ii = 0; ii < list.count(); ++ii)
+ array->Set(ii, engine->newQObject(list.at(ii)));
+ return array;
+ } else if (type == qMetaTypeId<QQmlV8Handle>()) {
+ return handlePtr->toHandle();
+ } else if (type == -1 || type == qMetaTypeId<QVariant>()) {
+ QVariant value = *qvariantPtr;
+ v8::Handle<v8::Value> rv = engine->fromVariant(value);
+ if (QObject *object = engine->toQObject(rv))
+ QQmlData::get(object, true)->setImplicitDestructible();
+ return rv;
+ } else {
+ return v8::Undefined();
+ }
+}
+
+QT_END_NAMESPACE
+
diff --git a/src/qml/qml/v8/qv8qobjectwrapper_p.h b/src/qml/qml/v8/qv8qobjectwrapper_p.h
new file mode 100644
index 0000000000..f7b965690b
--- /dev/null
+++ b/src/qml/qml/v8/qv8qobjectwrapper_p.h
@@ -0,0 +1,159 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QV8QOBJECTWRAPPER_P_H
+#define QV8QOBJECTWRAPPER_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qglobal.h>
+#include <QtCore/qmetatype.h>
+#include <QtCore/qpair.h>
+#include <QtCore/qhash.h>
+#include <private/qv8_p.h>
+#include <private/qhashedstring_p.h>
+#include <private/qqmldata_p.h>
+#include <private/qqmlpropertycache_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QObject;
+class QV8Engine;
+class QQmlData;
+class QV8ObjectResource;
+class QV8QObjectInstance;
+class QV8QObjectConnectionList;
+class QQmlPropertyCache;
+class Q_QML_EXPORT QV8QObjectWrapper
+{
+public:
+ QV8QObjectWrapper();
+ ~QV8QObjectWrapper();
+
+ void init(QV8Engine *);
+ void destroy();
+
+ v8::Handle<v8::Value> newQObject(QObject *object);
+ bool isQObject(v8::Handle<v8::Object>);
+ QObject *toQObject(v8::Handle<v8::Object>);
+ static QObject *toQObject(QV8ObjectResource *);
+
+ enum RevisionMode { IgnoreRevision, CheckRevision };
+ inline v8::Handle<v8::Value> getProperty(QObject *, const QHashedV8String &, RevisionMode);
+ inline bool setProperty(QObject *, const QHashedV8String &, v8::Handle<v8::Value>, RevisionMode);
+
+private:
+ friend class QQmlPropertyCache;
+ friend class QV8QObjectConnectionList;
+ friend class QV8QObjectInstance;
+
+ v8::Local<v8::Object> newQObject(QObject *, QQmlData *, QV8Engine *);
+ static v8::Handle<v8::Value> GetProperty(QV8Engine *, QObject *, v8::Handle<v8::Value> *,
+ const QHashedV8String &, QV8QObjectWrapper::RevisionMode);
+ static bool SetProperty(QV8Engine *, QObject *, const QHashedV8String &,
+ v8::Handle<v8::Value>, QV8QObjectWrapper::RevisionMode);
+ static v8::Handle<v8::Value> Getter(v8::Local<v8::String> property,
+ const v8::AccessorInfo &info);
+ static v8::Handle<v8::Value> Setter(v8::Local<v8::String> property,
+ v8::Local<v8::Value> value,
+ const v8::AccessorInfo &info);
+ static v8::Handle<v8::Integer> Query(v8::Local<v8::String> property,
+ const v8::AccessorInfo &info);
+ static v8::Handle<v8::Array> Enumerator(const v8::AccessorInfo &info);
+ static v8::Handle<v8::Value> Connect(const v8::Arguments &args);
+ static v8::Handle<v8::Value> Disconnect(const v8::Arguments &args);
+ static v8::Handle<v8::Value> Invoke(const v8::Arguments &args);
+ static QPair<QObject *, int> ExtractQtMethod(QV8Engine *, v8::Handle<v8::Function>);
+ static QPair<QObject *, int> ExtractQtSignal(QV8Engine *, v8::Handle<v8::Object>);
+
+ QV8Engine *m_engine;
+ quint32 m_id;
+ v8::Persistent<v8::Function> m_constructor;
+ v8::Persistent<v8::Function> m_methodConstructor;
+ v8::Persistent<v8::Function> m_signalHandlerConstructor;
+ v8::Persistent<v8::String> m_toStringSymbol;
+ v8::Persistent<v8::String> m_destroySymbol;
+ QHashedV8String m_toStringString;
+ QHashedV8String m_destroyString;
+ v8::Persistent<v8::Object> m_hiddenObject;
+ QHash<QObject *, QV8QObjectConnectionList *> m_connections;
+ typedef QHash<QObject *, QV8QObjectInstance *> TaintedHash;
+ TaintedHash m_taintedObjects;
+};
+
+v8::Handle<v8::Value> QV8QObjectWrapper::getProperty(QObject *object, const QHashedV8String &string,
+ RevisionMode mode)
+{
+ QQmlData *dd = QQmlData::get(object, false);
+ if (!dd || !dd->propertyCache || m_toStringString == string || m_destroyString == string ||
+ dd->propertyCache->property(string)) {
+ return GetProperty(m_engine, object, 0, string, mode);
+ } else {
+ return v8::Handle<v8::Value>();
+ }
+}
+
+bool QV8QObjectWrapper::setProperty(QObject *object, const QHashedV8String &string,
+ v8::Handle<v8::Value> value, RevisionMode mode)
+{
+ QQmlData *dd = QQmlData::get(object, false);
+ if (!dd || !dd->propertyCache || m_toStringString == string || m_destroyString == string ||
+ dd->propertyCache->property(string)) {
+ return SetProperty(m_engine, object, string, value, mode);
+ } else {
+ return false;
+ }
+}
+
+QT_END_NAMESPACE
+
+#endif // QV8QOBJECTWRAPPER_P_H
+
+
diff --git a/src/qml/qml/v8/qv8sequencewrapper.cpp b/src/qml/qml/v8/qv8sequencewrapper.cpp
new file mode 100644
index 0000000000..883ed1b60c
--- /dev/null
+++ b/src/qml/qml/v8/qv8sequencewrapper.cpp
@@ -0,0 +1,264 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtQml/qqml.h>
+
+#include "qv8sequencewrapper_p.h"
+#include "qv8sequencewrapper_p_p.h"
+#include "qv8engine_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QV8SequenceWrapper::QV8SequenceWrapper()
+ : m_engine(0)
+{
+}
+
+QV8SequenceWrapper::~QV8SequenceWrapper()
+{
+}
+
+#define REGISTER_QML_SEQUENCE_METATYPE(unused, unused2, SequenceType, unused3) qRegisterMetaType<SequenceType>();
+void QV8SequenceWrapper::init(QV8Engine *engine)
+{
+ FOREACH_QML_SEQUENCE_TYPE(REGISTER_QML_SEQUENCE_METATYPE)
+
+ m_engine = engine;
+ m_toString = qPersistentNew<v8::Function>(v8::FunctionTemplate::New(ToString)->GetFunction());
+ m_valueOf = qPersistentNew<v8::Function>(v8::FunctionTemplate::New(ValueOf)->GetFunction());
+ v8::Local<v8::FunctionTemplate> ft = v8::FunctionTemplate::New();
+ ft->InstanceTemplate()->SetFallbackPropertyHandler(Getter, Setter);
+ ft->InstanceTemplate()->SetIndexedPropertyHandler(IndexedGetter, IndexedSetter, 0, IndexedDeleter, IndexedEnumerator);
+ ft->InstanceTemplate()->SetAccessor(v8::String::New("length"), LengthGetter, LengthSetter,
+ v8::Handle<v8::Value>(), v8::DEFAULT,
+ v8::PropertyAttribute(v8::DontDelete | v8::DontEnum));
+ ft->InstanceTemplate()->SetAccessor(v8::String::New("toString"), ToStringGetter, 0,
+ m_toString, v8::DEFAULT,
+ v8::PropertyAttribute(v8::ReadOnly | v8::DontDelete | v8::DontEnum));
+ ft->InstanceTemplate()->SetAccessor(v8::String::New("valueOf"), ValueOfGetter, 0,
+ m_valueOf, v8::DEFAULT,
+ v8::PropertyAttribute(v8::ReadOnly | v8::DontDelete | v8::DontEnum));
+ ft->InstanceTemplate()->SetHasExternalResource(true);
+ ft->InstanceTemplate()->MarkAsUseUserObjectComparison();
+ m_constructor = qPersistentNew<v8::Function>(ft->GetFunction());
+}
+#undef REGISTER_QML_SEQUENCE_METATYPE
+
+void QV8SequenceWrapper::destroy()
+{
+ qPersistentDispose(m_toString);
+ qPersistentDispose(m_valueOf);
+ qPersistentDispose(m_constructor);
+}
+
+bool QV8SequenceWrapper::isEqual(QV8ObjectResource *lhs, QV8ObjectResource *rhs)
+{
+ Q_ASSERT(lhs && rhs && lhs->resourceType() == QV8ObjectResource::SequenceType && rhs->resourceType() == QV8ObjectResource::SequenceType);
+ QV8SequenceResource *lr = static_cast<QV8SequenceResource *>(lhs);
+ QV8SequenceResource *rr = static_cast<QV8SequenceResource *>(rhs);
+ return lr->isEqual(rr);
+}
+
+quint32 QV8SequenceWrapper::sequenceLength(QV8ObjectResource *r)
+{
+ Q_ASSERT(r->resourceType() == QV8ObjectResource::SequenceType);
+ QV8SequenceResource *sr = static_cast<QV8SequenceResource *>(r);
+ Q_ASSERT(sr);
+ return sr->lengthGetter();
+}
+
+#define NEW_REFERENCE_SEQUENCE(ElementType, ElementTypeName, SequenceType, unused) \
+ if (sequenceType == qMetaTypeId<SequenceType>()) { \
+ r = new QV8##ElementTypeName##SequenceResource(m_engine, object, propertyIndex); \
+ } else
+
+v8::Local<v8::Object> QV8SequenceWrapper::newSequence(int sequenceType, QObject *object, int propertyIndex, bool *succeeded)
+{
+ // This function is called when the property is a QObject Q_PROPERTY of
+ // the given sequence type. Internally we store a typed-sequence
+ // (as well as object ptr + property index for updated-read and write-back)
+ // and so access/mutate avoids variant conversion.
+ *succeeded = true;
+ QV8SequenceResource *r = 0;
+ FOREACH_QML_SEQUENCE_TYPE(NEW_REFERENCE_SEQUENCE) { /* else */ *succeeded = false; return v8::Local<v8::Object>(); }
+
+ v8::Local<v8::Object> rv = m_constructor->NewInstance();
+ rv->SetExternalResource(r);
+ rv->SetPrototype(v8::Array::New(1)->GetPrototype());
+ return rv;
+}
+#undef NEW_REFERENCE_SEQUENCE
+
+#define NEW_COPY_SEQUENCE(ElementType, ElementTypeName, SequenceType, unused) \
+ if (sequenceType == qMetaTypeId<SequenceType>()) { \
+ r = new QV8##ElementTypeName##SequenceResource(m_engine, v.value<SequenceType>()); \
+ } else
+
+v8::Local<v8::Object> QV8SequenceWrapper::fromVariant(const QVariant& v, bool *succeeded)
+{
+ // This function is called when assigning a sequence value to a normal JS var
+ // in a JS block. Internally, we store a sequence of the specified type.
+ // Access and mutation is extremely fast since it will not need to modify any
+ // QObject property.
+ int sequenceType = v.userType();
+ *succeeded = true;
+ QV8SequenceResource *r = 0;
+ FOREACH_QML_SEQUENCE_TYPE(NEW_COPY_SEQUENCE) { /* else */ *succeeded = false; return v8::Local<v8::Object>(); }
+
+ v8::Local<v8::Object> rv = m_constructor->NewInstance();
+ rv->SetExternalResource(r);
+ rv->SetPrototype(v8::Array::New(1)->GetPrototype());
+ return rv;
+}
+#undef NEW_COPY_SEQUENCE
+
+QVariant QV8SequenceWrapper::toVariant(QV8ObjectResource *r)
+{
+ Q_ASSERT(r->resourceType() == QV8ObjectResource::SequenceType);
+ QV8SequenceResource *resource = static_cast<QV8SequenceResource *>(r);
+ return resource->toVariant();
+}
+
+#define SEQUENCE_TO_VARIANT(ElementType, ElementTypeName, SequenceType, unused) \
+ if (typeHint == qMetaTypeId<SequenceType>()) { \
+ return QV8##ElementTypeName##SequenceResource::toVariant(m_engine, array, length, succeeded); \
+ } else
+
+QVariant QV8SequenceWrapper::toVariant(v8::Handle<v8::Array> array, int typeHint, bool *succeeded)
+{
+ *succeeded = true;
+ uint32_t length = array->Length();
+ FOREACH_QML_SEQUENCE_TYPE(SEQUENCE_TO_VARIANT) { /* else */ *succeeded = false; return QVariant(); }
+}
+#undef SEQUENCE_TO_VARIANT
+
+v8::Handle<v8::Value> QV8SequenceWrapper::IndexedSetter(quint32 index, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
+{
+ QV8SequenceResource *sr = v8_resource_cast<QV8SequenceResource>(info.This());
+ Q_ASSERT(sr);
+ return sr->indexedSetter(index, value);
+}
+
+v8::Handle<v8::Value> QV8SequenceWrapper::IndexedGetter(quint32 index, const v8::AccessorInfo &info)
+{
+ QV8SequenceResource *sr = v8_resource_cast<QV8SequenceResource>(info.This());
+ Q_ASSERT(sr);
+ return sr->indexedGetter(index);
+}
+
+v8::Handle<v8::Boolean> QV8SequenceWrapper::IndexedDeleter(quint32 index, const v8::AccessorInfo &info)
+{
+ QV8SequenceResource *sr = v8_resource_cast<QV8SequenceResource>(info.This());
+ Q_ASSERT(sr);
+ return sr->indexedDeleter(index);
+}
+
+v8::Handle<v8::Array> QV8SequenceWrapper::IndexedEnumerator(const v8::AccessorInfo &info)
+{
+ QV8SequenceResource *sr = v8_resource_cast<QV8SequenceResource>(info.This());
+ Q_ASSERT(sr);
+ return sr->indexedEnumerator();
+}
+
+v8::Handle<v8::Value> QV8SequenceWrapper::LengthGetter(v8::Local<v8::String> property, const v8::AccessorInfo &info)
+{
+ Q_UNUSED(property);
+ QV8SequenceResource *sr = v8_resource_cast<QV8SequenceResource>(info.This());
+ Q_ASSERT(sr);
+ return v8::Integer::NewFromUnsigned(sr->lengthGetter());
+}
+
+void QV8SequenceWrapper::LengthSetter(v8::Local<v8::String> property, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
+{
+ Q_UNUSED(property);
+ QV8SequenceResource *sr = v8_resource_cast<QV8SequenceResource>(info.This());
+ Q_ASSERT(sr);
+ sr->lengthSetter(value);
+}
+
+v8::Handle<v8::Value> QV8SequenceWrapper::ToStringGetter(v8::Local<v8::String> property, const v8::AccessorInfo &info)
+{
+ Q_UNUSED(property);
+ return info.Data();
+}
+
+v8::Handle<v8::Value> QV8SequenceWrapper::ValueOfGetter(v8::Local<v8::String> property,
+ const v8::AccessorInfo &info)
+{
+ Q_UNUSED(property);
+ return info.Data();
+}
+
+v8::Handle<v8::Value> QV8SequenceWrapper::ToString(const v8::Arguments &args)
+{
+ QV8SequenceResource *sr = v8_resource_cast<QV8SequenceResource>(args.This());
+ Q_ASSERT(sr);
+ return sr->toString();
+}
+
+v8::Handle<v8::Value> QV8SequenceWrapper::ValueOf(const v8::Arguments &args)
+{
+ QV8SequenceResource *sr = v8_resource_cast<QV8SequenceResource>(args.This());
+ Q_ASSERT(sr);
+ v8::Handle<v8::Value> tostringValue = sr->toString();
+ if (!tostringValue.IsEmpty())
+ return tostringValue;
+ return v8::Integer::NewFromUnsigned(sr->lengthGetter());
+}
+
+v8::Handle<v8::Value> QV8SequenceWrapper::Getter(v8::Local<v8::String> property,
+ const v8::AccessorInfo &info)
+{
+ Q_UNUSED(property);
+ Q_UNUSED(info);
+ return v8::Handle<v8::Value>();
+}
+
+v8::Handle<v8::Value> QV8SequenceWrapper::Setter(v8::Local<v8::String> property,
+ v8::Local<v8::Value> value,
+ const v8::AccessorInfo &info)
+{
+ Q_UNUSED(property);
+ Q_UNUSED(info);
+ return value;
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/v8/qv8sequencewrapper_p.h b/src/qml/qml/v8/qv8sequencewrapper_p.h
new file mode 100644
index 0000000000..104135ff76
--- /dev/null
+++ b/src/qml/qml/v8/qv8sequencewrapper_p.h
@@ -0,0 +1,106 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QV8SEQUENCEWRAPPER_P_H
+#define QV8SEQUENCEWRAPPER_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qglobal.h>
+#include <QtCore/qvariant.h>
+#include <private/qv8_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QV8Engine;
+class QV8ObjectResource;
+class QV8SequenceWrapper
+{
+public:
+ QV8SequenceWrapper();
+ ~QV8SequenceWrapper();
+
+ void init(QV8Engine *);
+ void destroy();
+
+ bool isEqual(QV8ObjectResource *lhs, const QVariant &rhs);
+ bool isEqual(QV8ObjectResource *lhs, QV8ObjectResource *rhs);
+ quint32 sequenceLength(QV8ObjectResource *);
+
+ v8::Local<v8::Object> newSequence(int sequenceTypeId, QObject *object, int propertyIndex, bool *succeeded);
+ v8::Local<v8::Object> fromVariant(const QVariant& v, bool *succeeded);
+ QVariant toVariant(QV8ObjectResource *);
+ QVariant toVariant(v8::Handle<v8::Array> array, int typeHint, bool *succeeded);
+
+private:
+ QV8Engine *m_engine;
+
+ v8::Persistent<v8::Function> m_constructor;
+ v8::Persistent<v8::Function> m_toString;
+ v8::Persistent<v8::Function> m_valueOf;
+
+ static v8::Handle<v8::Value> IndexedGetter(quint32 index, const v8::AccessorInfo &info);
+ static v8::Handle<v8::Value> IndexedSetter(quint32 index, v8::Local<v8::Value> value, const v8::AccessorInfo &info);
+ static v8::Handle<v8::Boolean> IndexedDeleter(quint32 index, const v8::AccessorInfo &info);
+ static v8::Handle<v8::Array> IndexedEnumerator(const v8::AccessorInfo &info);
+ static v8::Handle<v8::Value> LengthGetter(v8::Local<v8::String> property, const v8::AccessorInfo &info);
+ static void LengthSetter(v8::Local<v8::String> property, v8::Local<v8::Value> value, const v8::AccessorInfo &info);
+ static v8::Handle<v8::Value> ToStringGetter(v8::Local<v8::String> property, const v8::AccessorInfo &info);
+ static v8::Handle<v8::Value> ToString(const v8::Arguments &args);
+ static v8::Handle<v8::Value> ValueOfGetter(v8::Local<v8::String> property, const v8::AccessorInfo &info);
+ static v8::Handle<v8::Value> ValueOf(const v8::Arguments &args);
+ static v8::Handle<v8::Value> Getter(v8::Local<v8::String> property, const v8::AccessorInfo &info);
+ static v8::Handle<v8::Value> Setter(v8::Local<v8::String> property, v8::Local<v8::Value> value, const v8::AccessorInfo &info);
+};
+
+
+QT_END_NAMESPACE
+
+#endif // QV8SEQUENCEWRAPPER_P_H
diff --git a/src/qml/qml/v8/qv8sequencewrapper_p_p.h b/src/qml/qml/v8/qv8sequencewrapper_p_p.h
new file mode 100644
index 0000000000..9d519809fa
--- /dev/null
+++ b/src/qml/qml/v8/qv8sequencewrapper_p_p.h
@@ -0,0 +1,503 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QV8SEQUENCEWRAPPER_P_P_H
+#define QV8SEQUENCEWRAPPER_P_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qqmlengine_p.h>
+#include <private/qqmlmetatype_p.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \internal
+ \class QV8SequenceResource
+ \brief The abstract base class of the external resource used in sequence type objects
+
+ Every sequence type object returned by QV8SequenceWrapper::fromVariant() or
+ QV8SequenceWrapper::newSequence() has a type-specific QV8SequenceResource which
+ contains the type name, the meta type ids of the sequence and sequence element
+ types, as well as either the sequence data (copy) or object pointer and property
+ index (reference) data associated with the sequence.
+ */
+class QV8SequenceResource : public QV8ObjectResource
+{
+ V8_RESOURCE_TYPE(SequenceType);
+
+public:
+ virtual ~QV8SequenceResource() {}
+
+ enum ObjectType { Reference, Copy };
+
+ virtual QVariant toVariant() = 0;
+ virtual bool isEqual(const QV8SequenceResource *v) = 0;
+
+ virtual quint32 lengthGetter() = 0;
+ virtual void lengthSetter(v8::Handle<v8::Value> value) = 0;
+ virtual v8::Handle<v8::Value> indexedSetter(quint32 index, v8::Handle<v8::Value> value) = 0;
+ virtual v8::Handle<v8::Value> indexedGetter(quint32 index) = 0;
+ virtual v8::Handle<v8::Boolean> indexedDeleter(quint32 index) = 0;
+ virtual v8::Handle<v8::Array> indexedEnumerator() = 0;
+ virtual v8::Handle<v8::Value> toString() = 0;
+
+ ObjectType objectType;
+ QByteArray typeName;
+ int sequenceMetaTypeId;
+ int elementMetaTypeId;
+
+protected:
+ QV8SequenceResource(QV8Engine *engine, ObjectType type, const QByteArray &name, int sequenceId, int elementId)
+ : QV8ObjectResource(engine), objectType(type), typeName(name), sequenceMetaTypeId(sequenceId), elementMetaTypeId(elementId)
+ {
+ }
+};
+
+// helper function to generate valid warnings if errors occur during sequence operations.
+static void generateWarning(QV8Engine *engine, const QString& description)
+{
+ if (!engine)
+ return;
+ v8::Local<v8::StackTrace> currStack = v8::StackTrace::CurrentStackTrace(1);
+ if (currStack.IsEmpty())
+ return;
+ v8::Local<v8::StackFrame> currFrame = currStack->GetFrame(0);
+ if (currFrame.IsEmpty())
+ return;
+
+ QQmlError retn;
+ retn.setDescription(description);
+ retn.setLine(currFrame->GetLineNumber());
+ retn.setUrl(QUrl(engine->toString(currFrame->GetScriptName())));
+ QQmlEnginePrivate::warning(engine->engine(), retn);
+}
+
+
+static int convertV8ValueToInt(QV8Engine *, v8::Handle<v8::Value> v)
+{
+ return v->Int32Value();
+}
+
+static v8::Handle<v8::Value> convertIntToV8Value(QV8Engine *, int v)
+{
+ return v8::Integer::New(v);
+}
+
+static QString convertIntToString(QV8Engine *, int v)
+{
+ return QString::number(v);
+}
+
+static qreal convertV8ValueToReal(QV8Engine *, v8::Handle<v8::Value> v)
+{
+ return v->NumberValue();
+}
+
+static v8::Handle<v8::Value> convertRealToV8Value(QV8Engine *, qreal v)
+{
+ return v8::Number::New(v);
+}
+
+static QString convertRealToString(QV8Engine *, qreal v)
+{
+ return QString::number(v);
+}
+
+static bool convertV8ValueToBool(QV8Engine *, v8::Handle<v8::Value> v)
+{
+ return v->BooleanValue();
+}
+
+static v8::Handle<v8::Value> convertBoolToV8Value(QV8Engine *, bool v)
+{
+ return v8::Boolean::New(v);
+}
+
+static QString convertBoolToString(QV8Engine *, bool v)
+{
+ if (v)
+ return QLatin1String("true");
+ return QLatin1String("false");
+}
+
+static QString convertV8ValueToString(QV8Engine *e, v8::Handle<v8::Value> v)
+{
+ return e->toString(v->ToString());
+}
+
+static v8::Handle<v8::Value> convertStringToV8Value(QV8Engine *e, const QString &v)
+{
+ return e->toString(v);
+}
+
+static QString convertStringToString(QV8Engine *, const QString &v)
+{
+ return v;
+}
+
+static QString convertV8ValueToQString(QV8Engine *e, v8::Handle<v8::Value> v)
+{
+ return e->toString(v->ToString());
+}
+
+static v8::Handle<v8::Value> convertQStringToV8Value(QV8Engine *e, const QString &v)
+{
+ return e->toString(v);
+}
+
+static QString convertQStringToString(QV8Engine *, const QString &v)
+{
+ return v;
+}
+
+static QUrl convertV8ValueToUrl(QV8Engine *e, v8::Handle<v8::Value> v)
+{
+ QUrl u;
+ u.setEncodedUrl(e->toString(v->ToString()).toUtf8(), QUrl::TolerantMode);
+ return u;
+}
+
+static v8::Handle<v8::Value> convertUrlToV8Value(QV8Engine *e, const QUrl &v)
+{
+ return e->toString(QLatin1String(v.toEncoded().data()));
+}
+
+static QString convertUrlToString(QV8Engine *, const QUrl &v)
+{
+ return v.toString();
+}
+
+
+/*
+ \internal
+ \class QV8<Type>SequenceResource
+ \brief The external resource used in sequence type objects
+
+ Every sequence type object returned by QV8SequenceWrapper::newSequence() has
+ a QV8<Type>SequenceResource which contains a property index and a pointer
+ to the object which contains the property.
+
+ Every sequence type object returned by QV8SequenceWrapper::fromVariant() has
+ a QV8<Type>SequenceResource which contains a copy of the sequence value.
+ Operations on the sequence are implemented directly in terms of that sequence data.
+
+ There exists one QV8<Type>SequenceResource instance for every JavaScript Object
+ (sequence) instance returned from QV8SequenceWrapper::newSequence() or
+ QV8SequenceWrapper::fromVariant().
+ */
+
+// F(elementType, elementTypeName, sequenceType, defaultValue)
+#define FOREACH_QML_SEQUENCE_TYPE(F) \
+ F(int, Int, QList<int>, 0) \
+ F(qreal, Real, QList<qreal>, 0.0) \
+ F(bool, Bool, QList<bool>, false) \
+ F(QString, String, QList<QString>, QString()) \
+ F(QString, QString, QStringList, QString()) \
+ F(QUrl, Url, QList<QUrl>, QUrl())
+
+#define QML_SEQUENCE_TYPE_RESOURCE(SequenceElementType, SequenceElementTypeName, SequenceType, DefaultValue, ConversionToV8fn, ConversionFromV8fn, ToStringfn) \
+ QT_END_NAMESPACE \
+ Q_DECLARE_METATYPE(SequenceType) \
+ QT_BEGIN_NAMESPACE \
+ class QV8##SequenceElementTypeName##SequenceResource : public QV8SequenceResource { \
+ public:\
+ QV8##SequenceElementTypeName##SequenceResource(QV8Engine *engine, QObject *obj, int propIdx) \
+ : QV8SequenceResource(engine, QV8SequenceResource::Reference, #SequenceType, qMetaTypeId<SequenceType>(), qMetaTypeId<SequenceElementType>()) \
+ , object(obj), propertyIndex(propIdx) \
+ { \
+ } \
+ QV8##SequenceElementTypeName##SequenceResource(QV8Engine *engine, const SequenceType &value) \
+ : QV8SequenceResource(engine, QV8SequenceResource::Copy, #SequenceType, qMetaTypeId<SequenceType>(), qMetaTypeId<SequenceElementType>()) \
+ , object(0), propertyIndex(-1), c(value) \
+ { \
+ } \
+ ~QV8##SequenceElementTypeName##SequenceResource() \
+ { \
+ } \
+ static QVariant toVariant(QV8Engine *e, v8::Handle<v8::Array> array, uint32_t length, bool *succeeded) \
+ { \
+ SequenceType list; \
+ for (uint32_t ii = 0; ii < length; ++ii) { \
+ list.append(ConversionFromV8fn(e, array->Get(ii))); \
+ } \
+ *succeeded = true; \
+ return QVariant::fromValue<SequenceType>(list); \
+ } \
+ QVariant toVariant() \
+ { \
+ if (objectType == QV8SequenceResource::Reference) { \
+ if (!object) \
+ return QVariant(); \
+ loadReference(); \
+ } \
+ return QVariant::fromValue<SequenceType>(c); \
+ } \
+ bool isEqual(const QV8SequenceResource *v) \
+ { \
+ /* Note: two different sequences can never be equal (even if they */ \
+ /* contain the same elements in the same order) in order to */ \
+ /* maintain JavaScript semantics. However, if they both reference */ \
+ /* the same QObject+propertyIndex, they are equal. */ \
+ if (objectType == QV8SequenceResource::Reference && v->objectType == QV8SequenceResource::Reference) { \
+ if (sequenceMetaTypeId == v->sequenceMetaTypeId) { \
+ const QV8##SequenceElementTypeName##SequenceResource *rhs = static_cast<const QV8##SequenceElementTypeName##SequenceResource *>(v); \
+ return (object != 0 && object == rhs->object && propertyIndex == rhs->propertyIndex); \
+ } \
+ } else if (objectType == QV8SequenceResource::Copy && v->objectType == QV8SequenceResource::Copy) { \
+ if (sequenceMetaTypeId == v->sequenceMetaTypeId) { \
+ const QV8##SequenceElementTypeName##SequenceResource *rhs = static_cast<const QV8##SequenceElementTypeName##SequenceResource *>(v); \
+ return (this == rhs); \
+ } \
+ } \
+ return false; \
+ } \
+ quint32 lengthGetter() \
+ { \
+ if (objectType == QV8SequenceResource::Reference) { \
+ if (!object) \
+ return 0; \
+ loadReference(); \
+ } \
+ return static_cast<quint32>(c.count()); \
+ } \
+ void lengthSetter(v8::Handle<v8::Value> value) \
+ { \
+ /* Get the new required length */ \
+ if (value.IsEmpty() || !value->IsUint32()) \
+ return; \
+ quint32 newLength = value->Uint32Value(); \
+ /* Qt containers have int (rather than uint) allowable indexes. */ \
+ if (newLength > INT_MAX) { \
+ generateWarning(engine, QLatin1String("Index out of range during length set")); \
+ return; \
+ } \
+ /* Read the sequence from the QObject property if we're a reference */ \
+ if (objectType == QV8SequenceResource::Reference) { \
+ if (!object) \
+ return; \
+ loadReference(); \
+ } \
+ /* Determine whether we need to modify the sequence */ \
+ qint32 newCount = static_cast<qint32>(newLength); \
+ qint32 count = c.count(); \
+ if (newCount == count) { \
+ return; \
+ } else if (newCount > count) { \
+ /* according to ECMA262r3 we need to insert */ \
+ /* undefined values increasing length to newLength. */ \
+ /* We cannot, so we insert default-values instead. */ \
+ while (newCount > count++) { \
+ QT_TRY { \
+ c.append(DefaultValue); \
+ } QT_CATCH (std::bad_alloc &exception) { \
+ generateWarning(engine, QString(QLatin1String(exception.what()) \
+ + QLatin1String(" during length set"))); \
+ return; /* failed; don't write back any result. */ \
+ } \
+ } \
+ } else { \
+ /* according to ECMA262r3 we need to remove */ \
+ /* elements until the sequence is the required length. */ \
+ while (newCount < count) { \
+ count--; \
+ c.removeAt(count); \
+ } \
+ } \
+ /* write back if required. */ \
+ if (objectType == QV8SequenceResource::Reference) { \
+ /* write back. already checked that object is non-null, so skip that check here. */ \
+ storeReference(); \
+ } \
+ return; \
+ } \
+ v8::Handle<v8::Value> indexedSetter(quint32 index, v8::Handle<v8::Value> value) \
+ { \
+ /* Qt containers have int (rather than uint) allowable indexes. */ \
+ if (index > INT_MAX) { \
+ generateWarning(engine, QLatin1String("Index out of range during indexed set")); \
+ return v8::Undefined(); \
+ } \
+ if (objectType == QV8SequenceResource::Reference) { \
+ if (!object) \
+ return v8::Undefined(); \
+ loadReference(); \
+ } \
+ /* modify the sequence */ \
+ SequenceElementType elementValue = ConversionFromV8fn(engine, value); \
+ qint32 count = c.count(); \
+ qint32 signedIdx = static_cast<qint32>(index); \
+ if (signedIdx == count) { \
+ c.append(elementValue); \
+ } else if (signedIdx < count) { \
+ c[index] = elementValue; \
+ } else { \
+ /* according to ECMA262r3 we need to insert */ \
+ /* the value at the given index, increasing length to index+1. */ \
+ QT_TRY { \
+ while (signedIdx > count++) { \
+ c.append(DefaultValue); \
+ } \
+ c.append(elementValue); \
+ } QT_CATCH (std::bad_alloc &exception) { \
+ generateWarning(engine, QString(QLatin1String(exception.what()) \
+ + QLatin1String(" during indexed set"))); \
+ return v8::Undefined(); /* failed; don't write back any result. */ \
+ } \
+ } \
+ /* write back. already checked that object is non-null, so skip that check here. */ \
+ if (objectType == QV8SequenceResource::Reference) \
+ storeReference(); \
+ return value; \
+ } \
+ v8::Handle<v8::Value> indexedGetter(quint32 index) \
+ { \
+ /* Qt containers have int (rather than uint) allowable indexes. */ \
+ if (index > INT_MAX) { \
+ generateWarning(engine, QLatin1String("Index out of range during indexed get")); \
+ return v8::Undefined(); \
+ } \
+ if (objectType == QV8SequenceResource::Reference) { \
+ if (!object) \
+ return v8::Undefined(); \
+ loadReference(); \
+ } \
+ qint32 count = c.count(); \
+ qint32 signedIdx = static_cast<qint32>(index); \
+ if (signedIdx < count) \
+ return ConversionToV8fn(engine, c.at(signedIdx)); \
+ return v8::Undefined(); \
+ } \
+ v8::Handle<v8::Boolean> indexedDeleter(quint32 index) \
+ { \
+ /* Qt containers have int (rather than uint) allowable indexes. */ \
+ if (index > INT_MAX) \
+ return v8::Boolean::New(false); \
+ /* Read in the sequence from the QObject */ \
+ if (objectType == QV8SequenceResource::Reference) { \
+ if (!object) \
+ return v8::Boolean::New(false); \
+ loadReference(); \
+ } \
+ qint32 signedIdx = static_cast<qint32>(index); \
+ if (signedIdx < c.count()) { \
+ /* according to ECMA262r3 it should be Undefined, */ \
+ /* but we cannot, so we insert a default-value instead. */ \
+ c.replace(signedIdx, DefaultValue); \
+ if (objectType == QV8SequenceResource::Reference) { \
+ /* write back. already checked that object is non-null, so skip that check here. */ \
+ storeReference(); \
+ } \
+ return v8::Boolean::New(true); \
+ } \
+ return v8::Boolean::New(false); \
+ } \
+ v8::Handle<v8::Array> indexedEnumerator() \
+ { \
+ if (objectType == QV8SequenceResource::Reference) { \
+ if (!object) \
+ return v8::Handle<v8::Array>(); \
+ loadReference(); \
+ } \
+ qint32 count = c.count(); \
+ v8::Local<v8::Array> retn = v8::Array::New(count); \
+ for (qint32 i = 0; i < count; ++i) { \
+ retn->Set(static_cast<quint32>(i), v8::Integer::NewFromUnsigned(static_cast<quint32>(i))); \
+ } \
+ return retn; \
+ } \
+ v8::Handle<v8::Value> toString() \
+ { \
+ if (objectType == QV8SequenceResource::Reference) { \
+ if (!object) \
+ return v8::Undefined(); \
+ loadReference(); \
+ } \
+ QString str; \
+ qint32 count = c.count(); \
+ for (qint32 i = 0; i < count; ++i) { \
+ str += QString(QLatin1String("%1,")).arg(ToStringfn(engine, c[i])); \
+ } \
+ str.chop(1); \
+ return engine->toString(str); \
+ } \
+ void loadReference() \
+ { \
+ Q_ASSERT(object); \
+ Q_ASSERT(objectType == QV8SequenceResource::Reference); \
+ void *a[] = { &c, 0 }; \
+ QMetaObject::metacall(object, QMetaObject::ReadProperty, propertyIndex, a); \
+ } \
+ void storeReference() \
+ { \
+ Q_ASSERT(object); \
+ Q_ASSERT(objectType == QV8SequenceResource::Reference); \
+ int status = -1; \
+ QQmlPropertyPrivate::WriteFlags flags = \
+ QQmlPropertyPrivate::DontRemoveBinding; \
+ void *a[] = { &c, 0, &status, &flags }; \
+ QMetaObject::metacall(object, QMetaObject::WriteProperty, propertyIndex, a); \
+ } \
+ private: \
+ QQmlGuard<QObject> object; \
+ int propertyIndex; \
+ SequenceType c; \
+ };
+
+#define GENERATE_QML_SEQUENCE_TYPE_RESOURCE(ElementType, ElementTypeName, SequenceType, DefaultValue) \
+ QML_SEQUENCE_TYPE_RESOURCE(ElementType, ElementTypeName, SequenceType, DefaultValue, convert##ElementTypeName##ToV8Value, convertV8ValueTo##ElementTypeName, convert##ElementTypeName##ToString)
+
+FOREACH_QML_SEQUENCE_TYPE(GENERATE_QML_SEQUENCE_TYPE_RESOURCE)
+#undef GENERATE_QML_SEQUENCE_TYPE_RESOURCE
+#undef QML_SEQUENCE_TYPE_RESOURCE
+
+QT_END_NAMESPACE
+
+#endif // QV8SEQUENCEWRAPPER_P_P_H
diff --git a/src/qml/qml/v8/qv8sqlerrors.cpp b/src/qml/qml/v8/qv8sqlerrors.cpp
new file mode 100644
index 0000000000..8c5856ea18
--- /dev/null
+++ b/src/qml/qml/v8/qv8sqlerrors.cpp
@@ -0,0 +1,64 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qv8sqlerrors_p.h"
+#include "qv8engine_p.h"
+
+QT_BEGIN_NAMESPACE
+
+void qt_add_sqlexceptions(QV8Engine *engine)
+{
+ // SQL Exception
+ v8::PropertyAttribute attributes = (v8::PropertyAttribute)(v8::ReadOnly | v8::DontEnum | v8::DontDelete);
+
+ v8::Local<v8::Object> sqlexception = v8::Object::New();
+ sqlexception->Set(v8::String::New("UNKNOWN_ERR"), v8::Integer::New(SQLEXCEPTION_UNKNOWN_ERR), attributes);
+ sqlexception->Set(v8::String::New("DATABASE_ERR"), v8::Integer::New(SQLEXCEPTION_DATABASE_ERR), attributes);
+ sqlexception->Set(v8::String::New("VERSION_ERR"), v8::Integer::New(SQLEXCEPTION_VERSION_ERR), attributes);
+ sqlexception->Set(v8::String::New("TOO_LARGE_ERR"), v8::Integer::New(SQLEXCEPTION_TOO_LARGE_ERR), attributes);
+ sqlexception->Set(v8::String::New("QUOTA_ERR"), v8::Integer::New(SQLEXCEPTION_QUOTA_ERR), attributes);
+ sqlexception->Set(v8::String::New("SYNTAX_ERR"), v8::Integer::New(SQLEXCEPTION_SYNTAX_ERR), attributes);
+ sqlexception->Set(v8::String::New("CONSTRAINT_ERR"), v8::Integer::New(SQLEXCEPTION_CONSTRAINT_ERR), attributes);
+ sqlexception->Set(v8::String::New("TIMEOUT_ERR"), v8::Integer::New(SQLEXCEPTION_TIMEOUT_ERR), attributes);
+ engine->global()->Set(v8::String::New("SQLException"), sqlexception);
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/v8/qv8sqlerrors_p.h b/src/qml/qml/v8/qv8sqlerrors_p.h
new file mode 100644
index 0000000000..c799be6e7c
--- /dev/null
+++ b/src/qml/qml/v8/qv8sqlerrors_p.h
@@ -0,0 +1,77 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QV8SQLERRORS_P_H
+#define QV8SQLERRORS_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qglobal.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+#define SQLEXCEPTION_UNKNOWN_ERR 1
+#define SQLEXCEPTION_DATABASE_ERR 2
+#define SQLEXCEPTION_VERSION_ERR 3
+#define SQLEXCEPTION_TOO_LARGE_ERR 4
+#define SQLEXCEPTION_QUOTA_ERR 5
+#define SQLEXCEPTION_SYNTAX_ERR 6
+#define SQLEXCEPTION_CONSTRAINT_ERR 7
+#define SQLEXCEPTION_TIMEOUT_ERR 8
+
+class QV8Engine;
+void qt_add_sqlexceptions(QV8Engine *engine);
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QV8SQLERRORS_P_H
diff --git a/src/qml/qml/v8/qv8stringwrapper.cpp b/src/qml/qml/v8/qv8stringwrapper.cpp
new file mode 100644
index 0000000000..d4abbdc60b
--- /dev/null
+++ b/src/qml/qml/v8/qv8stringwrapper.cpp
@@ -0,0 +1,78 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qv8stringwrapper_p.h"
+#include "qjsconverter_p.h"
+#include "qjsconverter_impl_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QV8StringWrapper::QV8StringWrapper()
+{
+}
+
+QV8StringWrapper::~QV8StringWrapper()
+{
+}
+
+void QV8StringWrapper::init()
+{
+}
+
+void QV8StringWrapper::destroy()
+{
+}
+
+v8::Local<v8::String> QV8StringWrapper::toString(const QString &qstr)
+{
+ return QJSConverter::toString(qstr);
+}
+
+QString QV8StringWrapper::toString(v8::Handle<v8::String> jsstr)
+{
+ if (jsstr.IsEmpty()) {
+ return QString();
+ } else {
+ return QJSConverter::toString(jsstr);
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/v8/qv8stringwrapper_p.h b/src/qml/qml/v8/qv8stringwrapper_p.h
new file mode 100644
index 0000000000..1609720298
--- /dev/null
+++ b/src/qml/qml/v8/qv8stringwrapper_p.h
@@ -0,0 +1,78 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLV8STRINGWRAPPER_P_H
+#define QQMLV8STRINGWRAPPER_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtQml/qtqmlglobal.h>
+
+#include <QtCore/qstring.h>
+#include <private/qv8_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q_QML_EXPORT QV8StringWrapper
+{
+public:
+ QV8StringWrapper();
+ ~QV8StringWrapper();
+
+ void init();
+ void destroy();
+
+ v8::Local<v8::String> toString(const QString &);
+ QString toString(v8::Handle<v8::String>);
+};
+
+QT_END_NAMESPACE
+
+#endif // QQMLV8STRINGWRAPPER_P_H
diff --git a/src/qml/qml/v8/qv8typewrapper.cpp b/src/qml/qml/v8/qv8typewrapper.cpp
new file mode 100644
index 0000000000..dbf369e678
--- /dev/null
+++ b/src/qml/qml/v8/qv8typewrapper.cpp
@@ -0,0 +1,314 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qv8contextwrapper_p.h"
+#include "qv8engine_p.h"
+
+#include <private/qqmlengine_p.h>
+#include <private/qqmlcontext_p.h>
+
+#include <private/qjsvalue_p.h>
+#include <private/qscript_impl_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QV8TypeResource : public QV8ObjectResource
+{
+ V8_RESOURCE_TYPE(TypeType);
+
+public:
+ QV8TypeResource(QV8Engine *engine);
+ virtual ~QV8TypeResource();
+
+ QV8TypeWrapper::TypeNameMode mode;
+
+ QQmlGuard<QObject> object;
+
+ QQmlType *type;
+ QQmlTypeNameCache *typeNamespace;
+ const void *importNamespace;
+};
+
+QV8TypeResource::QV8TypeResource(QV8Engine *engine)
+: QV8ObjectResource(engine), mode(QV8TypeWrapper::IncludeEnums), type(0), typeNamespace(0), importNamespace(0)
+{
+}
+
+QV8TypeResource::~QV8TypeResource()
+{
+ if (typeNamespace) typeNamespace->release();
+}
+
+QV8TypeWrapper::QV8TypeWrapper()
+: m_engine(0)
+{
+}
+
+QV8TypeWrapper::~QV8TypeWrapper()
+{
+}
+
+void QV8TypeWrapper::destroy()
+{
+ qPersistentDispose(m_constructor);
+}
+
+void QV8TypeWrapper::init(QV8Engine *engine)
+{
+ m_engine = engine;
+ v8::Local<v8::FunctionTemplate> ft = v8::FunctionTemplate::New();
+ ft->InstanceTemplate()->SetNamedPropertyHandler(Getter, Setter);
+ ft->InstanceTemplate()->SetHasExternalResource(true);
+ m_constructor = qPersistentNew<v8::Function>(ft->GetFunction());
+}
+
+// Returns a type wrapper for type t on o. This allows access of enums, and attached properties.
+v8::Local<v8::Object> QV8TypeWrapper::newObject(QObject *o, QQmlType *t, TypeNameMode mode)
+{
+ Q_ASSERT(t);
+ // XXX NewInstance() should be optimized
+ v8::Local<v8::Object> rv = m_constructor->NewInstance();
+ QV8TypeResource *r = new QV8TypeResource(m_engine);
+ r->mode = mode; r->object = o; r->type = t;
+ rv->SetExternalResource(r);
+ return rv;
+}
+
+// Returns a type wrapper for importNamespace (of t) on o. This allows nested resolution of a type in a
+// namespace.
+v8::Local<v8::Object> QV8TypeWrapper::newObject(QObject *o, QQmlTypeNameCache *t,
+ const void *importNamespace, TypeNameMode mode)
+{
+ Q_ASSERT(t);
+ Q_ASSERT(importNamespace);
+ // XXX NewInstance() should be optimized
+ v8::Local<v8::Object> rv = m_constructor->NewInstance();
+ QV8TypeResource *r = new QV8TypeResource(m_engine);
+ t->addref();
+ r->mode = mode; r->object = o; r->typeNamespace = t; r->importNamespace = importNamespace;
+ rv->SetExternalResource(r);
+ return rv;
+}
+
+QVariant QV8TypeWrapper::toVariant(QV8ObjectResource *r)
+{
+ Q_ASSERT(r->resourceType() == QV8ObjectResource::TypeType);
+ QV8TypeResource *resource = static_cast<QV8TypeResource *>(r);
+ QV8Engine *v8engine = resource->engine;
+
+ if (resource->typeNamespace) {
+ if (QQmlMetaType::ModuleApiInstance *moduleApi = resource->typeNamespace->moduleApi(resource->importNamespace)) {
+ if (moduleApi->scriptCallback) {
+ moduleApi->scriptApi = moduleApi->scriptCallback(v8engine->engine(), v8engine->engine());
+ moduleApi->scriptCallback = 0;
+ moduleApi->qobjectCallback = 0;
+ } else if (moduleApi->qobjectCallback) {
+ moduleApi->qobjectApi = moduleApi->qobjectCallback(v8engine->engine(), v8engine->engine());
+ moduleApi->scriptCallback = 0;
+ moduleApi->qobjectCallback = 0;
+ }
+
+ if (moduleApi->qobjectApi) {
+ return QVariant::fromValue<QObject*>(moduleApi->qobjectApi);
+ }
+ }
+ }
+
+ // only QObject Module API can be converted to a variant.
+ return QVariant();
+}
+
+v8::Handle<v8::Value> QV8TypeWrapper::Getter(v8::Local<v8::String> property,
+ const v8::AccessorInfo &info)
+{
+ QV8TypeResource *resource = v8_resource_cast<QV8TypeResource>(info.This());
+
+ if (!resource)
+ return v8::Undefined();
+
+ QV8Engine *v8engine = resource->engine;
+ QObject *object = resource->object;
+
+ QHashedV8String propertystring(property);
+
+ if (resource->type) {
+ QQmlType *type = resource->type;
+
+ if (QV8Engine::startsWithUpper(property)) {
+ int value = type->enumValue(propertystring);
+ if (-1 != value)
+ return v8::Integer::New(value);
+
+ // Fall through to return empty handle
+
+ } else if (resource->object) {
+ QObject *ao = qmlAttachedPropertiesObjectById(type->attachedPropertiesId(), object);
+ if (ao)
+ return v8engine->qobjectWrapper()->getProperty(ao, propertystring,
+ QV8QObjectWrapper::IgnoreRevision);
+
+ // Fall through to return empty handle
+ }
+
+ // Fall through to return empty handle
+
+ } else if (resource->typeNamespace) {
+ Q_ASSERT(resource->importNamespace);
+ QQmlTypeNameCache::Result r = resource->typeNamespace->query(propertystring,
+ resource->importNamespace);
+
+ if (r.isValid()) {
+ if (r.type) {
+ return v8engine->typeWrapper()->newObject(object, r.type, resource->mode);
+ } else if (r.scriptIndex != -1) {
+ int index = r.scriptIndex;
+ QQmlContextData *context = v8engine->callingContext();
+ if (index < context->importedScripts.count())
+ return context->importedScripts.at(index);
+ }
+
+ return v8::Undefined();
+ } else if (QQmlMetaType::ModuleApiInstance *moduleApi = resource->typeNamespace->moduleApi(resource->importNamespace)) {
+
+ if (moduleApi->scriptCallback) {
+ moduleApi->scriptApi = moduleApi->scriptCallback(v8engine->engine(), v8engine->engine());
+ moduleApi->scriptCallback = 0;
+ moduleApi->qobjectCallback = 0;
+ } else if (moduleApi->qobjectCallback) {
+ moduleApi->qobjectApi = moduleApi->qobjectCallback(v8engine->engine(), v8engine->engine());
+ moduleApi->scriptCallback = 0;
+ moduleApi->qobjectCallback = 0;
+ }
+
+ if (moduleApi->qobjectApi) {
+ // check for enum value
+ if (QV8Engine::startsWithUpper(property)) {
+ if (resource->mode == IncludeEnums) {
+ QString name = v8engine->toString(property);
+
+ // ### Optimize
+ QByteArray enumName = name.toUtf8();
+ const QMetaObject *metaObject = moduleApi->qobjectApi->metaObject();
+ for (int ii = metaObject->enumeratorCount() - 1; ii >= 0; --ii) {
+ QMetaEnum e = metaObject->enumerator(ii);
+ bool ok;
+ int value = e.keyToValue(enumName.constData(), &ok);
+ if (ok)
+ return v8::Integer::New(value);
+ }
+ }
+ }
+
+ // check for property.
+ v8::Handle<v8::Value> rv = v8engine->qobjectWrapper()->getProperty(moduleApi->qobjectApi, propertystring, QV8QObjectWrapper::IgnoreRevision);
+ return rv;
+ } else if (!moduleApi->scriptApi.isUndefined()) {
+ // NOTE: if used in a binding, changes will not trigger re-evaluation since non-NOTIFYable.
+ QJSValuePrivate *apiprivate = QJSValuePrivate::get(moduleApi->scriptApi);
+ QScopedPointer<QJSValuePrivate> propertyValue(apiprivate->property(property).give());
+ return propertyValue->asV8Value(v8engine);
+ } else {
+ return v8::Handle<v8::Value>();
+ }
+ }
+
+ // Fall through to return empty handle
+
+ } else {
+ Q_ASSERT(!"Unreachable");
+ }
+
+ return v8::Handle<v8::Value>();
+}
+
+v8::Handle<v8::Value> QV8TypeWrapper::Setter(v8::Local<v8::String> property,
+ v8::Local<v8::Value> value,
+ const v8::AccessorInfo &info)
+{
+ QV8TypeResource *resource = v8_resource_cast<QV8TypeResource>(info.This());
+
+ if (!resource)
+ return value;
+
+ QV8Engine *v8engine = resource->engine;
+
+ QHashedV8String propertystring(property);
+
+ if (resource->type && resource->object) {
+ QQmlType *type = resource->type;
+ QObject *object = resource->object;
+ QObject *ao = qmlAttachedPropertiesObjectById(type->attachedPropertiesId(), object);
+ if (ao)
+ v8engine->qobjectWrapper()->setProperty(ao, propertystring, value,
+ QV8QObjectWrapper::IgnoreRevision);
+ } else if (resource->typeNamespace) {
+ if (QQmlMetaType::ModuleApiInstance *moduleApi = resource->typeNamespace->moduleApi(resource->importNamespace)) {
+ if (moduleApi->scriptCallback) {
+ moduleApi->scriptApi = moduleApi->scriptCallback(v8engine->engine(), v8engine->engine());
+ moduleApi->scriptCallback = 0;
+ moduleApi->qobjectCallback = 0;
+ } else if (moduleApi->qobjectCallback) {
+ moduleApi->qobjectApi = moduleApi->qobjectCallback(v8engine->engine(), v8engine->engine());
+ moduleApi->scriptCallback = 0;
+ moduleApi->qobjectCallback = 0;
+ }
+
+ if (moduleApi->qobjectApi) {
+ v8engine->qobjectWrapper()->setProperty(moduleApi->qobjectApi, propertystring, value,
+ QV8QObjectWrapper::IgnoreRevision);
+ } else if (!moduleApi->scriptApi.isUndefined()) {
+ QScopedPointer<QJSValuePrivate> setvalp(new QJSValuePrivate(v8engine, value));
+ QJSValuePrivate *apiprivate = QJSValuePrivate::get(moduleApi->scriptApi);
+ if (apiprivate->propertyFlags(property) & QJSValuePrivate::ReadOnly) {
+ QString error = QLatin1String("Cannot assign to read-only property \"") +
+ v8engine->toString(property) + QLatin1Char('\"');
+ v8::ThrowException(v8::Exception::Error(v8engine->toString(error)));
+ } else {
+ apiprivate->setProperty(property, setvalp.data());
+ }
+ }
+ }
+ }
+
+ return value;
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/v8/qv8typewrapper_p.h b/src/qml/qml/v8/qv8typewrapper_p.h
new file mode 100644
index 0000000000..8b658da6fb
--- /dev/null
+++ b/src/qml/qml/v8/qv8typewrapper_p.h
@@ -0,0 +1,94 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QV8TYPEWRAPPER_P_H
+#define QV8TYPEWRAPPER_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qglobal.h>
+#include <private/qv8_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QObject;
+class QV8Engine;
+class QQmlType;
+class QQmlTypeNameCache;
+class QV8TypeWrapper
+{
+public:
+ QV8TypeWrapper();
+ ~QV8TypeWrapper();
+
+ void init(QV8Engine *);
+ void destroy();
+
+ enum TypeNameMode { IncludeEnums, ExcludeEnums };
+ v8::Local<v8::Object> newObject(QObject *, QQmlType *, TypeNameMode = IncludeEnums);
+ v8::Local<v8::Object> newObject(QObject *, QQmlTypeNameCache *, const void *,
+ TypeNameMode = IncludeEnums);
+ QVariant toVariant(QV8ObjectResource *);
+
+private:
+ static v8::Handle<v8::Value> Getter(v8::Local<v8::String> property,
+ const v8::AccessorInfo &info);
+ static v8::Handle<v8::Value> Setter(v8::Local<v8::String> property,
+ v8::Local<v8::Value> value,
+ const v8::AccessorInfo &info);
+
+ QV8Engine *m_engine;
+ v8::Persistent<v8::Function> m_constructor;
+};
+
+QT_END_NAMESPACE
+
+#endif // QV8TYPEWRAPPER_P_H
+
diff --git a/src/qml/qml/v8/qv8valuetypewrapper.cpp b/src/qml/qml/v8/qv8valuetypewrapper.cpp
new file mode 100644
index 0000000000..54d871d5f0
--- /dev/null
+++ b/src/qml/qml/v8/qv8valuetypewrapper.cpp
@@ -0,0 +1,387 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qv8valuetypewrapper_p.h"
+#include "qv8engine_p.h"
+
+#include <private/qqmlvaluetype_p.h>
+#include <private/qqmlbinding_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QV8ValueTypeResource : public QV8ObjectResource
+{
+ V8_RESOURCE_TYPE(ValueTypeType);
+
+public:
+ enum ObjectType { Reference, Copy };
+
+ QV8ValueTypeResource(QV8Engine *engine, ObjectType objectType);
+
+ ObjectType objectType;
+ QQmlValueType *type;
+};
+
+class QV8ValueTypeReferenceResource : public QV8ValueTypeResource
+{
+public:
+ QV8ValueTypeReferenceResource(QV8Engine *engine);
+
+ QQmlGuard<QObject> object;
+ int property;
+};
+
+class QV8ValueTypeCopyResource : public QV8ValueTypeResource
+{
+public:
+ QV8ValueTypeCopyResource(QV8Engine *engine);
+
+ QVariant value;
+};
+
+QV8ValueTypeResource::QV8ValueTypeResource(QV8Engine *engine, ObjectType objectType)
+: QV8ObjectResource(engine), objectType(objectType)
+{
+}
+
+QV8ValueTypeReferenceResource::QV8ValueTypeReferenceResource(QV8Engine *engine)
+: QV8ValueTypeResource(engine, Reference)
+{
+}
+
+QV8ValueTypeCopyResource::QV8ValueTypeCopyResource(QV8Engine *engine)
+: QV8ValueTypeResource(engine, Copy)
+{
+}
+
+QV8ValueTypeWrapper::QV8ValueTypeWrapper()
+: m_engine(0)
+{
+}
+
+QV8ValueTypeWrapper::~QV8ValueTypeWrapper()
+{
+}
+
+void QV8ValueTypeWrapper::destroy()
+{
+ qPersistentDispose(m_toString);
+ qPersistentDispose(m_constructor);
+ qPersistentDispose(m_toStringSymbol);
+}
+
+static quint32 toStringHash = -1;
+
+void QV8ValueTypeWrapper::init(QV8Engine *engine)
+{
+ m_engine = engine;
+ m_toString = qPersistentNew<v8::Function>(v8::FunctionTemplate::New(ToString)->GetFunction());
+ v8::Local<v8::FunctionTemplate> ft = v8::FunctionTemplate::New();
+ ft->InstanceTemplate()->SetNamedPropertyHandler(Getter, Setter);
+ ft->InstanceTemplate()->SetHasExternalResource(true);
+ ft->InstanceTemplate()->MarkAsUseUserObjectComparison();
+ ft->InstanceTemplate()->SetAccessor(v8::String::New("toString"), ToStringGetter, 0,
+ m_toString, v8::DEFAULT,
+ v8::PropertyAttribute(v8::ReadOnly | v8::DontDelete));
+ m_constructor = qPersistentNew<v8::Function>(ft->GetFunction());
+
+ m_toStringSymbol = qPersistentNew<v8::String>(v8::String::NewSymbol("toString"));
+ m_toStringString = QHashedV8String(m_toStringSymbol);
+ toStringHash = m_toStringString.hash();
+}
+
+v8::Local<v8::Object> QV8ValueTypeWrapper::newValueType(QObject *object, int property, QQmlValueType *type)
+{
+ // XXX NewInstance() should be optimized
+ v8::Local<v8::Object> rv = m_constructor->NewInstance();
+ QV8ValueTypeReferenceResource *r = new QV8ValueTypeReferenceResource(m_engine);
+ r->type = type; r->object = object; r->property = property;
+ rv->SetExternalResource(r);
+ return rv;
+}
+
+v8::Local<v8::Object> QV8ValueTypeWrapper::newValueType(const QVariant &value, QQmlValueType *type)
+{
+ // XXX NewInstance() should be optimized
+ v8::Local<v8::Object> rv = m_constructor->NewInstance();
+ QV8ValueTypeCopyResource *r = new QV8ValueTypeCopyResource(m_engine);
+ r->type = type; r->value = value;
+ rv->SetExternalResource(r);
+ return rv;
+}
+
+QVariant QV8ValueTypeWrapper::toVariant(v8::Handle<v8::Object> obj)
+{
+ QV8ValueTypeResource *r = v8_resource_cast<QV8ValueTypeResource>(obj);
+ if (r) return toVariant(r);
+ else return QVariant();
+}
+
+QVariant QV8ValueTypeWrapper::toVariant(QV8ObjectResource *r)
+{
+ Q_ASSERT(r->resourceType() == QV8ObjectResource::ValueTypeType);
+ QV8ValueTypeResource *resource = static_cast<QV8ValueTypeResource *>(r);
+
+ if (resource->objectType == QV8ValueTypeResource::Reference) {
+ QV8ValueTypeReferenceResource *reference = static_cast<QV8ValueTypeReferenceResource *>(resource);
+
+ if (reference->object) {
+ reference->type->read(reference->object, reference->property);
+ return reference->type->value();
+ } else {
+ return QVariant();
+ }
+
+ } else {
+ Q_ASSERT(resource->objectType == QV8ValueTypeResource::Copy);
+
+ QV8ValueTypeCopyResource *copy = static_cast<QV8ValueTypeCopyResource *>(resource);
+
+ return copy->value;
+ }
+}
+
+bool QV8ValueTypeWrapper::isEqual(QV8ObjectResource *r, const QVariant& value)
+{
+ Q_ASSERT(r->resourceType() == QV8ObjectResource::ValueTypeType);
+ QV8ValueTypeResource *resource = static_cast<QV8ValueTypeResource *>(r);
+
+ if (resource->objectType == QV8ValueTypeResource::Reference) {
+ QV8ValueTypeReferenceResource *reference = static_cast<QV8ValueTypeReferenceResource *>(resource);
+ if (reference->object) {
+ reference->type->read(reference->object, reference->property);
+ return reference->type->isEqual(value);
+ } else {
+ return false;
+ }
+ } else {
+ Q_ASSERT(resource->objectType == QV8ValueTypeResource::Copy);
+ QV8ValueTypeCopyResource *copy = static_cast<QV8ValueTypeCopyResource *>(resource);
+ return (value == copy->value);
+ }
+}
+
+v8::Handle<v8::Value> QV8ValueTypeWrapper::ToStringGetter(v8::Local<v8::String> property,
+ const v8::AccessorInfo &info)
+{
+ Q_UNUSED(property);
+ return info.Data();
+}
+
+v8::Handle<v8::Value> QV8ValueTypeWrapper::ToString(const v8::Arguments &args)
+{
+ QV8ValueTypeResource *resource = v8_resource_cast<QV8ValueTypeResource>(args.This());
+ if (resource) {
+ if (resource->objectType == QV8ValueTypeResource::Reference) {
+ QV8ValueTypeReferenceResource *reference = static_cast<QV8ValueTypeReferenceResource *>(resource);
+ if (reference->object) {
+ reference->type->read(reference->object, reference->property);
+ return resource->engine->toString(resource->type->toString());
+ } else {
+ return v8::Undefined();
+ }
+ } else {
+ Q_ASSERT(resource->objectType == QV8ValueTypeResource::Copy);
+ QV8ValueTypeCopyResource *copy = static_cast<QV8ValueTypeCopyResource *>(resource);
+ QString result = copy->value.toString();
+ if (result.isEmpty() && !copy->value.canConvert(QVariant::String)) {
+ result = QString::fromLatin1("QVariant(%0)").arg(QString::fromLatin1(copy->value.typeName()));
+ }
+ return resource->engine->toString(result);
+ }
+ } else {
+ return v8::Undefined();
+ }
+}
+
+v8::Handle<v8::Value> QV8ValueTypeWrapper::Getter(v8::Local<v8::String> property,
+ const v8::AccessorInfo &info)
+{
+ QV8ValueTypeResource *r = v8_resource_cast<QV8ValueTypeResource>(info.This());
+ if (!r) return v8::Handle<v8::Value>();
+
+ QHashedV8String propertystring(property);
+
+ {
+ // Comparing the hash first actually makes a measurable difference here, at least on x86
+ quint32 hash = propertystring.hash();
+ if (hash == toStringHash &&
+ r->engine->valueTypeWrapper()->m_toStringString == propertystring) {
+ return r->engine->valueTypeWrapper()->m_toString;
+ }
+ }
+
+ QQmlPropertyData local;
+ QQmlPropertyData *result = 0;
+ {
+ QQmlData *ddata = QQmlData::get(r->type, false);
+ if (ddata && ddata->propertyCache)
+ result = ddata->propertyCache->property(propertystring);
+ else
+ result = QQmlPropertyCache::property(r->engine->engine(), r->type,
+ propertystring, local);
+ }
+
+ if (!result)
+ return v8::Handle<v8::Value>();
+
+ if (r->objectType == QV8ValueTypeResource::Reference) {
+ QV8ValueTypeReferenceResource *reference = static_cast<QV8ValueTypeReferenceResource *>(r);
+
+ if (!reference->object)
+ return v8::Handle<v8::Value>();
+
+ r->type->read(reference->object, reference->property);
+ } else {
+ Q_ASSERT(r->objectType == QV8ValueTypeResource::Copy);
+
+ QV8ValueTypeCopyResource *copy = static_cast<QV8ValueTypeCopyResource *>(r);
+
+ r->type->setValue(copy->value);
+ }
+
+#define VALUE_TYPE_LOAD(metatype, cpptype, constructor) \
+ if (result->propType == metatype) { \
+ cpptype v; \
+ void *args[] = { &v, 0 }; \
+ r->type->qt_metacall(QMetaObject::ReadProperty, result->coreIndex, args); \
+ return constructor(v); \
+ }
+
+ // These four types are the most common used by the value type wrappers
+ VALUE_TYPE_LOAD(QMetaType::QReal, qreal, v8::Number::New);
+ VALUE_TYPE_LOAD(QMetaType::Int, int, v8::Integer::New);
+ VALUE_TYPE_LOAD(QMetaType::QString, QString, r->engine->toString);
+ VALUE_TYPE_LOAD(QMetaType::Bool, bool, v8::Boolean::New);
+
+ QVariant v(result->propType, (void *)0);
+ void *args[] = { v.data(), 0 };
+ r->type->qt_metacall(QMetaObject::ReadProperty, result->coreIndex, args);
+ return r->engine->fromVariant(v);
+#undef VALUE_TYPE_ACCESSOR
+}
+
+v8::Handle<v8::Value> QV8ValueTypeWrapper::Setter(v8::Local<v8::String> property,
+ v8::Local<v8::Value> value,
+ const v8::AccessorInfo &info)
+{
+ QV8ValueTypeResource *r = v8_resource_cast<QV8ValueTypeResource>(info.This());
+ if (!r) return value;
+
+ QByteArray propName = r->engine->toString(property).toUtf8();
+ int index = r->type->metaObject()->indexOfProperty(propName.constData());
+ if (index == -1)
+ return value;
+
+ if (r->objectType == QV8ValueTypeResource::Reference) {
+ QV8ValueTypeReferenceResource *reference = static_cast<QV8ValueTypeReferenceResource *>(r);
+
+ if (!reference->object ||
+ !reference->object->metaObject()->property(reference->property).isWritable())
+ return value;
+
+ r->type->read(reference->object, reference->property);
+ QMetaProperty p = r->type->metaObject()->property(index);
+
+ QQmlBinding *newBinding = 0;
+
+ if (value->IsFunction()) {
+ QQmlContextData *context = r->engine->callingContext();
+ v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(value);
+
+ QQmlPropertyData cacheData;
+ cacheData.setFlags(QQmlPropertyData::IsWritable |
+ QQmlPropertyData::IsValueTypeVirtual);
+ cacheData.propType = reference->object->metaObject()->property(reference->property).userType();
+ cacheData.coreIndex = reference->property;
+ cacheData.valueTypeFlags = 0;
+ cacheData.valueTypeCoreIndex = index;
+ cacheData.valueTypePropType = p.userType();
+
+ v8::Local<v8::StackTrace> trace =
+ v8::StackTrace::CurrentStackTrace(1,
+ (v8::StackTrace::StackTraceOptions)(v8::StackTrace::kLineNumber |
+ v8::StackTrace::kScriptName));
+ v8::Local<v8::StackFrame> frame = trace->GetFrame(0);
+ int lineNumber = frame->GetLineNumber();
+ int columnNumber = frame->GetColumn();
+ QString url = r->engine->toString(frame->GetScriptName());
+
+ newBinding = new QQmlBinding(&function, reference->object, context);
+ newBinding->setSourceLocation(url, lineNumber, columnNumber);
+ newBinding->setTarget(reference->object, cacheData, context);
+ newBinding->setEvaluateFlags(newBinding->evaluateFlags() |
+ QQmlBinding::RequiresThisObject);
+ }
+
+ QQmlAbstractBinding *oldBinding =
+ QQmlPropertyPrivate::setBinding(reference->object, reference->property, index, newBinding);
+ if (oldBinding)
+ oldBinding->destroy();
+
+ if (!value->IsFunction()) {
+ QVariant v = r->engine->toVariant(value, -1);
+
+ if (p.isEnumType() && (QMetaType::Type)v.type() == QMetaType::Double)
+ v = v.toInt();
+
+ p.write(reference->type, v);
+
+ reference->type->write(reference->object, reference->property, 0);
+ }
+
+ } else {
+ Q_ASSERT(r->objectType == QV8ValueTypeResource::Copy);
+
+ QV8ValueTypeCopyResource *copy = static_cast<QV8ValueTypeCopyResource *>(r);
+
+ QVariant v = r->engine->toVariant(value, -1);
+
+ r->type->setValue(copy->value);
+ QMetaProperty p = r->type->metaObject()->property(index);
+ p.write(r->type, v);
+ copy->value = r->type->value();
+ }
+
+ return value;
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/v8/qv8valuetypewrapper_p.h b/src/qml/qml/v8/qv8valuetypewrapper_p.h
new file mode 100644
index 0000000000..b80d3cbbba
--- /dev/null
+++ b/src/qml/qml/v8/qv8valuetypewrapper_p.h
@@ -0,0 +1,104 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QV8VALUETYPEWRAPPER_P_H
+#define QV8VALUETYPEWRAPPER_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qglobal.h>
+#include <QtQml/qqmllist.h>
+#include <private/qv8_p.h>
+#include <private/qhashedstring_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QV8Engine;
+class QV8ObjectResource;
+class QQmlValueType;
+class QV8ValueTypeWrapper
+{
+public:
+ QV8ValueTypeWrapper();
+ ~QV8ValueTypeWrapper();
+
+ void init(QV8Engine *);
+ void destroy();
+
+ v8::Local<v8::Object> newValueType(QObject *, int, QQmlValueType *);
+ v8::Local<v8::Object> newValueType(const QVariant &, QQmlValueType *);
+
+ QVariant toVariant(v8::Handle<v8::Object>);
+ QVariant toVariant(QV8ObjectResource *);
+
+ static bool isEqual(QV8ObjectResource *, const QVariant& value);
+
+private:
+ static v8::Handle<v8::Value> ToStringGetter(v8::Local<v8::String> property,
+ const v8::AccessorInfo &info);
+ static v8::Handle<v8::Value> ToString(const v8::Arguments &args);
+ static v8::Handle<v8::Value> Getter(v8::Local<v8::String> property,
+ const v8::AccessorInfo &info);
+ static v8::Handle<v8::Value> Setter(v8::Local<v8::String> property,
+ v8::Local<v8::Value> value,
+ const v8::AccessorInfo &info);
+
+ QV8Engine *m_engine;
+ v8::Persistent<v8::Function> m_constructor;
+ v8::Persistent<v8::Function> m_toString;
+ v8::Persistent<v8::String> m_toStringSymbol;
+ QHashedV8String m_toStringString;
+};
+
+QT_END_NAMESPACE
+
+#endif // QV8VALUETYPEWRAPPER_P_H
+
+
diff --git a/src/qml/qml/v8/qv8variantresource_p.h b/src/qml/qml/v8/qv8variantresource_p.h
new file mode 100644
index 0000000000..0b6328cb54
--- /dev/null
+++ b/src/qml/qml/v8/qv8variantresource_p.h
@@ -0,0 +1,81 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QV8VARIANTRESOURCE_P_H
+#define QV8VARIANTRESOURCE_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qglobal.h>
+#include <private/qv8_p.h>
+#include <private/qv8engine_p.h>
+#include <private/qqmlengine_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QV8VariantResource : public QV8ObjectResource,
+ public QQmlEnginePrivate::ScarceResourceData
+{
+ V8_RESOURCE_TYPE(VariantType)
+
+public:
+ QV8VariantResource(QV8Engine *engine, const QVariant &data);
+
+ void addVmePropertyReference();
+ void removeVmePropertyReference();
+
+ bool m_isScarceResource;
+ int m_vmePropertyReferenceCount;
+};
+
+QT_END_NAMESPACE
+
+#endif // QV8VARIANTRESOURCE_P_H
+
diff --git a/src/qml/qml/v8/qv8variantwrapper.cpp b/src/qml/qml/v8/qv8variantwrapper.cpp
new file mode 100644
index 0000000000..4b1fc643f6
--- /dev/null
+++ b/src/qml/qml/v8/qv8variantwrapper.cpp
@@ -0,0 +1,279 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qv8variantwrapper_p.h"
+#include "qv8variantresource_p.h"
+#include "qv8engine_p.h"
+#include <private/qqmlengine_p.h>
+
+QT_BEGIN_NAMESPACE
+
+QV8VariantResource::QV8VariantResource(QV8Engine *engine, const QVariant &data)
+: QV8ObjectResource(engine), QQmlEnginePrivate::ScarceResourceData(data), m_isScarceResource(false), m_vmePropertyReferenceCount(0)
+{
+}
+
+void QV8VariantResource::addVmePropertyReference()
+{
+ if (m_isScarceResource && ++m_vmePropertyReferenceCount == 1) {
+ // remove from the ep->scarceResources list
+ // since it is now no longer eligible to be
+ // released automatically by the engine.
+ node.remove();
+ }
+}
+
+void QV8VariantResource::removeVmePropertyReference()
+{
+ if (m_isScarceResource && --m_vmePropertyReferenceCount == 0) {
+ // and add to the ep->scarceResources list
+ // since it is now eligible to be released
+ // automatically by the engine.
+ QQmlEnginePrivate::get(engine->engine())->scarceResources.insert(this);
+ }
+}
+
+QV8VariantWrapper::QV8VariantWrapper()
+: m_engine(0)
+{
+}
+
+QV8VariantWrapper::~QV8VariantWrapper()
+{
+}
+
+void QV8VariantWrapper::init(QV8Engine *engine)
+{
+ m_engine = engine;
+ m_toString = qPersistentNew<v8::Function>(v8::FunctionTemplate::New(ToString)->GetFunction());
+ m_valueOf = qPersistentNew<v8::Function>(v8::FunctionTemplate::New(ValueOf)->GetFunction());
+
+ {
+ v8::Local<v8::FunctionTemplate> ft = v8::FunctionTemplate::New();
+ ft->InstanceTemplate()->SetFallbackPropertyHandler(Getter, Setter);
+ ft->InstanceTemplate()->SetHasExternalResource(true);
+ ft->InstanceTemplate()->MarkAsUseUserObjectComparison();
+ ft->InstanceTemplate()->SetAccessor(v8::String::New("toString"), ToStringGetter, 0,
+ m_toString, v8::DEFAULT,
+ v8::PropertyAttribute(v8::ReadOnly | v8::DontDelete));
+ ft->InstanceTemplate()->SetAccessor(v8::String::New("valueOf"), ValueOfGetter, 0,
+ m_valueOf, v8::DEFAULT,
+ v8::PropertyAttribute(v8::ReadOnly | v8::DontDelete));
+ m_constructor = qPersistentNew<v8::Function>(ft->GetFunction());
+ }
+ {
+ m_preserve = qPersistentNew<v8::Function>(v8::FunctionTemplate::New(Preserve)->GetFunction());
+ m_destroy = qPersistentNew<v8::Function>(v8::FunctionTemplate::New(Destroy)->GetFunction());
+ v8::Local<v8::FunctionTemplate> ft = v8::FunctionTemplate::New();
+ ft->InstanceTemplate()->SetFallbackPropertyHandler(Getter, Setter);
+ ft->InstanceTemplate()->SetHasExternalResource(true);
+ ft->InstanceTemplate()->MarkAsUseUserObjectComparison();
+ ft->InstanceTemplate()->SetAccessor(v8::String::New("preserve"), PreserveGetter, 0,
+ m_preserve, v8::DEFAULT,
+ v8::PropertyAttribute(v8::ReadOnly | v8::DontDelete));
+ ft->InstanceTemplate()->SetAccessor(v8::String::New("destroy"), DestroyGetter, 0,
+ m_destroy, v8::DEFAULT,
+ v8::PropertyAttribute(v8::ReadOnly | v8::DontDelete));
+ ft->InstanceTemplate()->SetAccessor(v8::String::New("toString"), ToStringGetter, 0,
+ m_toString, v8::DEFAULT,
+ v8::PropertyAttribute(v8::ReadOnly | v8::DontDelete));
+ ft->InstanceTemplate()->SetAccessor(v8::String::New("valueOf"), ValueOfGetter, 0,
+ m_valueOf, v8::DEFAULT,
+ v8::PropertyAttribute(v8::ReadOnly | v8::DontDelete));
+ m_scarceConstructor = qPersistentNew<v8::Function>(ft->GetFunction());
+ }
+
+}
+
+void QV8VariantWrapper::destroy()
+{
+ qPersistentDispose(m_valueOf);
+ qPersistentDispose(m_toString);
+ qPersistentDispose(m_destroy);
+ qPersistentDispose(m_preserve);
+ qPersistentDispose(m_scarceConstructor);
+ qPersistentDispose(m_constructor);
+}
+
+v8::Local<v8::Object> QV8VariantWrapper::newVariant(const QVariant &value)
+{
+ bool scarceResource = value.type() == QVariant::Pixmap ||
+ value.type() == QVariant::Image;
+
+ // XXX NewInstance() should be optimized
+ v8::Local<v8::Object> rv;
+ QV8VariantResource *r = new QV8VariantResource(m_engine, value);
+
+ if (scarceResource) {
+ QQmlEnginePrivate *ep = QQmlEnginePrivate::get(m_engine->engine());
+ Q_ASSERT(ep->scarceResourcesRefCount);
+ rv = m_scarceConstructor->NewInstance();
+ r->m_isScarceResource = true;
+ ep->scarceResources.insert(r);
+ } else {
+ rv = m_constructor->NewInstance();
+ }
+
+ rv->SetExternalResource(r);
+ return rv;
+}
+
+bool QV8VariantWrapper::isVariant(v8::Handle<v8::Value> value)
+{
+ return value->IsObject() && v8_resource_cast<QV8VariantResource>(value->ToObject());
+}
+
+QVariant QV8VariantWrapper::toVariant(v8::Handle<v8::Object> obj)
+{
+ QV8VariantResource *r = v8_resource_cast<QV8VariantResource>(obj);
+ return r?r->data:QVariant();
+}
+
+QVariant QV8VariantWrapper::toVariant(QV8ObjectResource *r)
+{
+ Q_ASSERT(r->resourceType() == QV8ObjectResource::VariantType);
+ return static_cast<QV8VariantResource *>(r)->data;
+}
+
+QVariant &QV8VariantWrapper::variantValue(v8::Handle<v8::Value> value)
+{
+ Q_ASSERT(isVariant(value));
+ QV8VariantResource *r = v8_resource_cast<QV8VariantResource>(value->ToObject());
+ return static_cast<QV8VariantResource *>(r)->data;
+}
+
+v8::Handle<v8::Value> QV8VariantWrapper::Getter(v8::Local<v8::String> /* property */,
+ const v8::AccessorInfo & /* info */)
+{
+ return v8::Handle<v8::Value>();
+}
+
+v8::Handle<v8::Value> QV8VariantWrapper::Setter(v8::Local<v8::String> /* property */,
+ v8::Local<v8::Value> value,
+ const v8::AccessorInfo & /* info */)
+{
+ return value;
+}
+
+v8::Handle<v8::Value> QV8VariantWrapper::PreserveGetter(v8::Local<v8::String> property,
+ const v8::AccessorInfo &info)
+{
+ Q_UNUSED(property);
+ return info.Data();
+}
+
+v8::Handle<v8::Value> QV8VariantWrapper::DestroyGetter(v8::Local<v8::String> property,
+ const v8::AccessorInfo &info)
+{
+ Q_UNUSED(property);
+ return info.Data();
+}
+
+v8::Handle<v8::Value> QV8VariantWrapper::ToStringGetter(v8::Local<v8::String> property,
+ const v8::AccessorInfo &info)
+{
+ Q_UNUSED(property);
+ return info.Data();
+}
+
+v8::Handle<v8::Value> QV8VariantWrapper::ValueOfGetter(v8::Local<v8::String> property,
+ const v8::AccessorInfo &info)
+{
+ Q_UNUSED(property);
+ return info.Data();
+}
+
+v8::Handle<v8::Value> QV8VariantWrapper::Preserve(const v8::Arguments &args)
+{
+ QV8VariantResource *resource = v8_resource_cast<QV8VariantResource>(args.This());
+ if (resource) {
+ resource->node.remove();
+ }
+ return v8::Undefined();
+}
+
+v8::Handle<v8::Value> QV8VariantWrapper::Destroy(const v8::Arguments &args)
+{
+ QV8VariantResource *resource = v8_resource_cast<QV8VariantResource>(args.This());
+ if (resource) {
+ resource->data = QVariant();
+ resource->node.remove();
+ }
+ return v8::Undefined();
+}
+
+v8::Handle<v8::Value> QV8VariantWrapper::ToString(const v8::Arguments &args)
+{
+ QV8VariantResource *resource = v8_resource_cast<QV8VariantResource>(args.This());
+ if (resource) {
+ QString result = resource->data.toString();
+ if (result.isEmpty() && !resource->data.canConvert(QVariant::String))
+ result = QString::fromLatin1("QVariant(%0)").arg(QString::fromLatin1(resource->data.typeName()));
+ return resource->engine->toString(result);
+ } else {
+ return v8::Undefined();
+ }
+}
+
+v8::Handle<v8::Value> QV8VariantWrapper::ValueOf(const v8::Arguments &args)
+{
+ QV8VariantResource *resource = v8_resource_cast<QV8VariantResource>(args.This());
+ if (resource) {
+ QVariant v = resource->data;
+ switch (v.type()) {
+ case QVariant::Invalid:
+ return v8::Undefined();
+ case QVariant::String:
+ return resource->engine->toString(v.toString());
+ case QVariant::Int:
+ case QVariant::Double:
+ case QVariant::UInt:
+ return v8::Number::New(v.toDouble());
+ case QVariant::Bool:
+ return v8::Boolean::New(v.toBool());
+ default:
+ break;
+ }
+ }
+ return args.This();
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/v8/qv8variantwrapper_p.h b/src/qml/qml/v8/qv8variantwrapper_p.h
new file mode 100644
index 0000000000..877155c8ca
--- /dev/null
+++ b/src/qml/qml/v8/qv8variantwrapper_p.h
@@ -0,0 +1,110 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QV8VARIANTWRAPPER_P_H
+#define QV8VARIANTWRAPPER_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qglobal.h>
+#include <QtQml/qqmllist.h>
+#include <private/qv8_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QV8Engine;
+class QV8ObjectResource;
+class QV8VariantWrapper
+{
+public:
+ QV8VariantWrapper();
+ ~QV8VariantWrapper();
+
+ void init(QV8Engine *);
+ void destroy();
+
+ v8::Local<v8::Object> newVariant(const QVariant &);
+ bool isVariant(v8::Handle<v8::Value>);
+ static QVariant toVariant(v8::Handle<v8::Object>);
+ static QVariant toVariant(QV8ObjectResource *);
+ QVariant &variantValue(v8::Handle<v8::Value>);
+
+private:
+ static v8::Handle<v8::Value> Getter(v8::Local<v8::String> property,
+ const v8::AccessorInfo &info);
+ static v8::Handle<v8::Value> Setter(v8::Local<v8::String> property,
+ v8::Local<v8::Value> value,
+ const v8::AccessorInfo &info);
+ static v8::Handle<v8::Value> PreserveGetter(v8::Local<v8::String> property,
+ const v8::AccessorInfo &info);
+ static v8::Handle<v8::Value> DestroyGetter(v8::Local<v8::String> property,
+ const v8::AccessorInfo &info);
+ static v8::Handle<v8::Value> ToStringGetter(v8::Local<v8::String> property,
+ const v8::AccessorInfo &info);
+ static v8::Handle<v8::Value> ValueOfGetter(v8::Local<v8::String> property,
+ const v8::AccessorInfo &info);
+ static v8::Handle<v8::Value> Preserve(const v8::Arguments &args);
+ static v8::Handle<v8::Value> Destroy(const v8::Arguments &args);
+ static v8::Handle<v8::Value> ToString(const v8::Arguments &args);
+ static v8::Handle<v8::Value> ValueOf(const v8::Arguments &args);
+
+ QV8Engine *m_engine;
+ v8::Persistent<v8::Function> m_constructor;
+ v8::Persistent<v8::Function> m_scarceConstructor;
+ v8::Persistent<v8::Function> m_preserve;
+ v8::Persistent<v8::Function> m_destroy;
+ v8::Persistent<v8::Function> m_toString;
+ v8::Persistent<v8::Function> m_valueOf;
+};
+
+QT_END_NAMESPACE
+
+#endif // QV8VARIANTWRAPPER_P_H
+
diff --git a/src/qml/qml/v8/qv8worker.cpp b/src/qml/qml/v8/qv8worker.cpp
new file mode 100644
index 0000000000..6ea527166c
--- /dev/null
+++ b/src/qml/qml/v8/qv8worker.cpp
@@ -0,0 +1,392 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qv8worker_p.h"
+
+#include <private/qquicklistmodel_p.h>
+#include <private/qquicklistmodelworkeragent_p.h>
+
+QT_BEGIN_NAMESPACE
+
+// We allow the following JavaScript types to be passed between the main and
+// the secondary thread:
+// + undefined
+// + null
+// + Boolean
+// + String
+// + Function
+// + Array
+// + "Simple" Objects
+// + Number
+// + Date
+// + RegExp
+// <quint8 type><quint24 size><data>
+
+enum Type {
+ WorkerUndefined,
+ WorkerNull,
+ WorkerTrue,
+ WorkerFalse,
+ WorkerString,
+ WorkerFunction,
+ WorkerArray,
+ WorkerObject,
+ WorkerInt32,
+ WorkerUint32,
+ WorkerNumber,
+ WorkerDate,
+ WorkerRegexp,
+ WorkerListModel,
+ WorkerSequence
+};
+
+static inline quint32 valueheader(Type type, quint32 size = 0)
+{
+ return quint8(type) << 24 | (size & 0xFFFFFF);
+}
+
+static inline Type headertype(quint32 header)
+{
+ return (Type)(header >> 24);
+}
+
+static inline quint32 headersize(quint32 header)
+{
+ return header & 0xFFFFFF;
+}
+
+static inline void push(QByteArray &data, quint32 value)
+{
+ data.append((const char *)&value, sizeof(quint32));
+}
+
+static inline void push(QByteArray &data, double value)
+{
+ data.append((const char *)&value, sizeof(double));
+}
+
+static inline void push(QByteArray &data, void *ptr)
+{
+ data.append((const char *)&ptr, sizeof(void *));
+}
+
+static inline void reserve(QByteArray &data, int extra)
+{
+ data.reserve(data.size() + extra);
+}
+
+static inline quint32 popUint32(const char *&data)
+{
+ quint32 rv = *((quint32 *)data);
+ data += sizeof(quint32);
+ return rv;
+}
+
+static inline double popDouble(const char *&data)
+{
+ double rv = *((double *)data);
+ data += sizeof(double);
+ return rv;
+}
+
+static inline void *popPtr(const char *&data)
+{
+ void *rv = *((void **)data);
+ data += sizeof(void *);
+ return rv;
+}
+
+// XXX TODO: Check that worker script is exception safe in the case of
+// serialization/deserialization failures
+
+#define ALIGN(size) (((size) + 3) & ~3)
+void QV8Worker::serialize(QByteArray &data, v8::Handle<v8::Value> v, QV8Engine *engine)
+{
+ if (v.IsEmpty()) {
+ } else if (v->IsUndefined()) {
+ push(data, valueheader(WorkerUndefined));
+ } else if (v->IsNull()) {
+ push(data, valueheader(WorkerNull));
+ } else if (v->IsTrue()) {
+ push(data, valueheader(WorkerTrue));
+ } else if (v->IsFalse()) {
+ push(data, valueheader(WorkerFalse));
+ } else if (v->IsString()) {
+ v8::Handle<v8::String> string = v->ToString();
+ int length = string->Length() + 1;
+ if (length > 0xFFFFFF) {
+ push(data, valueheader(WorkerUndefined));
+ return;
+ }
+ int utf16size = ALIGN(length * sizeof(uint16_t));
+
+ reserve(data, utf16size + sizeof(quint32));
+ push(data, valueheader(WorkerString, length));
+
+ int offset = data.size();
+ data.resize(data.size() + utf16size);
+ char *buffer = data.data() + offset;
+
+ string->Write((uint16_t*)buffer);
+ } else if (v->IsFunction()) {
+ // XXX TODO: Implement passing function objects between the main and
+ // worker scripts
+ push(data, valueheader(WorkerUndefined));
+ } else if (v->IsArray()) {
+ v8::Handle<v8::Array> array = v8::Handle<v8::Array>::Cast(v);
+ uint32_t length = array->Length();
+ if (length > 0xFFFFFF) {
+ push(data, valueheader(WorkerUndefined));
+ return;
+ }
+ reserve(data, sizeof(quint32) + length * sizeof(quint32));
+ push(data, valueheader(WorkerArray, length));
+ for (uint32_t ii = 0; ii < length; ++ii)
+ serialize(data, array->Get(ii), engine);
+ } else if (v->IsInt32()) {
+ reserve(data, 2 * sizeof(quint32));
+ push(data, valueheader(WorkerInt32));
+ push(data, (quint32)v->Int32Value());
+ } else if (v->IsUint32()) {
+ reserve(data, 2 * sizeof(quint32));
+ push(data, valueheader(WorkerUint32));
+ push(data, v->Uint32Value());
+ } else if (v->IsNumber()) {
+ reserve(data, sizeof(quint32) + sizeof(double));
+ push(data, valueheader(WorkerNumber));
+ push(data, v->NumberValue());
+ } else if (v->IsDate()) {
+ reserve(data, sizeof(quint32) + sizeof(double));
+ push(data, valueheader(WorkerDate));
+ push(data, v8::Handle<v8::Date>::Cast(v)->NumberValue());
+ } else if (v->IsRegExp()) {
+ v8::Handle<v8::RegExp> regexp = v8::Handle<v8::RegExp>::Cast(v);
+ quint32 flags = regexp->GetFlags();
+ v8::Local<v8::String> source = regexp->GetSource();
+
+ int length = source->Length() + 1;
+ if (length > 0xFFFFFF) {
+ push(data, valueheader(WorkerUndefined));
+ return;
+ }
+ int utf16size = ALIGN(length * sizeof(uint16_t));
+
+ reserve(data, sizeof(quint32) + utf16size);
+ push(data, valueheader(WorkerRegexp, flags));
+ push(data, (quint32)length);
+ int offset = data.size();
+ data.resize(data.size() + utf16size);
+ char *buffer = data.data() + offset;
+
+ source->Write((uint16_t*)buffer);
+ } else if (v->IsObject() && !v->ToObject()->GetExternalResource()) {
+ v8::Handle<v8::Object> object = v->ToObject();
+ v8::Local<v8::Array> properties = engine->getOwnPropertyNames(object);
+ quint32 length = properties->Length();
+ if (length > 0xFFFFFF) {
+ push(data, valueheader(WorkerUndefined));
+ return;
+ }
+ push(data, valueheader(WorkerObject, length));
+ v8::TryCatch tc;
+ for (quint32 ii = 0; ii < length; ++ii) {
+ v8::Local<v8::String> str = properties->Get(ii)->ToString();
+ serialize(data, str, engine);
+
+ v8::Local<v8::Value> val = object->Get(str);
+ if (tc.HasCaught()) {
+ serialize(data, v8::Undefined(), engine);
+ tc.Reset();
+ } else {
+ serialize(data, val, engine);
+ }
+ }
+ } else if (engine->isQObject(v)) {
+ // XXX TODO: Generalize passing objects between the main thread and worker scripts so
+ // that others can trivially plug in their elements.
+ QQuickListModel *lm = qobject_cast<QQuickListModel *>(engine->toQObject(v));
+ if (lm && lm->agent()) {
+ QQuickListModelWorkerAgent *agent = lm->agent();
+ agent->addref();
+ push(data, valueheader(WorkerListModel));
+ push(data, (void *)agent);
+ return;
+ }
+ // No other QObject's are allowed to be sent
+ push(data, valueheader(WorkerUndefined));
+ } else {
+ // we can convert sequences, but not other types with external data.
+ if (v->IsObject()) {
+ v8::Handle<v8::Object> seqObj = v->ToObject();
+ QV8ObjectResource *r = static_cast<QV8ObjectResource *>(seqObj->GetExternalResource());
+ if (r->resourceType() == QV8ObjectResource::SequenceType) {
+ QVariant sequenceVariant = engine->sequenceWrapper()->toVariant(r);
+ if (!sequenceVariant.isNull()) {
+ // valid sequence. we generate a length (sequence length + 1 for the sequence type)
+ uint32_t seqLength = engine->sequenceWrapper()->sequenceLength(r);
+ uint32_t length = seqLength + 1;
+ if (length > 0xFFFFFF) {
+ push(data, valueheader(WorkerUndefined));
+ return;
+ }
+ reserve(data, sizeof(quint32) + length * sizeof(quint32));
+ push(data, valueheader(WorkerSequence, length));
+ serialize(data, v8::Integer::New(sequenceVariant.userType()), engine); // sequence type
+ for (uint32_t ii = 0; ii < seqLength; ++ii) {
+ serialize(data, seqObj->Get(ii), engine); // sequence elements
+ }
+
+ return;
+ }
+ }
+ }
+
+ // not a sequence.
+ push(data, valueheader(WorkerUndefined));
+ }
+}
+
+v8::Handle<v8::Value> QV8Worker::deserialize(const char *&data, QV8Engine *engine)
+{
+ quint32 header = popUint32(data);
+ Type type = headertype(header);
+
+ switch (type) {
+ case WorkerUndefined:
+ return v8::Undefined();
+ case WorkerNull:
+ return v8::Null();
+ case WorkerTrue:
+ return v8::True();
+ case WorkerFalse:
+ return v8::False();
+ case WorkerString:
+ {
+ quint32 size = headersize(header);
+ v8::Local<v8::String> string = v8::String::New((uint16_t*)data, size - 1);
+ data += ALIGN(size * sizeof(uint16_t));
+ return string;
+ }
+ case WorkerFunction:
+ Q_ASSERT(!"Unreachable");
+ break;
+ case WorkerArray:
+ {
+ quint32 size = headersize(header);
+ v8::Local<v8::Array> array = v8::Array::New(size);
+ for (quint32 ii = 0; ii < size; ++ii) {
+ array->Set(ii, deserialize(data, engine));
+ }
+ return array;
+ }
+ case WorkerObject:
+ {
+ quint32 size = headersize(header);
+ v8::Local<v8::Object> o = v8::Object::New();
+ for (quint32 ii = 0; ii < size; ++ii) {
+ v8::Handle<v8::Value> name = deserialize(data, engine);
+ v8::Handle<v8::Value> value = deserialize(data, engine);
+ o->Set(name, value);
+ }
+ return o;
+ }
+ case WorkerInt32:
+ return v8::Integer::New((qint32)popUint32(data));
+ case WorkerUint32:
+ return v8::Integer::NewFromUnsigned(popUint32(data));
+ case WorkerNumber:
+ return v8::Number::New(popDouble(data));
+ case WorkerDate:
+ return v8::Date::New(popDouble(data));
+ case WorkerRegexp:
+ {
+ quint32 flags = headersize(header);
+ quint32 length = popUint32(data);
+ v8::Local<v8::String> source = v8::String::New((uint16_t*)data, length - 1);
+ data += ALIGN(length * sizeof(uint16_t));
+ return v8::RegExp::New(source, (v8::RegExp::Flags)flags);
+ }
+ case WorkerListModel:
+ {
+ void *ptr = popPtr(data);
+ QQuickListModelWorkerAgent *agent = (QQuickListModelWorkerAgent *)ptr;
+ v8::Handle<v8::Value> rv = engine->newQObject(agent);
+ if (rv->IsObject()) {
+ QQuickListModelWorkerAgent::VariantRef ref(agent);
+ QVariant var = qVariantFromValue(ref);
+ rv->ToObject()->SetHiddenValue(v8::String::New("qml::ref"), engine->fromVariant(var));
+ }
+ agent->release();
+ agent->setV8Engine(engine);
+ return rv;
+ }
+ case WorkerSequence:
+ {
+ bool succeeded = false;
+ quint32 length = headersize(header);
+ quint32 seqLength = length - 1;
+ int sequenceType = deserialize(data, engine)->Int32Value();
+ v8::Local<v8::Array> array = v8::Array::New(seqLength);
+ for (quint32 ii = 0; ii < seqLength; ++ii)
+ array->Set(ii, deserialize(data, engine));
+ QVariant seqVariant = engine->sequenceWrapper()->toVariant(array, sequenceType, &succeeded);
+ return engine->sequenceWrapper()->fromVariant(seqVariant, &succeeded);
+ }
+ }
+ Q_ASSERT(!"Unreachable");
+ return v8::Undefined();
+}
+
+QByteArray QV8Worker::serialize(v8::Handle<v8::Value> value, QV8Engine *engine)
+{
+ QByteArray rv;
+ serialize(rv, value, engine);
+ return rv;
+}
+
+v8::Handle<v8::Value> QV8Worker::deserialize(const QByteArray &data, QV8Engine *engine)
+{
+ const char *stream = data.constData();
+ return deserialize(stream, engine);
+}
+
+QT_END_NAMESPACE
+
diff --git a/src/qml/qml/v8/qv8worker_p.h b/src/qml/qml/v8/qv8worker_p.h
new file mode 100644
index 0000000000..d398d21f60
--- /dev/null
+++ b/src/qml/qml/v8/qv8worker_p.h
@@ -0,0 +1,75 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QV8WORKER_P_H
+#define QV8WORKER_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 "qv8engine_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QV8Worker {
+public:
+ struct SavedData {
+ };
+
+ static QByteArray serialize(v8::Handle<v8::Value>, QV8Engine *);
+ static v8::Handle<v8::Value> deserialize(const QByteArray &, QV8Engine *);
+
+private:
+ static void serialize(QByteArray &, v8::Handle<v8::Value>, QV8Engine *);
+ static v8::Handle<v8::Value> deserialize(const char *&, QV8Engine *);
+};
+
+QT_END_NAMESPACE
+
+#endif // QV8WORKER_P_H
diff --git a/src/qml/qml/v8/script.pri b/src/qml/qml/v8/script.pri
new file mode 100644
index 0000000000..3439413f5e
--- /dev/null
+++ b/src/qml/qml/v8/script.pri
@@ -0,0 +1,21 @@
+SOURCES += \
+ $$PWD/qjsengine.cpp \
+ $$PWD/qjsvalue.cpp \
+ $$PWD/qjsvalueiterator.cpp \
+
+HEADERS += \
+ $$PWD/qjsengine.h \
+ $$PWD/qjsengine_p.h \
+ $$PWD/qjsvalue.h \
+ $$PWD/qjsvalue_p.h \
+ $$PWD/qjsvalueiterator.h \
+ $$PWD/qjsvalue_impl_p.h \
+ $$PWD/qjsconverter_p.h \
+ $$PWD/qjsconverter_impl_p.h \
+ $$PWD/qscriptisolate_p.h \
+ $$PWD/qscriptshareddata_p.h \
+ $$PWD/qscripttools_p.h \
+ $$PWD/qscript_impl_p.h \
+ $$PWD/qscriptoriginalglobalobject_p.h \
+ $$PWD/qjsvalueiterator_p.h \
+ $$PWD/qjsvalueiterator_impl_p.h
diff --git a/src/qml/qml/v8/v8.pri b/src/qml/qml/v8/v8.pri
new file mode 100644
index 0000000000..de492a8ce5
--- /dev/null
+++ b/src/qml/qml/v8/v8.pri
@@ -0,0 +1,45 @@
+INCLUDEPATH += $$PWD/../../../3rdparty/javascriptcore
+
+include(script.pri)
+
+HEADERS += \
+ $$PWD/qv8_p.h \
+ $$PWD/qv8debug_p.h \
+ $$PWD/qv8profiler_p.h \
+ $$PWD/qv8stringwrapper_p.h \
+ $$PWD/qv8engine_p.h \
+ $$PWD/qv8sequencewrapper_p.h \
+ $$PWD/qv8sequencewrapper_p_p.h \
+ $$PWD/qv8contextwrapper_p.h \
+ $$PWD/qv8qobjectwrapper_p.h \
+ $$PWD/qv8typewrapper_p.h \
+ $$PWD/qv8listwrapper_p.h \
+ $$PWD/qv8variantwrapper_p.h \
+ $$PWD/qv8variantresource_p.h \
+ $$PWD/qv8valuetypewrapper_p.h \
+ $$PWD/qv8include_p.h \
+ $$PWD/qv8worker_p.h \
+ $$PWD/qv8bindings_p.h \
+ $$PWD/../../../3rdparty/javascriptcore/DateMath.h \
+ $$PWD/qv8engine_impl_p.h \
+ $$PWD/qv8domerrors_p.h \
+ $$PWD/qv8sqlerrors_p.h \
+ $$PWD/qqmlbuiltinfunctions_p.h
+
+SOURCES += \
+ $$PWD/qv8stringwrapper.cpp \
+ $$PWD/qv8engine.cpp \
+ $$PWD/qv8sequencewrapper.cpp \
+ $$PWD/qv8contextwrapper.cpp \
+ $$PWD/qv8qobjectwrapper.cpp \
+ $$PWD/qv8typewrapper.cpp \
+ $$PWD/qv8listwrapper.cpp \
+ $$PWD/qv8variantwrapper.cpp \
+ $$PWD/qv8valuetypewrapper.cpp \
+ $$PWD/qv8include.cpp \
+ $$PWD/qv8worker.cpp \
+ $$PWD/qv8bindings.cpp \
+ $$PWD/../../../3rdparty/javascriptcore/DateMath.cpp \
+ $$PWD/qv8domerrors.cpp \
+ $$PWD/qv8sqlerrors.cpp \
+ $$PWD/qqmlbuiltinfunctions.cpp \ No newline at end of file
diff --git a/src/qml/qtqmlglobal.h b/src/qml/qtqmlglobal.h
new file mode 100644
index 0000000000..65277e60a9
--- /dev/null
+++ b/src/qml/qtqmlglobal.h
@@ -0,0 +1,67 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QTQMLGLOBAL_H
+#define QTQMLGLOBAL_H
+
+#include <QtCore/qglobal.h>
+
+#if defined(Q_OS_WIN)
+# if defined(QT_MAKEDLL) /* create a Qt DLL library */
+# if defined(QT_BUILD_QML_LIB)
+# define Q_QML_EXPORT Q_DECL_EXPORT
+# else
+# define Q_QML_EXPORT Q_DECL_IMPORT
+# endif
+# elif defined(QT_DLL) /* use a Qt DLL library */
+# define Q_QML_EXPORT Q_DECL_IMPORT
+# endif
+#endif
+
+#if !defined(Q_QML_EXPORT)
+# if defined(QT_SHARED)
+# define Q_QML_EXPORT Q_DECL_EXPORT
+# else
+# define Q_QML_EXPORT
+# endif
+#endif
+
+#endif // QTQMLGLOBAL_H
diff --git a/src/qml/qtqmlglobal_p.h b/src/qml/qtqmlglobal_p.h
new file mode 100644
index 0000000000..36926228c7
--- /dev/null
+++ b/src/qml/qtqmlglobal_p.h
@@ -0,0 +1,60 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QTQMLGLOBAL_P_H
+#define QTQMLGLOBAL_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 "qtqmlglobal.h"
+
+#define Q_QML_PRIVATE_EXPORT Q_QML_EXPORT
+
+#endif // QTQMLGLOBAL_P_H
diff --git a/src/qml/util/qqmlpropertymap.cpp b/src/qml/util/qqmlpropertymap.cpp
new file mode 100644
index 0000000000..5010af17c8
--- /dev/null
+++ b/src/qml/util/qqmlpropertymap.cpp
@@ -0,0 +1,309 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qqmlpropertymap.h"
+
+#include <private/qmetaobjectbuilder_p.h>
+#include <private/qqmlopenmetaobject_p.h>
+
+#include <QDebug>
+
+QT_BEGIN_NAMESPACE
+
+//QQmlPropertyMapMetaObject lets us listen for changes coming from QML
+//so we can emit the changed signal.
+class QQmlPropertyMapMetaObject : public QQmlOpenMetaObject
+{
+public:
+ QQmlPropertyMapMetaObject(QQmlPropertyMap *obj, QQmlPropertyMapPrivate *objPriv);
+
+protected:
+ virtual void propertyWritten(int index);
+ virtual void propertyCreated(int, QMetaPropertyBuilder &);
+ virtual int createProperty(const char *, const char *);
+private:
+ QQmlPropertyMap *map;
+ QQmlPropertyMapPrivate *priv;
+};
+
+class QQmlPropertyMapPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QQmlPropertyMap)
+public:
+ QQmlPropertyMapMetaObject *mo;
+ QStringList keys;
+ void emitChanged(const QString &key, const QVariant &value);
+ bool validKeyName(const QString& name);
+};
+
+bool QQmlPropertyMapPrivate::validKeyName(const QString& name)
+{
+ //The following strings shouldn't be used as property names
+ return name != QLatin1String("keys")
+ && name != QLatin1String("valueChanged")
+ && name != QLatin1String("QObject")
+ && name != QLatin1String("destroyed")
+ && name != QLatin1String("deleteLater");
+}
+
+void QQmlPropertyMapPrivate::emitChanged(const QString &key, const QVariant &value)
+{
+ Q_Q(QQmlPropertyMap);
+ emit q->valueChanged(key, value);
+}
+
+QQmlPropertyMapMetaObject::QQmlPropertyMapMetaObject(QQmlPropertyMap *obj, QQmlPropertyMapPrivate *objPriv) : QQmlOpenMetaObject(obj)
+{
+ map = obj;
+ priv = objPriv;
+}
+
+void QQmlPropertyMapMetaObject::propertyWritten(int index)
+{
+ priv->emitChanged(QString::fromUtf8(name(index)), operator[](index));
+}
+
+void QQmlPropertyMapMetaObject::propertyCreated(int, QMetaPropertyBuilder &b)
+{
+ priv->keys.append(QString::fromUtf8(b.name()));
+}
+
+int QQmlPropertyMapMetaObject::createProperty(const char *name, const char *value)
+{
+ if (!priv->validKeyName(QString::fromUtf8(name)))
+ return -1;
+ return QQmlOpenMetaObject::createProperty(name, value);
+}
+
+/*!
+ \class QQmlPropertyMap
+ \brief The QQmlPropertyMap class allows you to set key-value pairs that can be used in QML bindings.
+
+ QQmlPropertyMap provides a convenient way to expose domain data to the UI layer.
+ The following example shows how you might declare data in C++ and then
+ access it in QML.
+
+ In the C++ file:
+ \code
+ // create our data
+ QQmlPropertyMap ownerData;
+ ownerData.insert("name", QVariant(QString("John Smith")));
+ ownerData.insert("phone", QVariant(QString("555-5555")));
+
+ // expose it to the UI layer
+ QQuickView view;
+ QQmlContext *ctxt = view.rootContext();
+ ctxt->setContextProperty("owner", &ownerData);
+
+ view.setSource(QUrl::fromLocalFile("main.qml"));
+ view.show();
+ \endcode
+
+ Then, in \c main.qml:
+ \code
+ Text { text: owner.name + " " + owner.phone }
+ \endcode
+
+ The binding is dynamic - whenever a key's value is updated, anything bound to that
+ key will be updated as well.
+
+ To detect value changes made in the UI layer you can connect to the valueChanged() signal.
+ However, note that valueChanged() is \bold NOT emitted when changes are made by calling insert()
+ or clear() - it is only emitted when a value is updated from QML.
+
+ \note It is not possible to remove keys from the map; once a key has been added, you can only
+ modify or clear its associated value.
+*/
+
+/*!
+ Constructs a bindable map with parent object \a parent.
+*/
+QQmlPropertyMap::QQmlPropertyMap(QObject *parent)
+: QObject(*(new QQmlPropertyMapPrivate), parent)
+{
+ Q_D(QQmlPropertyMap);
+ d->mo = new QQmlPropertyMapMetaObject(this, d);
+}
+
+/*!
+ Destroys the bindable map.
+*/
+QQmlPropertyMap::~QQmlPropertyMap()
+{
+}
+
+/*!
+ Clears the value (if any) associated with \a key.
+*/
+void QQmlPropertyMap::clear(const QString &key)
+{
+ Q_D(QQmlPropertyMap);
+ d->mo->setValue(key.toUtf8(), QVariant());
+}
+
+/*!
+ Returns the value associated with \a key.
+
+ If no value has been set for this key (or if the value has been cleared),
+ an invalid QVariant is returned.
+*/
+QVariant QQmlPropertyMap::value(const QString &key) const
+{
+ Q_D(const QQmlPropertyMap);
+ return d->mo->value(key.toUtf8());
+}
+
+/*!
+ Sets the value associated with \a key to \a value.
+
+ If the key doesn't exist, it is automatically created.
+*/
+void QQmlPropertyMap::insert(const QString &key, const QVariant &value)
+{
+ Q_D(QQmlPropertyMap);
+
+ if (d->validKeyName(key)) {
+ d->mo->setValue(key.toUtf8(), value);
+ } else {
+ qWarning() << "Creating property with name"
+ << key
+ << "is not permitted, conflicts with internal symbols.";
+ }
+}
+
+/*!
+ Returns the list of keys.
+
+ Keys that have been cleared will still appear in this list, even though their
+ associated values are invalid QVariants.
+*/
+QStringList QQmlPropertyMap::keys() const
+{
+ Q_D(const QQmlPropertyMap);
+ return d->keys;
+}
+
+/*!
+ \overload
+
+ Same as size().
+*/
+int QQmlPropertyMap::count() const
+{
+ Q_D(const QQmlPropertyMap);
+ return d->keys.count();
+}
+
+/*!
+ Returns the number of keys in the map.
+
+ \sa isEmpty(), count()
+*/
+int QQmlPropertyMap::size() const
+{
+ Q_D(const QQmlPropertyMap);
+ return d->keys.size();
+}
+
+/*!
+ Returns true if the map contains no keys; otherwise returns
+ false.
+
+ \sa size()
+*/
+bool QQmlPropertyMap::isEmpty() const
+{
+ Q_D(const QQmlPropertyMap);
+ return d->keys.isEmpty();
+}
+
+/*!
+ Returns true if the map contains \a key.
+
+ \sa size()
+*/
+bool QQmlPropertyMap::contains(const QString &key) const
+{
+ Q_D(const QQmlPropertyMap);
+ return d->keys.contains(key);
+}
+
+/*!
+ Returns the value associated with the key \a key as a modifiable
+ reference.
+
+ If the map contains no item with key \a key, the function inserts
+ an invalid QVariant into the map with key \a key, and
+ returns a reference to it.
+
+ \sa insert(), value()
+*/
+QVariant &QQmlPropertyMap::operator[](const QString &key)
+{
+ //### optimize
+ Q_D(QQmlPropertyMap);
+ QByteArray utf8key = key.toUtf8();
+ if (!d->keys.contains(key))
+ insert(key, QVariant());//force creation -- needed below
+
+ return (*(d->mo))[utf8key];
+}
+
+/*!
+ \overload
+
+ Same as value().
+*/
+QVariant QQmlPropertyMap::operator[](const QString &key) const
+{
+ return value(key);
+}
+
+/*!
+ \fn void QQmlPropertyMap::valueChanged(const QString &key, const QVariant &value)
+ This signal is emitted whenever one of the values in the map is changed. \a key
+ is the key corresponding to the \a value that was changed.
+
+ \note valueChanged() is \bold NOT emitted when changes are made by calling insert()
+ or clear() - it is only emitted when a value is updated from QML.
+*/
+
+QT_END_NAMESPACE
diff --git a/src/qml/util/qqmlpropertymap.h b/src/qml/util/qqmlpropertymap.h
new file mode 100644
index 0000000000..53254ab672
--- /dev/null
+++ b/src/qml/util/qqmlpropertymap.h
@@ -0,0 +1,91 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLPROPERTYMAP_H
+#define QQMLPROPERTYMAP_H
+
+#include <QtQml/qtqmlglobal.h>
+
+#include <QtCore/QObject>
+#include <QtCore/QHash>
+#include <QtCore/QStringList>
+#include <QtCore/QVariant>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+
+class QQmlPropertyMapPrivate;
+class Q_QML_EXPORT QQmlPropertyMap : public QObject
+{
+ Q_OBJECT
+public:
+ QQmlPropertyMap(QObject *parent = 0);
+ virtual ~QQmlPropertyMap();
+
+ QVariant value(const QString &key) const;
+ void insert(const QString &key, const QVariant &value);
+ void clear(const QString &key);
+
+ Q_INVOKABLE QStringList keys() const;
+
+ int count() const;
+ int size() const;
+ bool isEmpty() const;
+ bool contains(const QString &key) const;
+
+ QVariant &operator[](const QString &key);
+ QVariant operator[](const QString &key) const;
+
+Q_SIGNALS:
+ void valueChanged(const QString &key, const QVariant &value);
+
+private:
+ Q_DECLARE_PRIVATE(QQmlPropertyMap)
+ Q_DISABLE_COPY(QQmlPropertyMap)
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/qml/util/util.pri b/src/qml/util/util.pri
new file mode 100644
index 0000000000..3b121ba3cb
--- /dev/null
+++ b/src/qml/util/util.pri
@@ -0,0 +1,5 @@
+SOURCES += \
+ $$PWD/qqmlpropertymap.cpp
+
+HEADERS += \
+ $$PWD/qqmlpropertymap.h