aboutsummaryrefslogtreecommitdiffstats
path: root/src/declarative
diff options
context:
space:
mode:
Diffstat (limited to 'src/declarative')
-rw-r--r--src/declarative/debugger/qdeclarativedebug.cpp46
-rw-r--r--src/declarative/debugger/qdeclarativedebugserver.cpp50
-rw-r--r--src/declarative/debugger/qdeclarativedebugserver_p.h3
-rw-r--r--src/declarative/debugger/qdeclarativedebugserverconnection_p.h1
-rw-r--r--src/declarative/debugger/qdeclarativedebugservice.cpp10
-rw-r--r--src/declarative/debugger/qdeclarativedebugservice_p.h2
-rw-r--r--src/declarative/debugger/qdeclarativedebugtrace.cpp9
-rw-r--r--src/declarative/debugger/qdeclarativedebugtrace_p.h1
-rw-r--r--src/declarative/debugger/qpacketprotocol.cpp49
-rw-r--r--src/declarative/debugger/qpacketprotocol_p.h2
-rw-r--r--src/declarative/declarative.pro4
-rw-r--r--src/declarative/graphicsitems/qdeclarativegridview.cpp4
-rw-r--r--src/declarative/graphicsitems/qdeclarativeitem.cpp48
-rw-r--r--src/declarative/graphicsitems/qdeclarativeitem_p.h11
-rw-r--r--src/declarative/graphicsitems/qdeclarativelistview.cpp15
-rw-r--r--src/declarative/graphicsitems/qdeclarativemousearea.cpp26
-rw-r--r--src/declarative/graphicsitems/qdeclarativemousearea_p.h3
-rw-r--r--src/declarative/graphicsitems/qdeclarativepathview.cpp4
-rw-r--r--src/declarative/graphicsitems/qdeclarativetextedit.cpp3
-rw-r--r--src/declarative/graphicsitems/qdeclarativetextinput.cpp2
-rw-r--r--src/declarative/graphicsitems/qdeclarativetextinput_p_p.h1
-rwxr-xr-xsrc/declarative/items/checksync.pl108
-rw-r--r--src/declarative/items/items.pri114
-rw-r--r--src/declarative/items/qsganchors.cpp1111
-rw-r--r--src/declarative/items/qsganchors_p.h201
-rw-r--r--src/declarative/items/qsganchors_p_p.h173
-rw-r--r--src/declarative/items/qsganimatedimage.cpp304
-rw-r--r--src/declarative/items/qsganimatedimage_p.h117
-rw-r--r--src/declarative/items/qsganimatedimage_p_p.h88
-rw-r--r--src/declarative/items/qsganimation.cpp442
-rw-r--r--src/declarative/items/qsganimation_p.h132
-rw-r--r--src/declarative/items/qsganimation_p_p.h97
-rw-r--r--src/declarative/items/qsgborderimage.cpp362
-rw-r--r--src/declarative/items/qsgborderimage_p.h110
-rw-r--r--src/declarative/items/qsgborderimage_p_p.h109
-rw-r--r--src/declarative/items/qsgcanvas.cpp1934
-rw-r--r--src/declarative/items/qsgcanvas.h123
-rw-r--r--src/declarative/items/qsgcanvas_p.h189
-rw-r--r--src/declarative/items/qsgcanvasitem.cpp441
-rw-r--r--src/declarative/items/qsgcanvasitem_p.h89
-rw-r--r--src/declarative/items/qsgclipnode.cpp121
-rw-r--r--src/declarative/items/qsgclipnode_p.h71
-rw-r--r--src/declarative/items/qsgcontext2d.cpp2716
-rw-r--r--src/declarative/items/qsgcontext2d_p.h409
-rw-r--r--src/declarative/items/qsgcontext2d_p_p.h227
-rw-r--r--src/declarative/items/qsgevents.cpp47
-rw-r--r--src/declarative/items/qsgevents_p_p.h142
-rw-r--r--src/declarative/items/qsgflickable.cpp1495
-rw-r--r--src/declarative/items/qsgflickable_p.h230
-rw-r--r--src/declarative/items/qsgflickable_p_p.h243
-rw-r--r--src/declarative/items/qsgflipable.cpp255
-rw-r--r--src/declarative/items/qsgflipable_p.h104
-rw-r--r--src/declarative/items/qsgfocusscope.cpp57
-rw-r--r--src/declarative/items/qsgfocusscope_p.h68
-rw-r--r--src/declarative/items/qsggridview.cpp2661
-rw-r--r--src/declarative/items/qsggridview_p.h290
-rw-r--r--src/declarative/items/qsgimage.cpp306
-rw-r--r--src/declarative/items/qsgimage_p.h104
-rw-r--r--src/declarative/items/qsgimage_p_p.h81
-rw-r--r--src/declarative/items/qsgimagebase.cpp285
-rw-r--r--src/declarative/items/qsgimagebase_p.h117
-rw-r--r--src/declarative/items/qsgimagebase_p_p.h93
-rw-r--r--src/declarative/items/qsgimplicitsizeitem.cpp93
-rw-r--r--src/declarative/items/qsgimplicitsizeitem_p.h101
-rw-r--r--src/declarative/items/qsgimplicitsizeitem_p_p.h92
-rw-r--r--src/declarative/items/qsgitem.cpp3143
-rw-r--r--src/declarative/items/qsgitem.h399
-rw-r--r--src/declarative/items/qsgitem_p.h712
-rw-r--r--src/declarative/items/qsgitemchangelistener_p.h82
-rw-r--r--src/declarative/items/qsgitemsmodule.cpp212
-rw-r--r--src/declarative/items/qsgitemsmodule_p.h65
-rw-r--r--src/declarative/items/qsglistview.cpp3064
-rw-r--r--src/declarative/items/qsglistview_p.h374
-rw-r--r--src/declarative/items/qsgloader.cpp340
-rw-r--r--src/declarative/items/qsgloader_p.h107
-rw-r--r--src/declarative/items/qsgloader_p_p.h91
-rw-r--r--src/declarative/items/qsgmousearea.cpp800
-rw-r--r--src/declarative/items/qsgmousearea_p.h219
-rw-r--r--src/declarative/items/qsgmousearea_p_p.h115
-rw-r--r--src/declarative/items/qsgninepatchnode.cpp292
-rw-r--r--src/declarative/items/qsgninepatchnode_p.h98
-rw-r--r--src/declarative/items/qsgpainteditem.cpp475
-rw-r--r--src/declarative/items/qsgpainteditem.h118
-rw-r--r--src/declarative/items/qsgpainteditem_p.h71
-rw-r--r--src/declarative/items/qsgpathview.cpp1416
-rw-r--r--src/declarative/items/qsgpathview_p.h254
-rw-r--r--src/declarative/items/qsgpathview_p_p.h193
-rw-r--r--src/declarative/items/qsgpincharea.cpp421
-rw-r--r--src/declarative/items/qsgpincharea_p.h315
-rw-r--r--src/declarative/items/qsgpincharea_p_p.h115
-rw-r--r--src/declarative/items/qsgpositioners.cpp788
-rw-r--r--src/declarative/items/qsgpositioners_p.h242
-rw-r--r--src/declarative/items/qsgpositioners_p_p.h174
-rw-r--r--src/declarative/items/qsgrectangle.cpp308
-rw-r--r--src/declarative/items/qsgrectangle_p.h189
-rw-r--r--src/declarative/items/qsgrectangle_p_p.h109
-rw-r--r--src/declarative/items/qsgrepeater.cpp294
-rw-r--r--src/declarative/items/qsgrepeater_p.h111
-rw-r--r--src/declarative/items/qsgrepeater_p_p.h83
-rw-r--r--src/declarative/items/qsgscalegrid.cpp213
-rw-r--r--src/declarative/items/qsgscalegrid_p_p.h134
-rw-r--r--src/declarative/items/qsgshadereffectitem.cpp590
-rw-r--r--src/declarative/items/qsgshadereffectitem_p.h158
-rw-r--r--src/declarative/items/qsgshadereffectmesh.cpp218
-rw-r--r--src/declarative/items/qsgshadereffectmesh_p.h102
-rw-r--r--src/declarative/items/qsgshadereffectnode.cpp322
-rw-r--r--src/declarative/items/qsgshadereffectnode_p.h148
-rw-r--r--src/declarative/items/qsgshadereffectsource.cpp818
-rw-r--r--src/declarative/items/qsgshadereffectsource_p.h246
-rw-r--r--src/declarative/items/qsgstateoperations.cpp1347
-rw-r--r--src/declarative/items/qsgstateoperations_p.h275
-rw-r--r--src/declarative/items/qsgtext.cpp1255
-rw-r--r--src/declarative/items/qsgtext_p.h214
-rw-r--r--src/declarative/items/qsgtext_p_p.h156
-rw-r--r--src/declarative/items/qsgtextedit.cpp1232
-rw-r--r--src/declarative/items/qsgtextedit_p.h303
-rw-r--r--src/declarative/items/qsgtextedit_p_p.h143
-rw-r--r--src/declarative/items/qsgtextinput.cpp1295
-rw-r--r--src/declarative/items/qsgtextinput_p.h302
-rw-r--r--src/declarative/items/qsgtextinput_p_p.h152
-rw-r--r--src/declarative/items/qsgtextnode.cpp457
-rw-r--r--src/declarative/items/qsgtextnode_p.h84
-rw-r--r--src/declarative/items/qsgtranslate.cpp297
-rw-r--r--src/declarative/items/qsgtranslate_p.h162
-rw-r--r--src/declarative/items/qsgview.cpp466
-rw-r--r--src/declarative/items/qsgview.h122
-rw-r--r--src/declarative/items/qsgvisualitemmodel.cpp1254
-rw-r--r--src/declarative/items/qsgvisualitemmodel_p.h257
-rw-r--r--src/declarative/items/syncexcludes11
-rw-r--r--src/declarative/qml/parser/qdeclarativejs.g53
-rw-r--r--src/declarative/qml/parser/qdeclarativejsast.cpp6
-rw-r--r--src/declarative/qml/parser/qdeclarativejsast_p.h12
-rw-r--r--src/declarative/qml/parser/qdeclarativejsastfwd_p.h2
-rw-r--r--src/declarative/qml/parser/qdeclarativejsastvisitor.cpp2
-rw-r--r--src/declarative/qml/parser/qdeclarativejsastvisitor_p.h4
-rw-r--r--src/declarative/qml/parser/qdeclarativejsengine_p.cpp6
-rw-r--r--src/declarative/qml/parser/qdeclarativejsengine_p.h4
-rw-r--r--src/declarative/qml/parser/qdeclarativejsglobal_p.h2
-rw-r--r--src/declarative/qml/parser/qdeclarativejsgrammar.cpp1490
-rw-r--r--src/declarative/qml/parser/qdeclarativejsgrammar_p.h14
-rw-r--r--src/declarative/qml/parser/qdeclarativejslexer.cpp8
-rw-r--r--src/declarative/qml/parser/qdeclarativejslexer_p.h2
-rw-r--r--src/declarative/qml/parser/qdeclarativejsmemorypool_p.h2
-rw-r--r--src/declarative/qml/parser/qdeclarativejsnodepool_p.h4
-rw-r--r--src/declarative/qml/parser/qdeclarativejsparser.cpp434
-rw-r--r--src/declarative/qml/parser/qdeclarativejsparser_p.h12
-rw-r--r--src/declarative/qml/qdeclarative.h142
-rw-r--r--src/declarative/qml/qdeclarativebinding.cpp19
-rw-r--r--src/declarative/qml/qdeclarativecompiledbindings.cpp2906
-rw-r--r--src/declarative/qml/qdeclarativecompiledbindings_p.h116
-rw-r--r--src/declarative/qml/qdeclarativecompileddata.cpp102
-rw-r--r--src/declarative/qml/qdeclarativecompiler.cpp534
-rw-r--r--src/declarative/qml/qdeclarativecompiler_p.h24
-rw-r--r--src/declarative/qml/qdeclarativecomponent.cpp48
-rw-r--r--src/declarative/qml/qdeclarativecomponent.h10
-rw-r--r--src/declarative/qml/qdeclarativecomponent_p.h5
-rw-r--r--src/declarative/qml/qdeclarativecontext.cpp84
-rw-r--r--src/declarative/qml/qdeclarativecontext_p.h11
-rw-r--r--src/declarative/qml/qdeclarativedirparser.cpp23
-rw-r--r--src/declarative/qml/qdeclarativedirparser_p.h16
-rw-r--r--src/declarative/qml/qdeclarativedom.cpp1835
-rw-r--r--src/declarative/qml/qdeclarativedom_p.h362
-rw-r--r--src/declarative/qml/qdeclarativedom_p_p.h157
-rw-r--r--src/declarative/qml/qdeclarativeengine.cpp145
-rw-r--r--src/declarative/qml/qdeclarativeengine.h3
-rw-r--r--src/declarative/qml/qdeclarativeengine_p.h25
-rw-r--r--src/declarative/qml/qdeclarativeexpression.cpp7
-rw-r--r--src/declarative/qml/qdeclarativeimageprovider.cpp33
-rw-r--r--src/declarative/qml/qdeclarativeimageprovider.h6
-rw-r--r--src/declarative/qml/qdeclarativeimport.cpp208
-rw-r--r--src/declarative/qml/qdeclarativeimport_p.h6
-rw-r--r--src/declarative/qml/qdeclarativeinfo.cpp12
-rw-r--r--src/declarative/qml/qdeclarativeinstruction.cpp134
-rw-r--r--src/declarative/qml/qdeclarativeinstruction_p.h479
-rw-r--r--src/declarative/qml/qdeclarativemetatype.cpp96
-rw-r--r--src/declarative/qml/qdeclarativemetatype_p.h39
-rw-r--r--src/declarative/qml/qdeclarativeobjectscriptclass.cpp27
-rw-r--r--src/declarative/qml/qdeclarativeprivate.h17
-rw-r--r--src/declarative/qml/qdeclarativeproperty.cpp3
-rw-r--r--src/declarative/qml/qdeclarativepropertycache.cpp2
-rw-r--r--src/declarative/qml/qdeclarativepropertycache_p.h21
-rw-r--r--src/declarative/qml/qdeclarativescarceresourcescriptclass.cpp219
-rw-r--r--src/declarative/qml/qdeclarativescarceresourcescriptclass_p.h163
-rw-r--r--src/declarative/qml/qdeclarativescriptparser.cpp76
-rw-r--r--src/declarative/qml/qdeclarativescriptparser_p.h4
-rw-r--r--src/declarative/qml/qdeclarativetypeloader.cpp244
-rw-r--r--src/declarative/qml/qdeclarativetypeloader_p.h62
-rw-r--r--src/declarative/qml/qdeclarativetypenamecache.cpp8
-rw-r--r--src/declarative/qml/qdeclarativetypenamecache_p.h16
-rw-r--r--src/declarative/qml/qdeclarativetypenamescriptclass.cpp38
-rw-r--r--src/declarative/qml/qdeclarativetypenamescriptclass_p.h1
-rw-r--r--src/declarative/qml/qdeclarativevme.cpp1519
-rw-r--r--src/declarative/qml/qdeclarativevme_p.h11
-rw-r--r--src/declarative/qml/qdeclarativevmemetaobject.cpp10
-rw-r--r--src/declarative/qml/qdeclarativexmlhttprequest.cpp21
-rw-r--r--src/declarative/qml/qintrusivelist.cpp173
-rw-r--r--src/declarative/qml/qintrusivelist_p.h254
-rw-r--r--src/declarative/qml/qmetaobjectbuilder.cpp57
-rw-r--r--src/declarative/qml/qmetaobjectbuilder_p.h4
-rw-r--r--src/declarative/qml/qml.pri14
-rw-r--r--src/declarative/qml/v4/qdeclarativev4bindings.cpp1530
-rw-r--r--src/declarative/qml/v4/qdeclarativev4bindings_p.h92
-rw-r--r--src/declarative/qml/v4/qdeclarativev4compiler.cpp1340
-rw-r--r--src/declarative/qml/v4/qdeclarativev4compiler_p.h104
-rw-r--r--src/declarative/qml/v4/qdeclarativev4compiler_p_p.h184
-rw-r--r--src/declarative/qml/v4/qdeclarativev4instruction.cpp559
-rw-r--r--src/declarative/qml/v4/qdeclarativev4instruction_p.h444
-rw-r--r--src/declarative/qml/v4/qdeclarativev4ir.cpp832
-rw-r--r--src/declarative/qml/v4/qdeclarativev4ir_p.h546
-rw-r--r--src/declarative/qml/v4/qdeclarativev4irbuilder.cpp1315
-rw-r--r--src/declarative/qml/v4/qdeclarativev4irbuilder_p.h242
-rw-r--r--src/declarative/qml/v4/qdeclarativev4program_p.h122
-rw-r--r--src/declarative/qml/v4/v4.pri17
-rw-r--r--src/declarative/scenegraph/coreapi/qsgdefaultrenderer.cpp538
-rw-r--r--src/declarative/scenegraph/coreapi/qsgdefaultrenderer_p.h98
-rw-r--r--src/declarative/scenegraph/coreapi/qsggeometry.cpp310
-rw-r--r--src/declarative/scenegraph/coreapi/qsggeometry.h254
-rw-r--r--src/declarative/scenegraph/coreapi/qsgmaterial.cpp535
-rw-r--r--src/declarative/scenegraph/coreapi/qsgmaterial.h144
-rw-r--r--src/declarative/scenegraph/coreapi/qsgmatrix4x4stack.cpp380
-rw-r--r--src/declarative/scenegraph/coreapi/qsgmatrix4x4stack.h104
-rw-r--r--src/declarative/scenegraph/coreapi/qsgmatrix4x4stack_p.h73
-rw-r--r--src/declarative/scenegraph/coreapi/qsgnode.cpp1187
-rw-r--r--src/declarative/scenegraph/coreapi/qsgnode.h359
-rw-r--r--src/declarative/scenegraph/coreapi/qsgnodeupdater.cpp243
-rw-r--r--src/declarative/scenegraph/coreapi/qsgnodeupdater_p.h87
-rw-r--r--src/declarative/scenegraph/coreapi/qsgrenderer.cpp544
-rw-r--r--src/declarative/scenegraph/coreapi/qsgrenderer_p.h219
-rw-r--r--src/declarative/scenegraph/qsgadaptationlayer.cpp42
-rw-r--r--src/declarative/scenegraph/qsgadaptationlayer_p.h124
-rw-r--r--src/declarative/scenegraph/qsgcontext.cpp449
-rw-r--r--src/declarative/scenegraph/qsgcontext_p.h126
-rw-r--r--src/declarative/scenegraph/qsgcontextplugin.cpp104
-rw-r--r--src/declarative/scenegraph/qsgcontextplugin_p.h81
-rw-r--r--src/declarative/scenegraph/qsgdefaultglyphnode.cpp95
-rw-r--r--src/declarative/scenegraph/qsgdefaultglyphnode_p.cpp313
-rw-r--r--src/declarative/scenegraph/qsgdefaultglyphnode_p.h83
-rw-r--r--src/declarative/scenegraph/qsgdefaultglyphnode_p_p.h95
-rw-r--r--src/declarative/scenegraph/qsgdefaultimagenode.cpp288
-rw-r--r--src/declarative/scenegraph/qsgdefaultimagenode_p.h90
-rw-r--r--src/declarative/scenegraph/qsgdefaultrectanglenode.cpp548
-rw-r--r--src/declarative/scenegraph/qsgdefaultrectanglenode_p.h108
-rw-r--r--src/declarative/scenegraph/qsgdistancefieldglyphcache.cpp952
-rw-r--r--src/declarative/scenegraph/qsgdistancefieldglyphcache_p.h160
-rw-r--r--src/declarative/scenegraph/qsgdistancefieldglyphnode.cpp223
-rw-r--r--src/declarative/scenegraph/qsgdistancefieldglyphnode_p.cpp667
-rw-r--r--src/declarative/scenegraph/qsgdistancefieldglyphnode_p.h93
-rw-r--r--src/declarative/scenegraph/qsgdistancefieldglyphnode_p_p.h128
-rw-r--r--src/declarative/scenegraph/qsgflashnode.cpp62
-rw-r--r--src/declarative/scenegraph/qsgflashnode_p.h69
-rw-r--r--src/declarative/scenegraph/scenegraph.pri80
-rw-r--r--src/declarative/scenegraph/util/qsgareaallocator.cpp290
-rw-r--r--src/declarative/scenegraph/util/qsgareaallocator_p.h73
-rw-r--r--src/declarative/scenegraph/util/qsgengine.cpp244
-rw-r--r--src/declarative/scenegraph/util/qsgengine.h100
-rw-r--r--src/declarative/scenegraph/util/qsgflatcolormaterial.cpp192
-rw-r--r--src/declarative/scenegraph/util/qsgflatcolormaterial.h71
-rw-r--r--src/declarative/scenegraph/util/qsgpainternode.cpp418
-rw-r--r--src/declarative/scenegraph/util/qsgpainternode_p.h149
-rw-r--r--src/declarative/scenegraph/util/qsgsimplerectnode.cpp132
-rw-r--r--src/declarative/scenegraph/util/qsgsimplerectnode.h77
-rw-r--r--src/declarative/scenegraph/util/qsgsimpletexturenode.cpp152
-rw-r--r--src/declarative/scenegraph/util/qsgsimpletexturenode.h82
-rw-r--r--src/declarative/scenegraph/util/qsgtexture.cpp415
-rw-r--r--src/declarative/scenegraph/util/qsgtexture.h132
-rw-r--r--src/declarative/scenegraph/util/qsgtexture_p.h113
-rw-r--r--src/declarative/scenegraph/util/qsgtexturematerial.cpp410
-rw-r--r--src/declarative/scenegraph/util/qsgtexturematerial.h102
-rw-r--r--src/declarative/scenegraph/util/qsgtexturematerial_p.h73
-rw-r--r--src/declarative/scenegraph/util/qsgtextureprovider.cpp65
-rw-r--r--src/declarative/scenegraph/util/qsgtextureprovider_p.h70
-rw-r--r--src/declarative/scenegraph/util/qsgvertexcolormaterial.cpp171
-rw-r--r--src/declarative/scenegraph/util/qsgvertexcolormaterial_p.h69
-rw-r--r--src/declarative/util/qdeclarativepixmapcache.cpp273
-rw-r--r--src/declarative/util/qdeclarativepixmapcache_p.h5
-rw-r--r--src/declarative/util/qdeclarativeview.h4
276 files changed, 71234 insertions, 8106 deletions
diff --git a/src/declarative/debugger/qdeclarativedebug.cpp b/src/declarative/debugger/qdeclarativedebug.cpp
index 2b6df38af6..32c2b47439 100644
--- a/src/declarative/debugger/qdeclarativedebug.cpp
+++ b/src/declarative/debugger/qdeclarativedebug.cpp
@@ -84,6 +84,7 @@ public:
static void remove(QDeclarativeEngineDebug *, QDeclarativeDebugRootContextQuery *);
static void remove(QDeclarativeEngineDebug *, QDeclarativeDebugObjectQuery *);
static void remove(QDeclarativeEngineDebug *, QDeclarativeDebugExpressionQuery *);
+ static void remove(QDeclarativeEngineDebug *, QDeclarativeDebugWatch *);
QHash<int, QDeclarativeDebugEnginesQuery *> enginesQuery;
QHash<int, QDeclarativeDebugRootContextQuery *> rootContextQuery;
@@ -120,6 +121,41 @@ QDeclarativeEngineDebugPrivate::~QDeclarativeEngineDebugPrivate()
{
if (client)
client->priv = 0;
+ delete client;
+
+ QHash<int, QDeclarativeDebugEnginesQuery*>::iterator enginesIter = enginesQuery.begin();
+ for (; enginesIter != enginesQuery.end(); ++enginesIter) {
+ enginesIter.value()->m_client = 0;
+ if (enginesIter.value()->state() == QDeclarativeDebugQuery::Waiting)
+ enginesIter.value()->setState(QDeclarativeDebugQuery::Error);
+ }
+
+ QHash<int, QDeclarativeDebugRootContextQuery*>::iterator rootContextIter = rootContextQuery.begin();
+ for (; rootContextIter != rootContextQuery.end(); ++rootContextIter) {
+ rootContextIter.value()->m_client = 0;
+ if (rootContextIter.value()->state() == QDeclarativeDebugQuery::Waiting)
+ rootContextIter.value()->setState(QDeclarativeDebugQuery::Error);
+ }
+
+ QHash<int, QDeclarativeDebugObjectQuery*>::iterator objectIter = objectQuery.begin();
+ for (; objectIter != objectQuery.end(); ++objectIter) {
+ objectIter.value()->m_client = 0;
+ if (objectIter.value()->state() == QDeclarativeDebugQuery::Waiting)
+ objectIter.value()->setState(QDeclarativeDebugQuery::Error);
+ }
+
+ QHash<int, QDeclarativeDebugExpressionQuery*>::iterator exprIter = expressionQuery.begin();
+ for (; exprIter != expressionQuery.end(); ++exprIter) {
+ exprIter.value()->m_client = 0;
+ if (exprIter.value()->state() == QDeclarativeDebugQuery::Waiting)
+ exprIter.value()->setState(QDeclarativeDebugQuery::Error);
+ }
+
+ QHash<int, QDeclarativeDebugWatch*>::iterator watchIter = watched.begin();
+ for (; watchIter != watched.end(); ++watchIter) {
+ watchIter.value()->m_client = 0;
+ watchIter.value()->setState(QDeclarativeDebugWatch::Dead);
+ }
}
int QDeclarativeEngineDebugPrivate::getId()
@@ -160,6 +196,14 @@ void QDeclarativeEngineDebugPrivate::remove(QDeclarativeEngineDebug *c, QDeclara
}
}
+void QDeclarativeEngineDebugPrivate::remove(QDeclarativeEngineDebug *c, QDeclarativeDebugWatch *w)
+{
+ if (c && w) {
+ QDeclarativeEngineDebugPrivate *p = (QDeclarativeEngineDebugPrivate *)QObjectPrivate::get(c);
+ p->watched.remove(w->m_queryId);
+ }
+}
+
void QDeclarativeEngineDebugPrivate::decode(QDataStream &ds, QDeclarativeDebugObjectReference &o,
bool simple)
{
@@ -647,6 +691,8 @@ QDeclarativeDebugWatch::QDeclarativeDebugWatch(QObject *parent)
QDeclarativeDebugWatch::~QDeclarativeDebugWatch()
{
+ if (m_client && m_queryId != -1)
+ QDeclarativeEngineDebugPrivate::remove(m_client, this);
}
int QDeclarativeDebugWatch::queryId() const
diff --git a/src/declarative/debugger/qdeclarativedebugserver.cpp b/src/declarative/debugger/qdeclarativedebugserver.cpp
index 6729314b7b..a69e01a6fe 100644
--- a/src/declarative/debugger/qdeclarativedebugserver.cpp
+++ b/src/declarative/debugger/qdeclarativedebugserver.cpp
@@ -90,7 +90,11 @@ public:
QHash<QString, QDeclarativeDebugService *> plugins;
QStringList clientPlugins;
bool gotHello;
+ QString waitingForMsgFromService;
+private:
+ // private slot
+ void _q_deliverMessage(const QString &serviceName, const QByteArray &message);
static QDeclarativeDebugServerConnection *loadConnectionPlugin(const QString &pluginName);
};
@@ -235,7 +239,6 @@ void QDeclarativeDebugServer::receiveMessage(const QByteArray &message)
QDataStream in(message);
if (!d->gotHello) {
-
QString name;
int op;
in >> name >> op;
@@ -307,17 +310,33 @@ void QDeclarativeDebugServer::receiveMessage(const QByteArray &message)
QByteArray message;
in >> message;
- QHash<QString, QDeclarativeDebugService *>::Iterator iter =
- d->plugins.find(name);
- if (iter == d->plugins.end()) {
- qWarning() << "QDeclarativeDebugServer: Message received for missing plugin" << name;
+ if (d->waitingForMsgFromService == name) {
+ // deliver directly so that it is delivered before waitForMessage is returning.
+ d->_q_deliverMessage(name, message);
+ d->waitingForMsgFromService.clear();
} else {
- (*iter)->messageReceived(message);
+ // deliver message in next event loop run.
+ // Fixes the case that the service does start it's own event loop ...,
+ // but the networking code doesn't deliver any new messages because readyRead
+ // hasn't returned.
+ QMetaObject::invokeMethod(this, "_q_deliverMessage", Qt::QueuedConnection,
+ Q_ARG(QString, name),
+ Q_ARG(QByteArray, message));
}
}
}
}
+void QDeclarativeDebugServerPrivate::_q_deliverMessage(const QString &serviceName, const QByteArray &message)
+{
+ QHash<QString, QDeclarativeDebugService *>::Iterator iter = plugins.find(serviceName);
+ if (iter == plugins.end()) {
+ qWarning() << "QDeclarativeDebugServer: Message received for missing plugin" << serviceName;
+ } else {
+ (*iter)->messageReceived(message);
+ }
+}
+
QList<QDeclarativeDebugService*> QDeclarativeDebugServer::services() const
{
const Q_D(QDeclarativeDebugServer);
@@ -375,4 +394,23 @@ void QDeclarativeDebugServer::sendMessage(QDeclarativeDebugService *service,
d->connection->send(msg);
}
+bool QDeclarativeDebugServer::waitForMessage(QDeclarativeDebugService *service)
+{
+ Q_D(QDeclarativeDebugServer);
+
+ if (!service
+ || !d->plugins.contains(service->name())
+ || !d->waitingForMsgFromService.isEmpty())
+ return false;
+
+ d->waitingForMsgFromService = service->name();
+
+ do {
+ d->connection->waitForMessage();
+ } while (!d->waitingForMsgFromService.isEmpty());
+ return true;
+}
+
QT_END_NAMESPACE
+
+#include "moc_qdeclarativedebugserver_p.cpp"
diff --git a/src/declarative/debugger/qdeclarativedebugserver_p.h b/src/declarative/debugger/qdeclarativedebugserver_p.h
index 351c4d018d..53c1077c7b 100644
--- a/src/declarative/debugger/qdeclarativedebugserver_p.h
+++ b/src/declarative/debugger/qdeclarativedebugserver_p.h
@@ -75,10 +75,13 @@ public:
void sendMessage(QDeclarativeDebugService *service, const QByteArray &message);
void receiveMessage(const QByteArray &message);
+ bool waitForMessage(QDeclarativeDebugService *service);
+
private:
friend class QDeclarativeDebugService;
friend class QDeclarativeDebugServicePrivate;
QDeclarativeDebugServer();
+ Q_PRIVATE_SLOT(d_func(), void _q_deliverMessage(QString, QByteArray))
};
QT_END_NAMESPACE
diff --git a/src/declarative/debugger/qdeclarativedebugserverconnection_p.h b/src/declarative/debugger/qdeclarativedebugserverconnection_p.h
index df99022485..d7f0de62fa 100644
--- a/src/declarative/debugger/qdeclarativedebugserverconnection_p.h
+++ b/src/declarative/debugger/qdeclarativedebugserverconnection_p.h
@@ -62,6 +62,7 @@ public:
virtual bool isConnected() const = 0;
virtual void send(const QByteArray &message) = 0;
virtual void disconnect() = 0;
+ virtual bool waitForMessage() = 0;
};
Q_DECLARE_INTERFACE(QDeclarativeDebugServerConnection, "com.trolltech.Qt.QDeclarativeDebugServerConnection/1.0")
diff --git a/src/declarative/debugger/qdeclarativedebugservice.cpp b/src/declarative/debugger/qdeclarativedebugservice.cpp
index f8c238c348..969ab35ce8 100644
--- a/src/declarative/debugger/qdeclarativedebugservice.cpp
+++ b/src/declarative/debugger/qdeclarativedebugservice.cpp
@@ -209,6 +209,16 @@ void QDeclarativeDebugService::sendMessage(const QByteArray &message)
d->server->sendMessage(this, message);
}
+bool QDeclarativeDebugService::waitForMessage()
+{
+ Q_D(QDeclarativeDebugService);
+
+ if (status() != Enabled)
+ return false;
+
+ return d->server->waitForMessage(this);
+}
+
void QDeclarativeDebugService::statusChanged(Status)
{
}
diff --git a/src/declarative/debugger/qdeclarativedebugservice_p.h b/src/declarative/debugger/qdeclarativedebugservice_p.h
index 5a1645ecc9..4f1f1a6bd8 100644
--- a/src/declarative/debugger/qdeclarativedebugservice_p.h
+++ b/src/declarative/debugger/qdeclarativedebugservice_p.h
@@ -69,6 +69,7 @@ public:
Status status() const;
void sendMessage(const QByteArray &);
+ bool waitForMessage();
static int idForObject(QObject *);
static QObject *objectForId(int);
@@ -84,6 +85,7 @@ protected:
private:
friend class QDeclarativeDebugServer;
+ friend class QDeclarativeDebugServerPrivate;
};
QT_END_NAMESPACE
diff --git a/src/declarative/debugger/qdeclarativedebugtrace.cpp b/src/declarative/debugger/qdeclarativedebugtrace.cpp
index 738be9d0b2..2772d38058 100644
--- a/src/declarative/debugger/qdeclarativedebugtrace.cpp
+++ b/src/declarative/debugger/qdeclarativedebugtrace.cpp
@@ -65,9 +65,14 @@ QByteArray QDeclarativeDebugData::toByteArray() const
QDeclarativeDebugTrace::QDeclarativeDebugTrace()
: QDeclarativeDebugService(QLatin1String("CanvasFrameRate")),
- m_enabled(false), m_deferredSend(true)
+ m_enabled(false), m_deferredSend(true), m_messageReceived(false)
{
m_timer.start();
+ if (status() == Enabled) {
+ // wait for first message indicating whether to trace or not
+ while (!m_messageReceived)
+ waitForMessage();
+ }
}
void QDeclarativeDebugTrace::addEvent(EventType t)
@@ -213,6 +218,8 @@ void QDeclarativeDebugTrace::messageReceived(const QByteArray &message)
stream >> m_enabled;
+ m_messageReceived = true;
+
if (!m_enabled)
sendMessages();
}
diff --git a/src/declarative/debugger/qdeclarativedebugtrace_p.h b/src/declarative/debugger/qdeclarativedebugtrace_p.h
index e97063e81b..30aa7723aa 100644
--- a/src/declarative/debugger/qdeclarativedebugtrace_p.h
+++ b/src/declarative/debugger/qdeclarativedebugtrace_p.h
@@ -120,6 +120,7 @@ private:
QPerformanceTimer m_timer;
bool m_enabled;
bool m_deferredSend;
+ bool m_messageReceived;
QList<QDeclarativeDebugData> m_data;
};
diff --git a/src/declarative/debugger/qpacketprotocol.cpp b/src/declarative/debugger/qpacketprotocol.cpp
index 33bc588e55..c24df6118d 100644
--- a/src/declarative/debugger/qpacketprotocol.cpp
+++ b/src/declarative/debugger/qpacketprotocol.cpp
@@ -42,6 +42,7 @@
#include "private/qpacketprotocol_p.h"
#include <QBuffer>
+#include <QElapsedTimer>
QT_BEGIN_NAMESPACE
@@ -114,7 +115,7 @@ Q_OBJECT
public:
QPacketProtocolPrivate(QPacketProtocol * parent, QIODevice * _dev)
: QObject(parent), inProgressSize(-1), maxPacketSize(MAX_PACKET_SIZE),
- dev(_dev)
+ waitingForPacket(false), dev(_dev)
{
Q_ASSERT(4 == sizeof(qint32));
@@ -125,7 +126,7 @@ public:
QObject::connect(this, SIGNAL(invalidPacket()),
parent, SIGNAL(invalidPacket()));
QObject::connect(dev, SIGNAL(readyRead()),
- this, SLOT(readyToRead()), Qt::QueuedConnection);
+ this, SLOT(readyToRead()));
QObject::connect(dev, SIGNAL(aboutToClose()),
this, SLOT(aboutToClose()));
QObject::connect(dev, SIGNAL(bytesWritten(qint64)),
@@ -200,6 +201,7 @@ public Q_SLOTS:
inProgress.clear();
emit readyRead();
+ waitingForPacket = false;
// Need to get trailing data
readyToRead();
@@ -213,6 +215,7 @@ public:
QByteArray inProgress;
qint32 inProgressSize;
qint32 maxPacketSize;
+ bool waitingForPacket;
QIODevice * dev;
};
@@ -324,6 +327,48 @@ QPacket QPacketProtocol::read()
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.
*/
diff --git a/src/declarative/debugger/qpacketprotocol_p.h b/src/declarative/debugger/qpacketprotocol_p.h
index 3cd9229e83..df3b170d17 100644
--- a/src/declarative/debugger/qpacketprotocol_p.h
+++ b/src/declarative/debugger/qpacketprotocol_p.h
@@ -75,6 +75,8 @@ public:
qint64 packetsAvailable() const;
QPacket read();
+ bool waitForReadyRead(int msecs = 3000);
+
void clear();
QIODevice * device();
diff --git a/src/declarative/declarative.pro b/src/declarative/declarative.pro
index 8c296ab034..adf1408c58 100644
--- a/src/declarative/declarative.pro
+++ b/src/declarative/declarative.pro
@@ -6,7 +6,7 @@ QPRO_PWD = $$PWD
CONFIG += module
MODULE_PRI += ../../modules/qt_declarative.pri
-QT = core-private gui-private script-private network
+QT = core-private gui-private script-private network script opengl-private
contains(QT_CONFIG, svg): QT += svg
DEFINES += QT_BUILD_DECLARATIVE_LIB QT_NO_URL_CAST_FROM_STRING
win32-msvc*|win32-icc:QMAKE_LFLAGS += /BASE:0x66000000
@@ -31,6 +31,8 @@ include(util/util.pri)
include(graphicsitems/graphicsitems.pri)
include(qml/qml.pri)
include(debugger/debugger.pri)
+include(scenegraph/scenegraph.pri)
+include(items/items.pri)
symbian: {
TARGET.UID3=0x2001E623
diff --git a/src/declarative/graphicsitems/qdeclarativegridview.cpp b/src/declarative/graphicsitems/qdeclarativegridview.cpp
index c4b2c2ebe0..aee91e1135 100644
--- a/src/declarative/graphicsitems/qdeclarativegridview.cpp
+++ b/src/declarative/graphicsitems/qdeclarativegridview.cpp
@@ -818,7 +818,9 @@ void QDeclarativeGridViewPrivate::createHighlight()
if (highlight) {
if (trackedItem == highlight)
trackedItem = 0;
- delete highlight->item;
+ if (highlight->item->scene())
+ highlight->item->scene()->removeItem(highlight->item);
+ highlight->item->deleteLater();
delete highlight;
highlight = 0;
delete highlightXAnimator;
diff --git a/src/declarative/graphicsitems/qdeclarativeitem.cpp b/src/declarative/graphicsitems/qdeclarativeitem.cpp
index fed3587db8..15cd728561 100644
--- a/src/declarative/graphicsitems/qdeclarativeitem.cpp
+++ b/src/declarative/graphicsitems/qdeclarativeitem.cpp
@@ -449,6 +449,12 @@ void QDeclarativeItemKeyFilter::componentComplete()
a chain of items with the same KeyNavigation handler. If multiple items in a row are not enabled
or visible, they will also be skipped.
+ KeyNavigation will implicitly set the other direction to return focus to this item. So if you set
+ \l left to another item, \l right will be set on that item's KeyNavigation to set focus back to this
+ item. However, if that item's KeyNavigation has had right explicitly set then no change will occur.
+ This means that the above example could have been written, with the same behaviour, without specifing
+ KeyNavigation.right or KeyNavigation.down for any of the items.
+
\sa {Keys}{Keys attached property}
*/
@@ -498,6 +504,13 @@ void QDeclarativeKeyNavigationAttached::setLeft(QDeclarativeItem *i)
if (d->left == i)
return;
d->left = i;
+ d->leftSet = true;
+ QDeclarativeKeyNavigationAttached* other =
+ qobject_cast<QDeclarativeKeyNavigationAttached*>(qmlAttachedPropertiesObject<QDeclarativeKeyNavigationAttached>(i));
+ if(other && !other->d_func()->rightSet){
+ other->d_func()->right = qobject_cast<QDeclarativeItem*>(parent());
+ emit other->rightChanged();
+ }
emit leftChanged();
}
@@ -513,6 +526,13 @@ void QDeclarativeKeyNavigationAttached::setRight(QDeclarativeItem *i)
if (d->right == i)
return;
d->right = i;
+ d->rightSet = true;
+ QDeclarativeKeyNavigationAttached* other =
+ qobject_cast<QDeclarativeKeyNavigationAttached*>(qmlAttachedPropertiesObject<QDeclarativeKeyNavigationAttached>(i));
+ if(other && !other->d_func()->leftSet){
+ other->d_func()->left = qobject_cast<QDeclarativeItem*>(parent());
+ emit other->leftChanged();
+ }
emit rightChanged();
}
@@ -528,6 +548,13 @@ void QDeclarativeKeyNavigationAttached::setUp(QDeclarativeItem *i)
if (d->up == i)
return;
d->up = i;
+ d->upSet = true;
+ QDeclarativeKeyNavigationAttached* other =
+ qobject_cast<QDeclarativeKeyNavigationAttached*>(qmlAttachedPropertiesObject<QDeclarativeKeyNavigationAttached>(i));
+ if(other && !other->d_func()->downSet){
+ other->d_func()->down = qobject_cast<QDeclarativeItem*>(parent());
+ emit other->downChanged();
+ }
emit upChanged();
}
@@ -543,6 +570,13 @@ void QDeclarativeKeyNavigationAttached::setDown(QDeclarativeItem *i)
if (d->down == i)
return;
d->down = i;
+ d->downSet = true;
+ QDeclarativeKeyNavigationAttached* other =
+ qobject_cast<QDeclarativeKeyNavigationAttached*>(qmlAttachedPropertiesObject<QDeclarativeKeyNavigationAttached>(i));
+ if(other && !other->d_func()->upSet){
+ other->d_func()->up = qobject_cast<QDeclarativeItem*>(parent());
+ emit other->upChanged();
+ }
emit downChanged();
}
@@ -558,6 +592,13 @@ void QDeclarativeKeyNavigationAttached::setTab(QDeclarativeItem *i)
if (d->tab == i)
return;
d->tab = i;
+ d->tabSet = true;
+ QDeclarativeKeyNavigationAttached* other =
+ qobject_cast<QDeclarativeKeyNavigationAttached*>(qmlAttachedPropertiesObject<QDeclarativeKeyNavigationAttached>(i));
+ if(other && !other->d_func()->backtabSet){
+ other->d_func()->backtab = qobject_cast<QDeclarativeItem*>(parent());
+ emit other->backtabChanged();
+ }
emit tabChanged();
}
@@ -573,6 +614,13 @@ void QDeclarativeKeyNavigationAttached::setBacktab(QDeclarativeItem *i)
if (d->backtab == i)
return;
d->backtab = i;
+ d->backtabSet = true;
+ QDeclarativeKeyNavigationAttached* other =
+ qobject_cast<QDeclarativeKeyNavigationAttached*>(qmlAttachedPropertiesObject<QDeclarativeKeyNavigationAttached>(i));
+ if(other && !other->d_func()->tabSet){
+ other->d_func()->tab = qobject_cast<QDeclarativeItem*>(parent());
+ emit other->tabChanged();
+ }
emit backtabChanged();
}
diff --git a/src/declarative/graphicsitems/qdeclarativeitem_p.h b/src/declarative/graphicsitems/qdeclarativeitem_p.h
index 517259c9cc..80131d137a 100644
--- a/src/declarative/graphicsitems/qdeclarativeitem_p.h
+++ b/src/declarative/graphicsitems/qdeclarativeitem_p.h
@@ -382,7 +382,10 @@ class QDeclarativeKeyNavigationAttachedPrivate : public QObjectPrivate
{
public:
QDeclarativeKeyNavigationAttachedPrivate()
- : QObjectPrivate(), left(0), right(0), up(0), down(0), tab(0), backtab(0) {}
+ : QObjectPrivate(),
+ left(0), right(0), up(0), down(0), tab(0), backtab(0),
+ leftSet(false), rightSet(false), upSet(false), downSet(false),
+ tabSet(false), backtabSet(false) {}
QDeclarativeItem *left;
QDeclarativeItem *right;
@@ -390,6 +393,12 @@ public:
QDeclarativeItem *down;
QDeclarativeItem *tab;
QDeclarativeItem *backtab;
+ bool leftSet : 1;
+ bool rightSet : 1;
+ bool upSet : 1;
+ bool downSet : 1;
+ bool tabSet : 1;
+ bool backtabSet : 1;
};
class QDeclarativeKeyNavigationAttached : public QObject, public QDeclarativeItemKeyFilter
diff --git a/src/declarative/graphicsitems/qdeclarativelistview.cpp b/src/declarative/graphicsitems/qdeclarativelistview.cpp
index 8d2fd93e2b..225b031530 100644
--- a/src/declarative/graphicsitems/qdeclarativelistview.cpp
+++ b/src/declarative/graphicsitems/qdeclarativelistview.cpp
@@ -733,6 +733,7 @@ void QDeclarativeListViewPrivate::refill(qreal from, qreal to, bool doBuffer)
if (doBuffer && (bufferMode & BufferBefore))
fillFrom = bufferFrom;
+ bool haveValidItems = false;
int modelIndex = visibleIndex;
qreal itemEnd = visiblePos-1;
if (!visibleItems.isEmpty()) {
@@ -741,11 +742,13 @@ void QDeclarativeListViewPrivate::refill(qreal from, qreal to, bool doBuffer)
int i = visibleItems.count() - 1;
while (i > 0 && visibleItems.at(i)->index == -1)
--i;
- if (visibleItems.at(i)->index != -1)
+ if (visibleItems.at(i)->index != -1) {
+ haveValidItems = true;
modelIndex = visibleItems.at(i)->index + 1;
+ }
}
- if (visibleItems.count() && (fillFrom > itemEnd+averageSize+spacing
+ if (haveValidItems && (fillFrom > itemEnd+averageSize+spacing
|| fillTo < visiblePos - averageSize - spacing)) {
// We've jumped more than a page. Estimate which items are now
// visible and fill from there.
@@ -940,7 +943,9 @@ void QDeclarativeListViewPrivate::createHighlight()
if (highlight) {
if (trackedItem == highlight)
trackedItem = 0;
- delete highlight->item;
+ if (highlight->item->scene())
+ highlight->item->scene()->removeItem(highlight->item);
+ highlight->item->deleteLater();
delete highlight;
highlight = 0;
delete highlightPosAnimator;
@@ -3406,9 +3411,9 @@ void QDeclarativeListView::itemsRemoved(int modelIndex, int count)
}
}
- if (removedVisible && !haveVisibleIndex) {
+ if (!haveVisibleIndex) {
d->timeline.clear();
- if (d->itemCount == 0) {
+ if (removedVisible && d->itemCount == 0) {
d->visibleIndex = 0;
d->visiblePos = d->header ? d->header->size() : 0;
d->setPosition(0);
diff --git a/src/declarative/graphicsitems/qdeclarativemousearea.cpp b/src/declarative/graphicsitems/qdeclarativemousearea.cpp
index 271a70498e..20ca0f689a 100644
--- a/src/declarative/graphicsitems/qdeclarativemousearea.cpp
+++ b/src/declarative/graphicsitems/qdeclarativemousearea.cpp
@@ -660,6 +660,32 @@ void QDeclarativeMouseArea::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
setHovered(false);
}
+#ifndef QT_NO_CONTEXTMENU
+void QDeclarativeMouseArea::contextMenuEvent(QGraphicsSceneContextMenuEvent *event)
+{
+ bool acceptsContextMenuButton;
+#if defined(Q_OS_SYMBIAN)
+ // In Symbian a Long Tap on the screen will trigger. See QSymbianControl::HandleLongTapEventL().
+ acceptsContextMenuButton = acceptedButtons() & Qt::LeftButton;
+#elif defined(Q_WS_WINCE)
+ // ### WinCE can trigger context menu event with a gesture in the left button or a
+ // click with the right button. Since we have no way here to differentiate them when
+ // event happens, accepting either of the them will block the event.
+ acceptsContextMenuButton = acceptedButtons() & (Qt::LeftButton | Qt::RightButton);
+#else
+ acceptsContextMenuButton = acceptedButtons() & Qt::RightButton;
+#endif
+
+ if (isEnabled() && event->reason() == QGraphicsSceneContextMenuEvent::Mouse
+ && acceptsContextMenuButton) {
+ // Do not let the context menu event propagate to items behind.
+ return;
+ }
+
+ QDeclarativeItem::contextMenuEvent(event);
+}
+#endif // QT_NO_CONTEXTMENU
+
bool QDeclarativeMouseArea::sceneEvent(QEvent *event)
{
bool rv = QDeclarativeItem::sceneEvent(event);
diff --git a/src/declarative/graphicsitems/qdeclarativemousearea_p.h b/src/declarative/graphicsitems/qdeclarativemousearea_p.h
index c3e5d3d704..8fd453f5de 100644
--- a/src/declarative/graphicsitems/qdeclarativemousearea_p.h
+++ b/src/declarative/graphicsitems/qdeclarativemousearea_p.h
@@ -190,6 +190,9 @@ protected:
void hoverEnterEvent(QGraphicsSceneHoverEvent *event);
void hoverMoveEvent(QGraphicsSceneHoverEvent *event);
void hoverLeaveEvent(QGraphicsSceneHoverEvent *event);
+#ifndef QT_NO_CONTEXTMENU
+ void contextMenuEvent(QGraphicsSceneContextMenuEvent *event);
+#endif // QT_NO_CONTEXTMENU
bool sceneEvent(QEvent *);
bool sendMouseEvent(QGraphicsSceneMouseEvent *event);
bool sceneEventFilter(QGraphicsItem *i, QEvent *e);
diff --git a/src/declarative/graphicsitems/qdeclarativepathview.cpp b/src/declarative/graphicsitems/qdeclarativepathview.cpp
index 79e52cd244..94f128dca8 100644
--- a/src/declarative/graphicsitems/qdeclarativepathview.cpp
+++ b/src/declarative/graphicsitems/qdeclarativepathview.cpp
@@ -203,7 +203,9 @@ void QDeclarativePathViewPrivate::createHighlight()
bool changed = false;
if (highlightItem) {
- delete highlightItem;
+ if (highlightItem->scene())
+ highlightItem->scene()->removeItem(highlightItem);
+ highlightItem->deleteLater();
highlightItem = 0;
changed = true;
}
diff --git a/src/declarative/graphicsitems/qdeclarativetextedit.cpp b/src/declarative/graphicsitems/qdeclarativetextedit.cpp
index fbeabcdc16..b32e02dcae 100644
--- a/src/declarative/graphicsitems/qdeclarativetextedit.cpp
+++ b/src/declarative/graphicsitems/qdeclarativetextedit.cpp
@@ -273,7 +273,6 @@ void QDeclarativeTextEdit::setText(const QString &text)
\o TextEdit.AutoText
\o TextEdit.PlainText
\o TextEdit.RichText
- \o TextEdit.StyledText
\endlist
The default is TextEdit.AutoText. If the text format is TextEdit.AutoText the text edit
@@ -1110,7 +1109,7 @@ void QDeclarativeTextEdit::setMouseSelectionMode(SelectionMode mode)
/*!
\qmlproperty bool TextEdit::readOnly
- Whether the user an interact with the TextEdit item. If this
+ Whether the user can interact with the TextEdit item. If this
property is set to true the text cannot be edited by user interaction.
By default this property is false.
diff --git a/src/declarative/graphicsitems/qdeclarativetextinput.cpp b/src/declarative/graphicsitems/qdeclarativetextinput.cpp
index dd5a58ebdc..98ec2050e9 100644
--- a/src/declarative/graphicsitems/qdeclarativetextinput.cpp
+++ b/src/declarative/graphicsitems/qdeclarativetextinput.cpp
@@ -1876,7 +1876,7 @@ bool QDeclarativeTextInput::isInputMethodComposing() const
void QDeclarativeTextInputPrivate::init()
{
Q_Q(QDeclarativeTextInput);
- control->setParent(q);
+ control->setParent(q);//Now mandatory due to accessibility changes
control->setCursorWidth(1);
control->setPasswordCharacter(QLatin1Char('*'));
q->setSmooth(smooth);
diff --git a/src/declarative/graphicsitems/qdeclarativetextinput_p_p.h b/src/declarative/graphicsitems/qdeclarativetextinput_p_p.h
index 4712c65ff0..947ddc7bfa 100644
--- a/src/declarative/graphicsitems/qdeclarativetextinput_p_p.h
+++ b/src/declarative/graphicsitems/qdeclarativetextinput_p_p.h
@@ -84,7 +84,6 @@ public:
showInputPanelOnFocus = false;
}
#endif
-
}
~QDeclarativeTextInputPrivate()
diff --git a/src/declarative/items/checksync.pl b/src/declarative/items/checksync.pl
new file mode 100755
index 0000000000..26288bf1f4
--- /dev/null
+++ b/src/declarative/items/checksync.pl
@@ -0,0 +1,108 @@
+#!/usr/bin/perl
+#############################################################################
+##
+## Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+## All rights reserved.
+## Contact: Nokia Corporation (qt-info@nokia.com)
+##
+## This file is part of the Declarative module of the Qt Toolkit.
+##
+## $QT_BEGIN_LICENSE:LGPL$
+## No Commercial Usage
+## This file contains pre-release code and may not be distributed.
+## You may use this file in accordance with the terms and conditions
+## contained in the Technology Preview License Agreement accompanying
+## this package.
+##
+## GNU Lesser General Public License Usage
+## Alternatively, this file may be used under the terms of the GNU Lesser
+## General Public License version 2.1 as published by the Free Software
+## Foundation and appearing in the file LICENSE.LGPL included in the
+## packaging of this file. Please review the following information to
+## ensure the GNU Lesser General Public License version 2.1 requirements
+## will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+##
+## In addition, as a special exception, 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.
+##
+## If you have questions regarding the use of this file, please contact
+## Nokia at qt-info@nokia.com.
+##
+##
+##
+##
+##
+##
+##
+##
+## $QT_END_LICENSE$
+##
+#############################################################################
+
+use strict;
+use warnings;
+
+die "Usage: $0 <QML directory>" if (@ARGV != 1);
+
+my @excludes;
+open (SYNCEXCLUDES, "<", "syncexcludes");
+while (<SYNCEXCLUDES>) {
+ if (/^([a-zA-Z0-9\._]+)/) {
+ my $exclude = $1;
+ push (@excludes, $exclude);
+ }
+}
+
+my $portdir = ".";
+my $qmldir = $ARGV[0];
+
+opendir (PORTDIR, $portdir) or die "Cannot open port directory";
+opendir (QMLDIR, $qmldir) or die "Cannot open QML directory";
+
+my @portfiles = readdir(PORTDIR);
+my @qmlfiles = readdir(QMLDIR);
+
+closedir(PORTDIR);
+closedir(QMLDIR);
+
+foreach my $qmlfile (@qmlfiles) {
+ if ($qmlfile =~ /^qdeclarative.*\.cpp$/ or $qmlfile =~ /qdeclarative.*\.h$/) {
+
+ if (grep { $_ eq $qmlfile} @excludes) {
+ next;
+ }
+
+ my $portfile = $qmlfile;
+ $portfile =~ s/^qdeclarative/qsg/;
+
+ if (grep { $_ eq $portfile} @portfiles) {
+
+ open (PORTFILE, "<", "$portdir/$portfile") or die("Cannot open $portdir/$portfile for reading");
+
+ my $firstline = <PORTFILE>;
+
+ close (PORTFILE);
+
+ if ($firstline and $firstline =~ /^\/\/ Commit: ([a-z0-9]+)/) {
+ my $sha1 = $1;
+ my $commitSha1 = "";
+
+ my $output = `cd $qmldir; git log $qmlfile | head -n 1`;
+ if ($output =~ /commit ([a-z0-9]+)/) {
+ $commitSha1 = $1;
+ }
+
+ if ($commitSha1 eq $sha1) {
+ print ("$portfile: OK\n");
+ } else {
+ print ("$portfile: OUT OF DATE\n");
+ }
+ } else {
+ print ("$portfile: OUT OF DATE\n");
+ }
+ } else {
+ print ("$portfile: MISSING\n");
+ }
+ }
+}
diff --git a/src/declarative/items/items.pri b/src/declarative/items/items.pri
new file mode 100644
index 0000000000..d6942973cd
--- /dev/null
+++ b/src/declarative/items/items.pri
@@ -0,0 +1,114 @@
+INCLUDEPATH += $$PWD
+
+HEADERS += \
+ $$PWD/qsgevents_p_p.h \
+ $$PWD/qsgitemchangelistener_p.h \
+ $$PWD/qsganchors_p.h \
+ $$PWD/qsganchors_p_p.h \
+ $$PWD/qsgitem.h \
+ $$PWD/qsgitem_p.h \
+ $$PWD/qsgrectangle_p.h \
+ $$PWD/qsgrectangle_p_p.h \
+ $$PWD/qsgcanvas.h \
+ $$PWD/qsgcanvas_p.h \
+ $$PWD/qsgfocusscope_p.h \
+ $$PWD/qsgitemsmodule_p.h \
+ $$PWD/qsgpainteditem.h \
+ $$PWD/qsgpainteditem_p.h \
+ $$PWD/qsgtext_p.h \
+ $$PWD/qsgtext_p_p.h \
+ $$PWD/qsgtextnode_p.h \
+ $$PWD/qsgtextinput_p.h \
+ $$PWD/qsgtextinput_p_p.h \
+ $$PWD/qsgtextedit_p.h \
+ $$PWD/qsgtextedit_p_p.h \
+ $$PWD/qsgimagebase_p.h \
+ $$PWD/qsgimagebase_p_p.h \
+ $$PWD/qsgimage_p.h \
+ $$PWD/qsgimage_p_p.h \
+ $$PWD/qsgborderimage_p.h \
+ $$PWD/qsgborderimage_p_p.h \
+ $$PWD/qsgninepatchnode_p.h \
+ $$PWD/qsgscalegrid_p_p.h \
+ $$PWD/qsgmousearea_p.h \
+ $$PWD/qsgmousearea_p_p.h \
+ $$PWD/qsgpincharea_p.h \
+ $$PWD/qsgpincharea_p_p.h \
+ $$PWD/qsgflickable_p.h \
+ $$PWD/qsgflickable_p_p.h \
+ $$PWD/qsglistview_p.h \
+ $$PWD/qsgvisualitemmodel_p.h \
+ $$PWD/qsgrepeater_p.h \
+ $$PWD/qsgrepeater_p_p.h \
+ $$PWD/qsggridview_p.h \
+ $$PWD/qsgpathview_p.h \
+ $$PWD/qsgpathview_p_p.h \
+ $$PWD/qsgpositioners_p.h \
+ $$PWD/qsgpositioners_p_p.h \
+ $$PWD/qsgloader_p.h \
+ $$PWD/qsgloader_p_p.h \
+ $$PWD/qsganimatedimage_p.h \
+ $$PWD/qsganimatedimage_p_p.h \
+ $$PWD/qsgflipable_p.h \
+ $$PWD/qsgtranslate_p.h \
+ $$PWD/qsgclipnode_p.h \
+ $$PWD/qsgview.h \
+ $$PWD/qsganimation_p.h \
+ $$PWD/qsganimation_p_p.h \
+ $$PWD/qsgstateoperations_p.h \
+ $$PWD/qsgimplicitsizeitem_p.h \
+ $$PWD/qsgimplicitsizeitem_p_p.h \
+ $$PWD/qsgcanvasitem_p.h \
+ $$PWD/qsgcontext2d_p.h \
+ $$PWD/qsgcontext2d_p_p.h \
+
+SOURCES += \
+ $$PWD/qsgevents.cpp \
+ $$PWD/qsganchors.cpp \
+ $$PWD/qsgitem.cpp \
+ $$PWD/qsgrectangle.cpp \
+ $$PWD/qsgcanvas.cpp \
+ $$PWD/qsgfocusscope.cpp \
+ $$PWD/qsgitemsmodule.cpp \
+ $$PWD/qsgpainteditem.cpp \
+ $$PWD/qsgtext.cpp \
+ $$PWD/qsgtextnode.cpp \
+ $$PWD/qsgtextinput.cpp \
+ $$PWD/qsgtextedit.cpp \
+ $$PWD/qsgimagebase.cpp \
+ $$PWD/qsgimage.cpp \
+ $$PWD/qsgborderimage.cpp \
+ $$PWD/qsgninepatchnode.cpp \
+ $$PWD/qsgscalegrid.cpp \
+ $$PWD/qsgmousearea.cpp \
+ $$PWD/qsgpincharea.cpp \
+ $$PWD/qsgflickable.cpp \
+ $$PWD/qsglistview.cpp \
+ $$PWD/qsgvisualitemmodel.cpp \
+ $$PWD/qsgrepeater.cpp \
+ $$PWD/qsggridview.cpp \
+ $$PWD/qsgpathview.cpp \
+ $$PWD/qsgpositioners.cpp \
+ $$PWD/qsgloader.cpp \
+ $$PWD/qsganimatedimage.cpp \
+ $$PWD/qsgflipable.cpp \
+ $$PWD/qsgtranslate.cpp \
+ $$PWD/qsgclipnode.cpp \
+ $$PWD/qsgview.cpp \
+ $$PWD/qsganimation.cpp \
+ $$PWD/qsgstateoperations.cpp \
+ $$PWD/qsgimplicitsizeitem.cpp \
+ $$PWD/qsgcanvasitem.cpp \
+ $$PWD/qsgcontext2d.cpp \
+
+SOURCES += \
+ $$PWD/qsgshadereffectitem.cpp \
+ $$PWD/qsgshadereffectmesh.cpp \
+ $$PWD/qsgshadereffectnode.cpp \
+ $$PWD/qsgshadereffectsource.cpp \
+
+HEADERS += \
+ $$PWD/qsgshadereffectitem_p.h \
+ $$PWD/qsgshadereffectmesh_p.h \
+ $$PWD/qsgshadereffectnode_p.h \
+ $$PWD/qsgshadereffectsource_p.h \
diff --git a/src/declarative/items/qsganchors.cpp b/src/declarative/items/qsganchors.cpp
new file mode 100644
index 0000000000..ff9351edbc
--- /dev/null
+++ b/src/declarative/items/qsganchors.cpp
@@ -0,0 +1,1111 @@
+// Commit: 2c7cab4172f1acc86fd49345a2847417e162f2c3
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsganchors_p_p.h"
+
+#include "qsgitem.h"
+#include "qsgitem_p.h"
+
+#include <qdeclarativeinfo.h>
+
+QT_BEGIN_NAMESPACE
+
+//TODO: should we cache relationships, so we don't have to check each time (parent-child or sibling)?
+//TODO: support non-parent, non-sibling (need to find lowest common ancestor)
+
+static qreal hcenter(QSGItem *item)
+{
+ qreal width = item->width();
+ int iw = width;
+ if (iw % 2)
+ return (width + 1) / 2;
+ else
+ return width / 2;
+}
+
+static qreal vcenter(QSGItem *item)
+{
+ qreal height = item->height();
+ int ih = height;
+ if (ih % 2)
+ return (height + 1) / 2;
+ else
+ return height / 2;
+}
+
+//### const item?
+//local position
+static qreal position(QSGItem *item, QSGAnchorLine::AnchorLine anchorLine)
+{
+ qreal ret = 0.0;
+ switch(anchorLine) {
+ case QSGAnchorLine::Left:
+ ret = item->x();
+ break;
+ case QSGAnchorLine::Right:
+ ret = item->x() + item->width();
+ break;
+ case QSGAnchorLine::Top:
+ ret = item->y();
+ break;
+ case QSGAnchorLine::Bottom:
+ ret = item->y() + item->height();
+ break;
+ case QSGAnchorLine::HCenter:
+ ret = item->x() + hcenter(item);
+ break;
+ case QSGAnchorLine::VCenter:
+ ret = item->y() + vcenter(item);
+ break;
+ case QSGAnchorLine::Baseline:
+ ret = item->y() + item->baselineOffset();
+ break;
+ default:
+ break;
+ }
+
+ return ret;
+}
+
+//position when origin is 0,0
+static qreal adjustedPosition(QSGItem *item, QSGAnchorLine::AnchorLine anchorLine)
+{
+ qreal ret = 0.0;
+ switch(anchorLine) {
+ case QSGAnchorLine::Left:
+ ret = 0.0;
+ break;
+ case QSGAnchorLine::Right:
+ ret = item->width();
+ break;
+ case QSGAnchorLine::Top:
+ ret = 0.0;
+ break;
+ case QSGAnchorLine::Bottom:
+ ret = item->height();
+ break;
+ case QSGAnchorLine::HCenter:
+ ret = hcenter(item);
+ break;
+ case QSGAnchorLine::VCenter:
+ ret = vcenter(item);
+ break;
+ case QSGAnchorLine::Baseline:
+ ret = item->baselineOffset();
+ break;
+ default:
+ break;
+ }
+
+ return ret;
+}
+
+QSGAnchors::QSGAnchors(QSGItem *item, QObject *parent)
+: QObject(*new QSGAnchorsPrivate(item), parent)
+{
+}
+
+QSGAnchors::~QSGAnchors()
+{
+ Q_D(QSGAnchors);
+ d->remDepend(d->fill);
+ d->remDepend(d->centerIn);
+ d->remDepend(d->left.item);
+ d->remDepend(d->right.item);
+ d->remDepend(d->top.item);
+ d->remDepend(d->bottom.item);
+ d->remDepend(d->vCenter.item);
+ d->remDepend(d->hCenter.item);
+ d->remDepend(d->baseline.item);
+}
+
+void QSGAnchorsPrivate::fillChanged()
+{
+ Q_Q(QSGAnchors);
+ if (!fill || !isItemComplete())
+ return;
+
+ if (updatingFill < 2) {
+ ++updatingFill;
+
+ qreal horizontalMargin = q->mirrored() ? rightMargin : leftMargin;
+
+ if (fill == item->parentItem()) { //child-parent
+ setItemPos(QPointF(horizontalMargin, topMargin));
+ } else if (fill->parentItem() == item->parentItem()) { //siblings
+ setItemPos(QPointF(fill->x()+horizontalMargin, fill->y()+topMargin));
+ }
+ setItemSize(QSizeF(fill->width()-leftMargin-rightMargin, fill->height()-topMargin-bottomMargin));
+
+ --updatingFill;
+ } else {
+ // ### Make this certain :)
+ qmlInfo(item) << QSGAnchors::tr("Possible anchor loop detected on fill.");
+ }
+
+}
+
+void QSGAnchorsPrivate::centerInChanged()
+{
+ Q_Q(QSGAnchors);
+ if (!centerIn || fill || !isItemComplete())
+ return;
+
+ if (updatingCenterIn < 2) {
+ ++updatingCenterIn;
+
+ qreal effectiveHCenterOffset = q->mirrored() ? -hCenterOffset : hCenterOffset;
+ if (centerIn == item->parentItem()) {
+ QPointF p(hcenter(item->parentItem()) - hcenter(item) + effectiveHCenterOffset,
+ vcenter(item->parentItem()) - vcenter(item) + vCenterOffset);
+ setItemPos(p);
+
+ } else if (centerIn->parentItem() == item->parentItem()) {
+ QPointF p(centerIn->x() + hcenter(centerIn) - hcenter(item) + effectiveHCenterOffset,
+ centerIn->y() + vcenter(centerIn) - vcenter(item) + vCenterOffset);
+ setItemPos(p);
+ }
+
+ --updatingCenterIn;
+ } else {
+ // ### Make this certain :)
+ qmlInfo(item) << QSGAnchors::tr("Possible anchor loop detected on centerIn.");
+ }
+}
+
+void QSGAnchorsPrivate::clearItem(QSGItem *item)
+{
+ if (!item)
+ return;
+ if (fill == item)
+ fill = 0;
+ if (centerIn == item)
+ centerIn = 0;
+ if (left.item == item) {
+ left.item = 0;
+ usedAnchors &= ~QSGAnchors::LeftAnchor;
+ }
+ if (right.item == item) {
+ right.item = 0;
+ usedAnchors &= ~QSGAnchors::RightAnchor;
+ }
+ if (top.item == item) {
+ top.item = 0;
+ usedAnchors &= ~QSGAnchors::TopAnchor;
+ }
+ if (bottom.item == item) {
+ bottom.item = 0;
+ usedAnchors &= ~QSGAnchors::BottomAnchor;
+ }
+ if (vCenter.item == item) {
+ vCenter.item = 0;
+ usedAnchors &= ~QSGAnchors::VCenterAnchor;
+ }
+ if (hCenter.item == item) {
+ hCenter.item = 0;
+ usedAnchors &= ~QSGAnchors::HCenterAnchor;
+ }
+ if (baseline.item == item) {
+ baseline.item = 0;
+ usedAnchors &= ~QSGAnchors::BaselineAnchor;
+ }
+}
+
+void QSGAnchorsPrivate::addDepend(QSGItem *item)
+{
+ if (!item)
+ return;
+
+ QSGItemPrivate *p = QSGItemPrivate::get(item);
+ p->addItemChangeListener(this, QSGItemPrivate::Geometry);
+}
+
+void QSGAnchorsPrivate::remDepend(QSGItem *item)
+{
+ if (!item)
+ return;
+
+ QSGItemPrivate *p = QSGItemPrivate::get(item);
+ p->removeItemChangeListener(this, QSGItemPrivate::Geometry);
+}
+
+bool QSGAnchors::mirrored()
+{
+ Q_D(QSGAnchors);
+ return QSGItemPrivate::get(d->item)->effectiveLayoutMirror;
+}
+
+bool QSGAnchorsPrivate::isItemComplete() const
+{
+ return componentComplete;
+}
+
+void QSGAnchors::classBegin()
+{
+ Q_D(QSGAnchors);
+ d->componentComplete = false;
+}
+
+void QSGAnchors::componentComplete()
+{
+ Q_D(QSGAnchors);
+ d->componentComplete = true;
+}
+
+void QSGAnchorsPrivate::setItemHeight(qreal v)
+{
+ updatingMe = true;
+ item->setHeight(v);
+ updatingMe = false;
+}
+
+void QSGAnchorsPrivate::setItemWidth(qreal v)
+{
+ updatingMe = true;
+ item->setWidth(v);
+ updatingMe = false;
+}
+
+void QSGAnchorsPrivate::setItemX(qreal v)
+{
+ updatingMe = true;
+ item->setX(v);
+ updatingMe = false;
+}
+
+void QSGAnchorsPrivate::setItemY(qreal v)
+{
+ updatingMe = true;
+ item->setY(v);
+ updatingMe = false;
+}
+
+void QSGAnchorsPrivate::setItemPos(const QPointF &v)
+{
+ updatingMe = true;
+ item->setPos(v);
+ updatingMe = false;
+}
+
+void QSGAnchorsPrivate::setItemSize(const QSizeF &v)
+{
+ updatingMe = true;
+ item->setSize(v);
+ updatingMe = false;
+}
+
+void QSGAnchorsPrivate::updateMe()
+{
+ if (updatingMe) {
+ updatingMe = false;
+ return;
+ }
+
+ fillChanged();
+ centerInChanged();
+ updateHorizontalAnchors();
+ updateVerticalAnchors();
+}
+
+void QSGAnchorsPrivate::updateOnComplete()
+{
+ fillChanged();
+ centerInChanged();
+ updateHorizontalAnchors();
+ updateVerticalAnchors();
+}
+
+void QSGAnchorsPrivate::itemGeometryChanged(QSGItem *, const QRectF &newG, const QRectF &oldG)
+{
+ fillChanged();
+ centerInChanged();
+ if (newG.x() != oldG.x() || newG.width() != oldG.width())
+ updateHorizontalAnchors();
+ if (newG.y() != oldG.y() || newG.height() != oldG.height())
+ updateVerticalAnchors();
+}
+
+QSGItem *QSGAnchors::fill() const
+{
+ Q_D(const QSGAnchors);
+ return d->fill;
+}
+
+void QSGAnchors::setFill(QSGItem *f)
+{
+ Q_D(QSGAnchors);
+ if (d->fill == f)
+ return;
+
+ if (!f) {
+ d->remDepend(d->fill);
+ d->fill = f;
+ emit fillChanged();
+ return;
+ }
+ if (f != d->item->parentItem() && f->parentItem() != d->item->parentItem()){
+ qmlInfo(d->item) << tr("Cannot anchor to an item that isn't a parent or sibling.");
+ return;
+ }
+ d->remDepend(d->fill);
+ d->fill = f;
+ d->addDepend(d->fill);
+ emit fillChanged();
+ d->fillChanged();
+}
+
+void QSGAnchors::resetFill()
+{
+ setFill(0);
+}
+
+QSGItem *QSGAnchors::centerIn() const
+{
+ Q_D(const QSGAnchors);
+ return d->centerIn;
+}
+
+void QSGAnchors::setCenterIn(QSGItem* c)
+{
+ Q_D(QSGAnchors);
+ if (d->centerIn == c)
+ return;
+
+ if (!c) {
+ d->remDepend(d->centerIn);
+ d->centerIn = c;
+ emit centerInChanged();
+ return;
+ }
+ if (c != d->item->parentItem() && c->parentItem() != d->item->parentItem()){
+ qmlInfo(d->item) << tr("Cannot anchor to an item that isn't a parent or sibling.");
+ return;
+ }
+
+ d->remDepend(d->centerIn);
+ d->centerIn = c;
+ d->addDepend(d->centerIn);
+ emit centerInChanged();
+ d->centerInChanged();
+}
+
+void QSGAnchors::resetCenterIn()
+{
+ setCenterIn(0);
+}
+
+bool QSGAnchorsPrivate::calcStretch(const QSGAnchorLine &edge1,
+ const QSGAnchorLine &edge2,
+ qreal offset1,
+ qreal offset2,
+ QSGAnchorLine::AnchorLine line,
+ qreal &stretch)
+{
+ bool edge1IsParent = (edge1.item == item->parentItem());
+ bool edge2IsParent = (edge2.item == item->parentItem());
+ bool edge1IsSibling = (edge1.item->parentItem() == item->parentItem());
+ bool edge2IsSibling = (edge2.item->parentItem() == item->parentItem());
+
+ bool invalid = false;
+ if ((edge2IsParent && edge1IsParent) || (edge2IsSibling && edge1IsSibling)) {
+ stretch = (position(edge2.item, edge2.anchorLine) + offset2)
+ - (position(edge1.item, edge1.anchorLine) + offset1);
+ } else if (edge2IsParent && edge1IsSibling) {
+ stretch = (position(edge2.item, edge2.anchorLine) + offset2)
+ - (position(item->parentItem(), line)
+ + position(edge1.item, edge1.anchorLine) + offset1);
+ } else if (edge2IsSibling && edge1IsParent) {
+ stretch = (position(item->parentItem(), line) + position(edge2.item, edge2.anchorLine) + offset2)
+ - (position(edge1.item, edge1.anchorLine) + offset1);
+ } else
+ invalid = true;
+
+ return invalid;
+}
+
+void QSGAnchorsPrivate::updateVerticalAnchors()
+{
+ if (fill || centerIn || !isItemComplete())
+ return;
+
+ if (updatingVerticalAnchor < 2) {
+ ++updatingVerticalAnchor;
+ if (usedAnchors & QSGAnchors::TopAnchor) {
+ //Handle stretching
+ bool invalid = true;
+ qreal height = 0.0;
+ if (usedAnchors & QSGAnchors::BottomAnchor) {
+ invalid = calcStretch(top, bottom, topMargin, -bottomMargin, QSGAnchorLine::Top, height);
+ } else if (usedAnchors & QSGAnchors::VCenterAnchor) {
+ invalid = calcStretch(top, vCenter, topMargin, vCenterOffset, QSGAnchorLine::Top, height);
+ height *= 2;
+ }
+ if (!invalid)
+ setItemHeight(height);
+
+ //Handle top
+ if (top.item == item->parentItem()) {
+ setItemY(adjustedPosition(top.item, top.anchorLine) + topMargin);
+ } else if (top.item->parentItem() == item->parentItem()) {
+ setItemY(position(top.item, top.anchorLine) + topMargin);
+ }
+ } else if (usedAnchors & QSGAnchors::BottomAnchor) {
+ //Handle stretching (top + bottom case is handled above)
+ if (usedAnchors & QSGAnchors::VCenterAnchor) {
+ qreal height = 0.0;
+ bool invalid = calcStretch(vCenter, bottom, vCenterOffset, -bottomMargin,
+ QSGAnchorLine::Top, height);
+ if (!invalid)
+ setItemHeight(height*2);
+ }
+
+ //Handle bottom
+ if (bottom.item == item->parentItem()) {
+ setItemY(adjustedPosition(bottom.item, bottom.anchorLine) - item->height() - bottomMargin);
+ } else if (bottom.item->parentItem() == item->parentItem()) {
+ setItemY(position(bottom.item, bottom.anchorLine) - item->height() - bottomMargin);
+ }
+ } else if (usedAnchors & QSGAnchors::VCenterAnchor) {
+ //(stetching handled above)
+
+ //Handle vCenter
+ if (vCenter.item == item->parentItem()) {
+ setItemY(adjustedPosition(vCenter.item, vCenter.anchorLine)
+ - vcenter(item) + vCenterOffset);
+ } else if (vCenter.item->parentItem() == item->parentItem()) {
+ setItemY(position(vCenter.item, vCenter.anchorLine) - vcenter(item) + vCenterOffset);
+ }
+ } else if (usedAnchors & QSGAnchors::BaselineAnchor) {
+ //Handle baseline
+ if (baseline.item == item->parentItem()) {
+ setItemY(adjustedPosition(baseline.item, baseline.anchorLine) - item->baselineOffset() + baselineOffset);
+ } else if (baseline.item->parentItem() == item->parentItem()) {
+ setItemY(position(baseline.item, baseline.anchorLine) - item->baselineOffset() + baselineOffset);
+ }
+ }
+ --updatingVerticalAnchor;
+ } else {
+ // ### Make this certain :)
+ qmlInfo(item) << QSGAnchors::tr("Possible anchor loop detected on vertical anchor.");
+ }
+}
+
+inline QSGAnchorLine::AnchorLine reverseAnchorLine(QSGAnchorLine::AnchorLine anchorLine)
+{
+ if (anchorLine == QSGAnchorLine::Left) {
+ return QSGAnchorLine::Right;
+ } else if (anchorLine == QSGAnchorLine::Right) {
+ return QSGAnchorLine::Left;
+ } else {
+ return anchorLine;
+ }
+}
+
+void QSGAnchorsPrivate::updateHorizontalAnchors()
+{
+ Q_Q(QSGAnchors);
+ if (fill || centerIn || !isItemComplete())
+ return;
+
+ if (updatingHorizontalAnchor < 3) {
+ ++updatingHorizontalAnchor;
+ qreal effectiveRightMargin, effectiveLeftMargin, effectiveHorizontalCenterOffset;
+ QSGAnchorLine effectiveLeft, effectiveRight, effectiveHorizontalCenter;
+ QSGAnchors::Anchor effectiveLeftAnchor, effectiveRightAnchor;
+ if (q->mirrored()) {
+ effectiveLeftAnchor = QSGAnchors::RightAnchor;
+ effectiveRightAnchor = QSGAnchors::LeftAnchor;
+ effectiveLeft.item = right.item;
+ effectiveLeft.anchorLine = reverseAnchorLine(right.anchorLine);
+ effectiveRight.item = left.item;
+ effectiveRight.anchorLine = reverseAnchorLine(left.anchorLine);
+ effectiveHorizontalCenter.item = hCenter.item;
+ effectiveHorizontalCenter.anchorLine = reverseAnchorLine(hCenter.anchorLine);
+ effectiveLeftMargin = rightMargin;
+ effectiveRightMargin = leftMargin;
+ effectiveHorizontalCenterOffset = -hCenterOffset;
+ } else {
+ effectiveLeftAnchor = QSGAnchors::LeftAnchor;
+ effectiveRightAnchor = QSGAnchors::RightAnchor;
+ effectiveLeft = left;
+ effectiveRight = right;
+ effectiveHorizontalCenter = hCenter;
+ effectiveLeftMargin = leftMargin;
+ effectiveRightMargin = rightMargin;
+ effectiveHorizontalCenterOffset = hCenterOffset;
+ }
+
+ if (usedAnchors & effectiveLeftAnchor) {
+ //Handle stretching
+ bool invalid = true;
+ qreal width = 0.0;
+ if (usedAnchors & effectiveRightAnchor) {
+ invalid = calcStretch(effectiveLeft, effectiveRight, effectiveLeftMargin, -effectiveRightMargin, QSGAnchorLine::Left, width);
+ } else if (usedAnchors & QSGAnchors::HCenterAnchor) {
+ invalid = calcStretch(effectiveLeft, effectiveHorizontalCenter, effectiveLeftMargin, effectiveHorizontalCenterOffset, QSGAnchorLine::Left, width);
+ width *= 2;
+ }
+ if (!invalid)
+ setItemWidth(width);
+
+ //Handle left
+ if (effectiveLeft.item == item->parentItem()) {
+ setItemX(adjustedPosition(effectiveLeft.item, effectiveLeft.anchorLine) + effectiveLeftMargin);
+ } else if (effectiveLeft.item->parentItem() == item->parentItem()) {
+ setItemX(position(effectiveLeft.item, effectiveLeft.anchorLine) + effectiveLeftMargin);
+ }
+ } else if (usedAnchors & effectiveRightAnchor) {
+ //Handle stretching (left + right case is handled in updateLeftAnchor)
+ if (usedAnchors & QSGAnchors::HCenterAnchor) {
+ qreal width = 0.0;
+ bool invalid = calcStretch(effectiveHorizontalCenter, effectiveRight, effectiveHorizontalCenterOffset, -effectiveRightMargin,
+ QSGAnchorLine::Left, width);
+ if (!invalid)
+ setItemWidth(width*2);
+ }
+
+ //Handle right
+ if (effectiveRight.item == item->parentItem()) {
+ setItemX(adjustedPosition(effectiveRight.item, effectiveRight.anchorLine) - item->width() - effectiveRightMargin);
+ } else if (effectiveRight.item->parentItem() == item->parentItem()) {
+ setItemX(position(effectiveRight.item, effectiveRight.anchorLine) - item->width() - effectiveRightMargin);
+ }
+ } else if (usedAnchors & QSGAnchors::HCenterAnchor) {
+ //Handle hCenter
+ if (effectiveHorizontalCenter.item == item->parentItem()) {
+ setItemX(adjustedPosition(effectiveHorizontalCenter.item, effectiveHorizontalCenter.anchorLine) - hcenter(item) + effectiveHorizontalCenterOffset);
+ } else if (effectiveHorizontalCenter.item->parentItem() == item->parentItem()) {
+ setItemX(position(effectiveHorizontalCenter.item, effectiveHorizontalCenter.anchorLine) - hcenter(item) + effectiveHorizontalCenterOffset);
+ }
+ }
+ --updatingHorizontalAnchor;
+ } else {
+ // ### Make this certain :)
+ qmlInfo(item) << QSGAnchors::tr("Possible anchor loop detected on horizontal anchor.");
+ }
+}
+
+QSGAnchorLine QSGAnchors::top() const
+{
+ Q_D(const QSGAnchors);
+ return d->top;
+}
+
+void QSGAnchors::setTop(const QSGAnchorLine &edge)
+{
+ Q_D(QSGAnchors);
+ if (!d->checkVAnchorValid(edge) || d->top == edge)
+ return;
+
+ d->usedAnchors |= TopAnchor;
+
+ if (!d->checkVValid()) {
+ d->usedAnchors &= ~TopAnchor;
+ return;
+ }
+
+ d->remDepend(d->top.item);
+ d->top = edge;
+ d->addDepend(d->top.item);
+ emit topChanged();
+ d->updateVerticalAnchors();
+}
+
+void QSGAnchors::resetTop()
+{
+ Q_D(QSGAnchors);
+ d->usedAnchors &= ~TopAnchor;
+ d->remDepend(d->top.item);
+ d->top = QSGAnchorLine();
+ emit topChanged();
+ d->updateVerticalAnchors();
+}
+
+QSGAnchorLine QSGAnchors::bottom() const
+{
+ Q_D(const QSGAnchors);
+ return d->bottom;
+}
+
+void QSGAnchors::setBottom(const QSGAnchorLine &edge)
+{
+ Q_D(QSGAnchors);
+ if (!d->checkVAnchorValid(edge) || d->bottom == edge)
+ return;
+
+ d->usedAnchors |= BottomAnchor;
+
+ if (!d->checkVValid()) {
+ d->usedAnchors &= ~BottomAnchor;
+ return;
+ }
+
+ d->remDepend(d->bottom.item);
+ d->bottom = edge;
+ d->addDepend(d->bottom.item);
+ emit bottomChanged();
+ d->updateVerticalAnchors();
+}
+
+void QSGAnchors::resetBottom()
+{
+ Q_D(QSGAnchors);
+ d->usedAnchors &= ~BottomAnchor;
+ d->remDepend(d->bottom.item);
+ d->bottom = QSGAnchorLine();
+ emit bottomChanged();
+ d->updateVerticalAnchors();
+}
+
+QSGAnchorLine QSGAnchors::verticalCenter() const
+{
+ Q_D(const QSGAnchors);
+ return d->vCenter;
+}
+
+void QSGAnchors::setVerticalCenter(const QSGAnchorLine &edge)
+{
+ Q_D(QSGAnchors);
+ if (!d->checkVAnchorValid(edge) || d->vCenter == edge)
+ return;
+
+ d->usedAnchors |= VCenterAnchor;
+
+ if (!d->checkVValid()) {
+ d->usedAnchors &= ~VCenterAnchor;
+ return;
+ }
+
+ d->remDepend(d->vCenter.item);
+ d->vCenter = edge;
+ d->addDepend(d->vCenter.item);
+ emit verticalCenterChanged();
+ d->updateVerticalAnchors();
+}
+
+void QSGAnchors::resetVerticalCenter()
+{
+ Q_D(QSGAnchors);
+ d->usedAnchors &= ~VCenterAnchor;
+ d->remDepend(d->vCenter.item);
+ d->vCenter = QSGAnchorLine();
+ emit verticalCenterChanged();
+ d->updateVerticalAnchors();
+}
+
+QSGAnchorLine QSGAnchors::baseline() const
+{
+ Q_D(const QSGAnchors);
+ return d->baseline;
+}
+
+void QSGAnchors::setBaseline(const QSGAnchorLine &edge)
+{
+ Q_D(QSGAnchors);
+ if (!d->checkVAnchorValid(edge) || d->baseline == edge)
+ return;
+
+ d->usedAnchors |= BaselineAnchor;
+
+ if (!d->checkVValid()) {
+ d->usedAnchors &= ~BaselineAnchor;
+ return;
+ }
+
+ d->remDepend(d->baseline.item);
+ d->baseline = edge;
+ d->addDepend(d->baseline.item);
+ emit baselineChanged();
+ d->updateVerticalAnchors();
+}
+
+void QSGAnchors::resetBaseline()
+{
+ Q_D(QSGAnchors);
+ d->usedAnchors &= ~BaselineAnchor;
+ d->remDepend(d->baseline.item);
+ d->baseline = QSGAnchorLine();
+ emit baselineChanged();
+ d->updateVerticalAnchors();
+}
+
+QSGAnchorLine QSGAnchors::left() const
+{
+ Q_D(const QSGAnchors);
+ return d->left;
+}
+
+void QSGAnchors::setLeft(const QSGAnchorLine &edge)
+{
+ Q_D(QSGAnchors);
+ if (!d->checkHAnchorValid(edge) || d->left == edge)
+ return;
+
+ d->usedAnchors |= LeftAnchor;
+
+ if (!d->checkHValid()) {
+ d->usedAnchors &= ~LeftAnchor;
+ return;
+ }
+
+ d->remDepend(d->left.item);
+ d->left = edge;
+ d->addDepend(d->left.item);
+ emit leftChanged();
+ d->updateHorizontalAnchors();
+}
+
+void QSGAnchors::resetLeft()
+{
+ Q_D(QSGAnchors);
+ d->usedAnchors &= ~LeftAnchor;
+ d->remDepend(d->left.item);
+ d->left = QSGAnchorLine();
+ emit leftChanged();
+ d->updateHorizontalAnchors();
+}
+
+QSGAnchorLine QSGAnchors::right() const
+{
+ Q_D(const QSGAnchors);
+ return d->right;
+}
+
+void QSGAnchors::setRight(const QSGAnchorLine &edge)
+{
+ Q_D(QSGAnchors);
+ if (!d->checkHAnchorValid(edge) || d->right == edge)
+ return;
+
+ d->usedAnchors |= RightAnchor;
+
+ if (!d->checkHValid()) {
+ d->usedAnchors &= ~RightAnchor;
+ return;
+ }
+
+ d->remDepend(d->right.item);
+ d->right = edge;
+ d->addDepend(d->right.item);
+ emit rightChanged();
+ d->updateHorizontalAnchors();
+}
+
+void QSGAnchors::resetRight()
+{
+ Q_D(QSGAnchors);
+ d->usedAnchors &= ~RightAnchor;
+ d->remDepend(d->right.item);
+ d->right = QSGAnchorLine();
+ emit rightChanged();
+ d->updateHorizontalAnchors();
+}
+
+QSGAnchorLine QSGAnchors::horizontalCenter() const
+{
+ Q_D(const QSGAnchors);
+ return d->hCenter;
+}
+
+void QSGAnchors::setHorizontalCenter(const QSGAnchorLine &edge)
+{
+ Q_D(QSGAnchors);
+ if (!d->checkHAnchorValid(edge) || d->hCenter == edge)
+ return;
+
+ d->usedAnchors |= HCenterAnchor;
+
+ if (!d->checkHValid()) {
+ d->usedAnchors &= ~HCenterAnchor;
+ return;
+ }
+
+ d->remDepend(d->hCenter.item);
+ d->hCenter = edge;
+ d->addDepend(d->hCenter.item);
+ emit horizontalCenterChanged();
+ d->updateHorizontalAnchors();
+}
+
+void QSGAnchors::resetHorizontalCenter()
+{
+ Q_D(QSGAnchors);
+ d->usedAnchors &= ~HCenterAnchor;
+ d->remDepend(d->hCenter.item);
+ d->hCenter = QSGAnchorLine();
+ emit horizontalCenterChanged();
+ d->updateHorizontalAnchors();
+}
+
+qreal QSGAnchors::leftMargin() const
+{
+ Q_D(const QSGAnchors);
+ return d->leftMargin;
+}
+
+void QSGAnchors::setLeftMargin(qreal offset)
+{
+ Q_D(QSGAnchors);
+ if (d->leftMargin == offset)
+ return;
+ d->leftMargin = offset;
+ if(d->fill)
+ d->fillChanged();
+ else
+ d->updateHorizontalAnchors();
+ emit leftMarginChanged();
+}
+
+qreal QSGAnchors::rightMargin() const
+{
+ Q_D(const QSGAnchors);
+ return d->rightMargin;
+}
+
+void QSGAnchors::setRightMargin(qreal offset)
+{
+ Q_D(QSGAnchors);
+ if (d->rightMargin == offset)
+ return;
+ d->rightMargin = offset;
+ if(d->fill)
+ d->fillChanged();
+ else
+ d->updateHorizontalAnchors();
+ emit rightMarginChanged();
+}
+
+qreal QSGAnchors::margins() const
+{
+ Q_D(const QSGAnchors);
+ return d->margins;
+}
+
+void QSGAnchors::setMargins(qreal offset)
+{
+ Q_D(QSGAnchors);
+ if (d->margins == offset)
+ return;
+ //###Is it significantly faster to set them directly so we can call fillChanged only once?
+ if(!d->rightMargin || d->rightMargin == d->margins)
+ setRightMargin(offset);
+ if(!d->leftMargin || d->leftMargin == d->margins)
+ setLeftMargin(offset);
+ if(!d->topMargin || d->topMargin == d->margins)
+ setTopMargin(offset);
+ if(!d->bottomMargin || d->bottomMargin == d->margins)
+ setBottomMargin(offset);
+ d->margins = offset;
+ emit marginsChanged();
+
+}
+
+qreal QSGAnchors::horizontalCenterOffset() const
+{
+ Q_D(const QSGAnchors);
+ return d->hCenterOffset;
+}
+
+void QSGAnchors::setHorizontalCenterOffset(qreal offset)
+{
+ Q_D(QSGAnchors);
+ if (d->hCenterOffset == offset)
+ return;
+ d->hCenterOffset = offset;
+ if(d->centerIn)
+ d->centerInChanged();
+ else
+ d->updateHorizontalAnchors();
+ emit horizontalCenterOffsetChanged();
+}
+
+qreal QSGAnchors::topMargin() const
+{
+ Q_D(const QSGAnchors);
+ return d->topMargin;
+}
+
+void QSGAnchors::setTopMargin(qreal offset)
+{
+ Q_D(QSGAnchors);
+ if (d->topMargin == offset)
+ return;
+ d->topMargin = offset;
+ if(d->fill)
+ d->fillChanged();
+ else
+ d->updateVerticalAnchors();
+ emit topMarginChanged();
+}
+
+qreal QSGAnchors::bottomMargin() const
+{
+ Q_D(const QSGAnchors);
+ return d->bottomMargin;
+}
+
+void QSGAnchors::setBottomMargin(qreal offset)
+{
+ Q_D(QSGAnchors);
+ if (d->bottomMargin == offset)
+ return;
+ d->bottomMargin = offset;
+ if(d->fill)
+ d->fillChanged();
+ else
+ d->updateVerticalAnchors();
+ emit bottomMarginChanged();
+}
+
+qreal QSGAnchors::verticalCenterOffset() const
+{
+ Q_D(const QSGAnchors);
+ return d->vCenterOffset;
+}
+
+void QSGAnchors::setVerticalCenterOffset(qreal offset)
+{
+ Q_D(QSGAnchors);
+ if (d->vCenterOffset == offset)
+ return;
+ d->vCenterOffset = offset;
+ if(d->centerIn)
+ d->centerInChanged();
+ else
+ d->updateVerticalAnchors();
+ emit verticalCenterOffsetChanged();
+}
+
+qreal QSGAnchors::baselineOffset() const
+{
+ Q_D(const QSGAnchors);
+ return d->baselineOffset;
+}
+
+void QSGAnchors::setBaselineOffset(qreal offset)
+{
+ Q_D(QSGAnchors);
+ if (d->baselineOffset == offset)
+ return;
+ d->baselineOffset = offset;
+ d->updateVerticalAnchors();
+ emit baselineOffsetChanged();
+}
+
+QSGAnchors::Anchors QSGAnchors::usedAnchors() const
+{
+ Q_D(const QSGAnchors);
+ return d->usedAnchors;
+}
+
+bool QSGAnchorsPrivate::checkHValid() const
+{
+ if (usedAnchors & QSGAnchors::LeftAnchor &&
+ usedAnchors & QSGAnchors::RightAnchor &&
+ usedAnchors & QSGAnchors::HCenterAnchor) {
+ qmlInfo(item) << QSGAnchors::tr("Cannot specify left, right, and hcenter anchors.");
+ return false;
+ }
+
+ return true;
+}
+
+bool QSGAnchorsPrivate::checkHAnchorValid(QSGAnchorLine anchor) const
+{
+ if (!anchor.item) {
+ qmlInfo(item) << QSGAnchors::tr("Cannot anchor to a null item.");
+ return false;
+ } else if (anchor.anchorLine & QSGAnchorLine::Vertical_Mask) {
+ qmlInfo(item) << QSGAnchors::tr("Cannot anchor a horizontal edge to a vertical edge.");
+ return false;
+ } else if (anchor.item != item->parentItem() && anchor.item->parentItem() != item->parentItem()){
+ qmlInfo(item) << QSGAnchors::tr("Cannot anchor to an item that isn't a parent or sibling.");
+ return false;
+ } else if (anchor.item == item) {
+ qmlInfo(item) << QSGAnchors::tr("Cannot anchor item to self.");
+ return false;
+ }
+
+ return true;
+}
+
+bool QSGAnchorsPrivate::checkVValid() const
+{
+ if (usedAnchors & QSGAnchors::TopAnchor &&
+ usedAnchors & QSGAnchors::BottomAnchor &&
+ usedAnchors & QSGAnchors::VCenterAnchor) {
+ qmlInfo(item) << QSGAnchors::tr("Cannot specify top, bottom, and vcenter anchors.");
+ return false;
+ } else if (usedAnchors & QSGAnchors::BaselineAnchor &&
+ (usedAnchors & QSGAnchors::TopAnchor ||
+ usedAnchors & QSGAnchors::BottomAnchor ||
+ usedAnchors & QSGAnchors::VCenterAnchor)) {
+ qmlInfo(item) << QSGAnchors::tr("Baseline anchor cannot be used in conjunction with top, bottom, or vcenter anchors.");
+ return false;
+ }
+
+ return true;
+}
+
+bool QSGAnchorsPrivate::checkVAnchorValid(QSGAnchorLine anchor) const
+{
+ if (!anchor.item) {
+ qmlInfo(item) << QSGAnchors::tr("Cannot anchor to a null item.");
+ return false;
+ } else if (anchor.anchorLine & QSGAnchorLine::Horizontal_Mask) {
+ qmlInfo(item) << QSGAnchors::tr("Cannot anchor a vertical edge to a horizontal edge.");
+ return false;
+ } else if (anchor.item != item->parentItem() && anchor.item->parentItem() != item->parentItem()){
+ qmlInfo(item) << QSGAnchors::tr("Cannot anchor to an item that isn't a parent or sibling.");
+ return false;
+ } else if (anchor.item == item){
+ qmlInfo(item) << QSGAnchors::tr("Cannot anchor item to self.");
+ return false;
+ }
+
+ return true;
+}
+
+QT_END_NAMESPACE
+
+#include <moc_qsganchors_p.cpp>
+
diff --git a/src/declarative/items/qsganchors_p.h b/src/declarative/items/qsganchors_p.h
new file mode 100644
index 0000000000..d26fb57961
--- /dev/null
+++ b/src/declarative/items/qsganchors_p.h
@@ -0,0 +1,201 @@
+// Commit: 2c7cab4172f1acc86fd49345a2847417e162f2c3
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGANCHORS_P_H
+#define QSGANCHORS_P_H
+
+#include <qdeclarative.h>
+
+#include <QtCore/QObject>
+
+#include <private/qdeclarativeglobal_p.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QSGItem;
+class QSGAnchorsPrivate;
+class QSGAnchorLine;
+class Q_DECLARATIVE_PRIVATE_EXPORT QSGAnchors : public QObject
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QSGAnchorLine left READ left WRITE setLeft RESET resetLeft NOTIFY leftChanged)
+ Q_PROPERTY(QSGAnchorLine right READ right WRITE setRight RESET resetRight NOTIFY rightChanged)
+ Q_PROPERTY(QSGAnchorLine horizontalCenter READ horizontalCenter WRITE setHorizontalCenter RESET resetHorizontalCenter NOTIFY horizontalCenterChanged)
+ Q_PROPERTY(QSGAnchorLine top READ top WRITE setTop RESET resetTop NOTIFY topChanged)
+ Q_PROPERTY(QSGAnchorLine bottom READ bottom WRITE setBottom RESET resetBottom NOTIFY bottomChanged)
+ Q_PROPERTY(QSGAnchorLine verticalCenter READ verticalCenter WRITE setVerticalCenter RESET resetVerticalCenter NOTIFY verticalCenterChanged)
+ Q_PROPERTY(QSGAnchorLine baseline READ baseline WRITE setBaseline RESET resetBaseline NOTIFY baselineChanged)
+ Q_PROPERTY(qreal margins READ margins WRITE setMargins NOTIFY marginsChanged)
+ Q_PROPERTY(qreal leftMargin READ leftMargin WRITE setLeftMargin NOTIFY leftMarginChanged)
+ Q_PROPERTY(qreal rightMargin READ rightMargin WRITE setRightMargin NOTIFY rightMarginChanged)
+ Q_PROPERTY(qreal horizontalCenterOffset READ horizontalCenterOffset WRITE setHorizontalCenterOffset NOTIFY horizontalCenterOffsetChanged)
+ Q_PROPERTY(qreal topMargin READ topMargin WRITE setTopMargin NOTIFY topMarginChanged)
+ Q_PROPERTY(qreal bottomMargin READ bottomMargin WRITE setBottomMargin NOTIFY bottomMarginChanged)
+ Q_PROPERTY(qreal verticalCenterOffset READ verticalCenterOffset WRITE setVerticalCenterOffset NOTIFY verticalCenterOffsetChanged)
+ Q_PROPERTY(qreal baselineOffset READ baselineOffset WRITE setBaselineOffset NOTIFY baselineOffsetChanged)
+ Q_PROPERTY(QSGItem *fill READ fill WRITE setFill RESET resetFill NOTIFY fillChanged)
+ Q_PROPERTY(QSGItem *centerIn READ centerIn WRITE setCenterIn RESET resetCenterIn NOTIFY centerInChanged)
+ Q_PROPERTY(bool mirrored READ mirrored NOTIFY mirroredChanged)
+
+public:
+ QSGAnchors(QSGItem *item, QObject *parent=0);
+ virtual ~QSGAnchors();
+
+ enum Anchor {
+ LeftAnchor = 0x01,
+ RightAnchor = 0x02,
+ TopAnchor = 0x04,
+ BottomAnchor = 0x08,
+ HCenterAnchor = 0x10,
+ VCenterAnchor = 0x20,
+ BaselineAnchor = 0x40,
+ Horizontal_Mask = LeftAnchor | RightAnchor | HCenterAnchor,
+ Vertical_Mask = TopAnchor | BottomAnchor | VCenterAnchor | BaselineAnchor
+ };
+ Q_DECLARE_FLAGS(Anchors, Anchor)
+
+ QSGAnchorLine left() const;
+ void setLeft(const QSGAnchorLine &edge);
+ void resetLeft();
+
+ QSGAnchorLine right() const;
+ void setRight(const QSGAnchorLine &edge);
+ void resetRight();
+
+ QSGAnchorLine horizontalCenter() const;
+ void setHorizontalCenter(const QSGAnchorLine &edge);
+ void resetHorizontalCenter();
+
+ QSGAnchorLine top() const;
+ void setTop(const QSGAnchorLine &edge);
+ void resetTop();
+
+ QSGAnchorLine bottom() const;
+ void setBottom(const QSGAnchorLine &edge);
+ void resetBottom();
+
+ QSGAnchorLine verticalCenter() const;
+ void setVerticalCenter(const QSGAnchorLine &edge);
+ void resetVerticalCenter();
+
+ QSGAnchorLine baseline() const;
+ void setBaseline(const QSGAnchorLine &edge);
+ void resetBaseline();
+
+ qreal leftMargin() const;
+ void setLeftMargin(qreal);
+
+ qreal rightMargin() const;
+ void setRightMargin(qreal);
+
+ qreal horizontalCenterOffset() const;
+ void setHorizontalCenterOffset(qreal);
+
+ qreal topMargin() const;
+ void setTopMargin(qreal);
+
+ qreal bottomMargin() const;
+ void setBottomMargin(qreal);
+
+ qreal margins() const;
+ void setMargins(qreal);
+
+ qreal verticalCenterOffset() const;
+ void setVerticalCenterOffset(qreal);
+
+ qreal baselineOffset() const;
+ void setBaselineOffset(qreal);
+
+ QSGItem *fill() const;
+ void setFill(QSGItem *);
+ void resetFill();
+
+ QSGItem *centerIn() const;
+ void setCenterIn(QSGItem *);
+ void resetCenterIn();
+
+ Anchors usedAnchors() const;
+
+ bool mirrored();
+
+ void classBegin();
+ void componentComplete();
+
+Q_SIGNALS:
+ void leftChanged();
+ void rightChanged();
+ void topChanged();
+ void bottomChanged();
+ void verticalCenterChanged();
+ void horizontalCenterChanged();
+ void baselineChanged();
+ void fillChanged();
+ void centerInChanged();
+ void leftMarginChanged();
+ void rightMarginChanged();
+ void topMarginChanged();
+ void bottomMarginChanged();
+ void marginsChanged();
+ void verticalCenterOffsetChanged();
+ void horizontalCenterOffsetChanged();
+ void baselineOffsetChanged();
+ void mirroredChanged();
+
+private:
+ friend class QSGItemPrivate;
+ Q_DISABLE_COPY(QSGAnchors)
+ Q_DECLARE_PRIVATE(QSGAnchors)
+};
+Q_DECLARE_OPERATORS_FOR_FLAGS(QSGAnchors::Anchors)
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QSGAnchors)
+
+QT_END_HEADER
+
+#endif // QSGANCHORS_P_H
diff --git a/src/declarative/items/qsganchors_p_p.h b/src/declarative/items/qsganchors_p_p.h
new file mode 100644
index 0000000000..cb9b950c8f
--- /dev/null
+++ b/src/declarative/items/qsganchors_p_p.h
@@ -0,0 +1,173 @@
+// Commit: 2c7cab4172f1acc86fd49345a2847417e162f2c3
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGANCHORS_P_P_H
+#define QSGANCHORS_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 "qsganchors_p.h"
+#include "qsgitemchangelistener_p.h"
+#include <private/qobject_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QSGAnchorLine
+{
+public:
+ QSGAnchorLine() : item(0), anchorLine(Invalid) {}
+
+ enum AnchorLine {
+ Invalid = 0x0,
+ Left = 0x01,
+ Right = 0x02,
+ Top = 0x04,
+ Bottom = 0x08,
+ HCenter = 0x10,
+ VCenter = 0x20,
+ Baseline = 0x40,
+ Horizontal_Mask = Left | Right | HCenter,
+ Vertical_Mask = Top | Bottom | VCenter | Baseline
+ };
+
+ QSGItem *item;
+ AnchorLine anchorLine;
+};
+
+inline bool operator==(const QSGAnchorLine& a, const QSGAnchorLine& b)
+{
+ return a.item == b.item && a.anchorLine == b.anchorLine;
+}
+
+class QSGAnchorsPrivate : public QObjectPrivate, public QSGItemChangeListener
+{
+ Q_DECLARE_PUBLIC(QSGAnchors)
+public:
+ QSGAnchorsPrivate(QSGItem *i)
+ : componentComplete(true), updatingMe(false), updatingHorizontalAnchor(0),
+ updatingVerticalAnchor(0), updatingFill(0), updatingCenterIn(0), item(i), usedAnchors(0), fill(0),
+ centerIn(0), leftMargin(0), rightMargin(0), topMargin(0), bottomMargin(0),
+ margins(0), vCenterOffset(0), hCenterOffset(0), baselineOffset(0)
+ {
+ }
+
+ void clearItem(QSGItem *);
+
+ void addDepend(QSGItem *);
+ void remDepend(QSGItem *);
+ bool isItemComplete() const;
+
+ bool componentComplete:1;
+ bool updatingMe:1;
+ uint updatingHorizontalAnchor:2;
+ uint updatingVerticalAnchor:2;
+ uint updatingFill:2;
+ uint updatingCenterIn:2;
+
+ void setItemHeight(qreal);
+ void setItemWidth(qreal);
+ void setItemX(qreal);
+ void setItemY(qreal);
+ void setItemPos(const QPointF &);
+ void setItemSize(const QSizeF &);
+
+ void updateOnComplete();
+ void updateMe();
+
+ // QSGItemGeometryListener interface
+ void itemGeometryChanged(QSGItem *, const QRectF &, const QRectF &);
+ QSGAnchorsPrivate *anchorPrivate() { return this; }
+
+ bool checkHValid() const;
+ bool checkVValid() const;
+ bool checkHAnchorValid(QSGAnchorLine anchor) const;
+ bool checkVAnchorValid(QSGAnchorLine anchor) const;
+ bool calcStretch(const QSGAnchorLine &edge1, const QSGAnchorLine &edge2, qreal offset1, qreal offset2, QSGAnchorLine::AnchorLine line, qreal &stretch);
+
+ bool isMirrored() const;
+ void updateHorizontalAnchors();
+ void updateVerticalAnchors();
+ void fillChanged();
+ void centerInChanged();
+
+ QSGItem *item;
+ QSGAnchors::Anchors usedAnchors;
+
+ QSGItem *fill;
+ QSGItem *centerIn;
+
+ QSGAnchorLine left;
+ QSGAnchorLine right;
+ QSGAnchorLine top;
+ QSGAnchorLine bottom;
+ QSGAnchorLine vCenter;
+ QSGAnchorLine hCenter;
+ QSGAnchorLine baseline;
+
+ qreal leftMargin;
+ qreal rightMargin;
+ qreal topMargin;
+ qreal bottomMargin;
+ qreal margins;
+ qreal vCenterOffset;
+ qreal hCenterOffset;
+ qreal baselineOffset;
+
+ static inline QSGAnchorsPrivate *get(QSGAnchors *o) {
+ return static_cast<QSGAnchorsPrivate *>(QObjectPrivate::get(o));
+ }
+};
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(QSGAnchorLine)
+
+#endif
diff --git a/src/declarative/items/qsganimatedimage.cpp b/src/declarative/items/qsganimatedimage.cpp
new file mode 100644
index 0000000000..f036042ce2
--- /dev/null
+++ b/src/declarative/items/qsganimatedimage.cpp
@@ -0,0 +1,304 @@
+// Commit: af33f9f2e7ec433b81f5c18e3e7395db4a56c5fe
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsganimatedimage_p.h"
+#include "qsganimatedimage_p_p.h"
+
+#ifndef QT_NO_MOVIE
+
+#include <QtDeclarative/qdeclarativeinfo.h>
+#include <QtGui/qmovie.h>
+#include <QtNetwork/qnetworkrequest.h>
+#include <QtNetwork/qnetworkreply.h>
+
+#include <private/qdeclarativeengine_p.h>
+
+QT_BEGIN_NAMESPACE
+
+QSGAnimatedImage::QSGAnimatedImage(QSGItem *parent)
+ : QSGImage(*(new QSGAnimatedImagePrivate), parent)
+{
+}
+
+QSGAnimatedImage::~QSGAnimatedImage()
+{
+ Q_D(QSGAnimatedImage);
+ delete d->_movie;
+}
+
+bool QSGAnimatedImage::isPaused() const
+{
+ Q_D(const QSGAnimatedImage);
+ if(!d->_movie)
+ return false;
+ return d->_movie->state()==QMovie::Paused;
+}
+
+void QSGAnimatedImage::setPaused(bool pause)
+{
+ Q_D(QSGAnimatedImage);
+ if(pause == d->paused)
+ return;
+ d->paused = pause;
+ if(!d->_movie)
+ return;
+ d->_movie->setPaused(pause);
+}
+
+bool QSGAnimatedImage::isPlaying() const
+{
+ Q_D(const QSGAnimatedImage);
+ if (!d->_movie)
+ return false;
+ return d->_movie->state()!=QMovie::NotRunning;
+}
+
+void QSGAnimatedImage::setPlaying(bool play)
+{
+ Q_D(QSGAnimatedImage);
+ if(play == d->playing)
+ return;
+ d->playing = play;
+ if (!d->_movie)
+ return;
+ if (play)
+ d->_movie->start();
+ else
+ d->_movie->stop();
+}
+
+int QSGAnimatedImage::currentFrame() const
+{
+ Q_D(const QSGAnimatedImage);
+ if (!d->_movie)
+ return d->preset_currentframe;
+ return d->_movie->currentFrameNumber();
+}
+
+void QSGAnimatedImage::setCurrentFrame(int frame)
+{
+ Q_D(QSGAnimatedImage);
+ if (!d->_movie) {
+ d->preset_currentframe = frame;
+ return;
+ }
+ d->_movie->jumpToFrame(frame);
+}
+
+int QSGAnimatedImage::frameCount() const
+{
+ Q_D(const QSGAnimatedImage);
+ if (!d->_movie)
+ return 0;
+ return d->_movie->frameCount();
+}
+
+void QSGAnimatedImage::setSource(const QUrl &url)
+{
+ Q_D(QSGAnimatedImage);
+ if (url == d->url)
+ return;
+
+ delete d->_movie;
+ d->_movie = 0;
+
+ if (d->reply) {
+ d->reply->deleteLater();
+ d->reply = 0;
+ }
+
+ d->url = url;
+ emit sourceChanged(d->url);
+
+ if (isComponentComplete())
+ load();
+}
+
+void QSGAnimatedImage::load()
+{
+ Q_D(QSGAnimatedImage);
+
+ QSGImageBase::Status oldStatus = d->status;
+ qreal oldProgress = d->progress;
+
+ if (d->url.isEmpty()) {
+ delete d->_movie;
+ d->setPixmap(QPixmap());
+ d->progress = 0;
+ d->status = Null;
+ if (d->status != oldStatus)
+ emit statusChanged(d->status);
+ if (d->progress != oldProgress)
+ emit progressChanged(d->progress);
+ } else {
+#ifndef QT_NO_LOCALFILE_OPTIMIZED_QML
+ QString lf = QDeclarativeEnginePrivate::urlToLocalFileOrQrc(d->url);
+ if (!lf.isEmpty()) {
+ //### should be unified with movieRequestFinished
+ d->_movie = new QMovie(lf);
+ if (!d->_movie->isValid()){
+ qmlInfo(this) << "Error Reading Animated Image File " << d->url.toString();
+ delete d->_movie;
+ d->_movie = 0;
+ d->status = Error;
+ if (d->status != oldStatus)
+ emit statusChanged(d->status);
+ return;
+ }
+ connect(d->_movie, SIGNAL(stateChanged(QMovie::MovieState)),
+ this, SLOT(playingStatusChanged()));
+ connect(d->_movie, SIGNAL(frameChanged(int)),
+ this, SLOT(movieUpdate()));
+ d->_movie->setCacheMode(QMovie::CacheAll);
+ if(d->playing)
+ d->_movie->start();
+ else
+ d->_movie->jumpToFrame(0);
+ if(d->paused)
+ d->_movie->setPaused(true);
+ d->setPixmap(d->_movie->currentPixmap());
+ d->status = Ready;
+ d->progress = 1.0;
+ if (d->status != oldStatus)
+ emit statusChanged(d->status);
+ if (d->progress != oldProgress)
+ emit progressChanged(d->progress);
+ return;
+ }
+#endif
+ d->status = Loading;
+ d->progress = 0;
+ emit statusChanged(d->status);
+ emit progressChanged(d->progress);
+ QNetworkRequest req(d->url);
+ req.setAttribute(QNetworkRequest::HttpPipeliningAllowedAttribute, true);
+ d->reply = qmlEngine(this)->networkAccessManager()->get(req);
+ QObject::connect(d->reply, SIGNAL(finished()),
+ this, SLOT(movieRequestFinished()));
+ QObject::connect(d->reply, SIGNAL(downloadProgress(qint64,qint64)),
+ this, SLOT(requestProgress(qint64,qint64)));
+ }
+}
+
+#define ANIMATEDIMAGE_MAXIMUM_REDIRECT_RECURSION 16
+
+void QSGAnimatedImage::movieRequestFinished()
+{
+ Q_D(QSGAnimatedImage);
+
+ d->redirectCount++;
+ if (d->redirectCount < ANIMATEDIMAGE_MAXIMUM_REDIRECT_RECURSION) {
+ QVariant redirect = d->reply->attribute(QNetworkRequest::RedirectionTargetAttribute);
+ if (redirect.isValid()) {
+ QUrl url = d->reply->url().resolved(redirect.toUrl());
+ d->reply->deleteLater();
+ d->reply = 0;
+ setSource(url);
+ return;
+ }
+ }
+ d->redirectCount=0;
+
+ d->_movie = new QMovie(d->reply);
+ if (!d->_movie->isValid()){
+#ifndef QT_NO_DEBUG_STREAM
+ qmlInfo(this) << "Error Reading Animated Image File " << d->url;
+#endif
+ delete d->_movie;
+ d->_movie = 0;
+ d->status = Error;
+ emit statusChanged(d->status);
+ return;
+ }
+ connect(d->_movie, SIGNAL(stateChanged(QMovie::MovieState)),
+ this, SLOT(playingStatusChanged()));
+ connect(d->_movie, SIGNAL(frameChanged(int)),
+ this, SLOT(movieUpdate()));
+ d->_movie->setCacheMode(QMovie::CacheAll);
+ if(d->playing)
+ d->_movie->start();
+ if (d->paused || !d->playing) {
+ d->_movie->jumpToFrame(d->preset_currentframe);
+ d->preset_currentframe = 0;
+ }
+ if(d->paused)
+ d->_movie->setPaused(true);
+ d->setPixmap(d->_movie->currentPixmap());
+ d->status = Ready;
+ emit statusChanged(d->status);
+}
+
+void QSGAnimatedImage::movieUpdate()
+{
+ Q_D(QSGAnimatedImage);
+ d->setPixmap(d->_movie->currentPixmap());
+ emit frameChanged();
+}
+
+void QSGAnimatedImage::playingStatusChanged()
+{
+ Q_D(QSGAnimatedImage);
+ if((d->_movie->state() != QMovie::NotRunning) != d->playing){
+ d->playing = (d->_movie->state() != QMovie::NotRunning);
+ emit playingChanged();
+ }
+ if((d->_movie->state() == QMovie::Paused) != d->paused){
+ d->playing = (d->_movie->state() == QMovie::Paused);
+ emit pausedChanged();
+ }
+}
+
+void QSGAnimatedImage::componentComplete()
+{
+ Q_D(QSGAnimatedImage);
+ QSGItem::componentComplete(); // NOT QSGImage
+ if (d->url.isValid())
+ load();
+ if (!d->reply) {
+ setCurrentFrame(d->preset_currentframe);
+ d->preset_currentframe = 0;
+ }
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_MOVIE
diff --git a/src/declarative/items/qsganimatedimage_p.h b/src/declarative/items/qsganimatedimage_p.h
new file mode 100644
index 0000000000..64319a0f0d
--- /dev/null
+++ b/src/declarative/items/qsganimatedimage_p.h
@@ -0,0 +1,117 @@
+// Commit: 80d0fe9cbd92288a08d5ced8767f1edb651dae37
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGANIMATEDIMAGE_P_H
+#define QSGANIMATEDIMAGE_P_H
+
+#include "qsgimage_p.h"
+
+#ifndef QT_NO_MOVIE
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QMovie;
+class QSGAnimatedImagePrivate;
+
+class Q_AUTOTEST_EXPORT QSGAnimatedImage : public QSGImage
+{
+ Q_OBJECT
+
+ Q_PROPERTY(bool playing READ isPlaying WRITE setPlaying NOTIFY playingChanged)
+ Q_PROPERTY(bool paused READ isPaused WRITE setPaused NOTIFY pausedChanged)
+ Q_PROPERTY(int currentFrame READ currentFrame WRITE setCurrentFrame NOTIFY frameChanged)
+ Q_PROPERTY(int frameCount READ frameCount)
+
+ // read-only for AnimatedImage
+ Q_PROPERTY(QSize sourceSize READ sourceSize NOTIFY sourceSizeChanged)
+
+public:
+ QSGAnimatedImage(QSGItem *parent=0);
+ ~QSGAnimatedImage();
+
+ bool isPlaying() const;
+ void setPlaying(bool play);
+
+ bool isPaused() const;
+ void setPaused(bool pause);
+
+ int currentFrame() const;
+ void setCurrentFrame(int frame);
+
+ int frameCount() const;
+
+ // Extends QSGImage's src property*/
+ virtual void setSource(const QUrl&);
+
+Q_SIGNALS:
+ void playingChanged();
+ void pausedChanged();
+ void frameChanged();
+ void sourceSizeChanged();
+
+private Q_SLOTS:
+ void movieUpdate();
+ void movieRequestFinished();
+ void playingStatusChanged();
+
+protected:
+ virtual void load();
+ void componentComplete();
+
+private:
+ Q_DISABLE_COPY(QSGAnimatedImage)
+ Q_DECLARE_PRIVATE(QSGAnimatedImage)
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QSGAnimatedImage)
+
+QT_END_HEADER
+
+#endif // QT_NO_MOVIE
+
+#endif // QSGANIMATEDIMAGE_P_H
diff --git a/src/declarative/items/qsganimatedimage_p_p.h b/src/declarative/items/qsganimatedimage_p_p.h
new file mode 100644
index 0000000000..560c8c1d43
--- /dev/null
+++ b/src/declarative/items/qsganimatedimage_p_p.h
@@ -0,0 +1,88 @@
+// Commit: ac5c099cc3c5b8c7eec7a49fdeb8a21037230350
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGANIMATEDIMAGE_P_P_H
+#define QSGANIMATEDIMAGE_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 "qsgimage_p_p.h"
+
+#ifndef QT_NO_MOVIE
+
+QT_BEGIN_NAMESPACE
+
+class QMovie;
+class QNetworkReply;
+
+class QSGAnimatedImagePrivate : public QSGImagePrivate
+{
+ Q_DECLARE_PUBLIC(QSGAnimatedImage)
+
+public:
+ QSGAnimatedImagePrivate()
+ : playing(true), paused(false), preset_currentframe(0), _movie(0), reply(0), redirectCount(0)
+ {
+ }
+
+ bool playing;
+ bool paused;
+ int preset_currentframe;
+ QMovie *_movie;
+ QNetworkReply *reply;
+ int redirectCount;
+};
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_MOVIE
+
+#endif // QSGANIMATEDIMAGE_P_P_H
diff --git a/src/declarative/items/qsganimation.cpp b/src/declarative/items/qsganimation.cpp
new file mode 100644
index 0000000000..ad6ed030fd
--- /dev/null
+++ b/src/declarative/items/qsganimation.cpp
@@ -0,0 +1,442 @@
+// Commit: 91501cc9b542de644cd70098a6bc5ff738cdeb49
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsganimation_p.h"
+#include "qsganimation_p_p.h"
+#include "qsgstateoperations_p.h"
+
+#include <QtDeclarative/qdeclarativeinfo.h>
+#include <QtCore/qmath.h>
+#include <QtCore/qsequentialanimationgroup.h>
+#include <QtCore/qparallelanimationgroup.h>
+
+QT_BEGIN_NAMESPACE
+
+QSGParentAnimation::QSGParentAnimation(QObject *parent)
+ : QDeclarativeAnimationGroup(*(new QSGParentAnimationPrivate), parent)
+{
+ Q_D(QSGParentAnimation);
+ d->topLevelGroup = new QSequentialAnimationGroup;
+ QDeclarative_setParent_noEvent(d->topLevelGroup, this);
+
+ d->startAction = new QActionAnimation;
+ QDeclarative_setParent_noEvent(d->startAction, d->topLevelGroup);
+ d->topLevelGroup->addAnimation(d->startAction);
+
+ d->ag = new QParallelAnimationGroup;
+ QDeclarative_setParent_noEvent(d->ag, d->topLevelGroup);
+ d->topLevelGroup->addAnimation(d->ag);
+
+ d->endAction = new QActionAnimation;
+ QDeclarative_setParent_noEvent(d->endAction, d->topLevelGroup);
+ d->topLevelGroup->addAnimation(d->endAction);
+}
+
+QSGParentAnimation::~QSGParentAnimation()
+{
+}
+
+QSGItem *QSGParentAnimation::target() const
+{
+ Q_D(const QSGParentAnimation);
+ return d->target;
+}
+
+void QSGParentAnimation::setTarget(QSGItem *target)
+{
+ Q_D(QSGParentAnimation);
+ if (target == d->target)
+ return;
+
+ d->target = target;
+ emit targetChanged();
+}
+
+QSGItem *QSGParentAnimation::newParent() const
+{
+ Q_D(const QSGParentAnimation);
+ return d->newParent;
+}
+
+void QSGParentAnimation::setNewParent(QSGItem *newParent)
+{
+ Q_D(QSGParentAnimation);
+ if (newParent == d->newParent)
+ return;
+
+ d->newParent = newParent;
+ emit newParentChanged();
+}
+
+QSGItem *QSGParentAnimation::via() const
+{
+ Q_D(const QSGParentAnimation);
+ return d->via;
+}
+
+void QSGParentAnimation::setVia(QSGItem *via)
+{
+ Q_D(QSGParentAnimation);
+ if (via == d->via)
+ return;
+
+ d->via = via;
+ emit viaChanged();
+}
+
+//### mirrors same-named function in QSGItem
+QPointF QSGParentAnimationPrivate::computeTransformOrigin(QSGItem::TransformOrigin origin, qreal width, qreal height) const
+{
+ switch(origin) {
+ default:
+ case QSGItem::TopLeft:
+ return QPointF(0, 0);
+ case QSGItem::Top:
+ return QPointF(width / 2., 0);
+ case QSGItem::TopRight:
+ return QPointF(width, 0);
+ case QSGItem::Left:
+ return QPointF(0, height / 2.);
+ case QSGItem::Center:
+ return QPointF(width / 2., height / 2.);
+ case QSGItem::Right:
+ return QPointF(width, height / 2.);
+ case QSGItem::BottomLeft:
+ return QPointF(0, height);
+ case QSGItem::Bottom:
+ return QPointF(width / 2., height);
+ case QSGItem::BottomRight:
+ return QPointF(width, height);
+ }
+}
+
+void QSGParentAnimation::transition(QDeclarativeStateActions &actions,
+ QDeclarativeProperties &modified,
+ TransitionDirection direction)
+{
+ Q_D(QSGParentAnimation);
+
+ struct QSGParentAnimationData : public QAbstractAnimationAction
+ {
+ QSGParentAnimationData() {}
+ ~QSGParentAnimationData() { qDeleteAll(pc); }
+
+ QDeclarativeStateActions actions;
+ //### reverse should probably apply on a per-action basis
+ bool reverse;
+ QList<QSGParentChange *> pc;
+ virtual void doAction()
+ {
+ for (int ii = 0; ii < actions.count(); ++ii) {
+ const QDeclarativeAction &action = actions.at(ii);
+ if (reverse)
+ action.event->reverse();
+ else
+ action.event->execute();
+ }
+ }
+ };
+
+ QSGParentAnimationData *data = new QSGParentAnimationData;
+ QSGParentAnimationData *viaData = new QSGParentAnimationData;
+
+ bool hasExplicit = false;
+ if (d->target && d->newParent) {
+ data->reverse = false;
+ QDeclarativeAction myAction;
+ QSGParentChange *pc = new QSGParentChange;
+ pc->setObject(d->target);
+ pc->setParent(d->newParent);
+ myAction.event = pc;
+ data->pc << pc;
+ data->actions << myAction;
+ hasExplicit = true;
+ if (d->via) {
+ viaData->reverse = false;
+ QDeclarativeAction myVAction;
+ QSGParentChange *vpc = new QSGParentChange;
+ vpc->setObject(d->target);
+ vpc->setParent(d->via);
+ myVAction.event = vpc;
+ viaData->pc << vpc;
+ viaData->actions << myVAction;
+ }
+ //### once actions have concept of modified,
+ // loop to match appropriate ParentChanges and mark as modified
+ }
+
+ if (!hasExplicit)
+ for (int i = 0; i < actions.size(); ++i) {
+ QDeclarativeAction &action = actions[i];
+ if (action.event && action.event->typeName() == QLatin1String("ParentChange")
+ && (!d->target || static_cast<QSGParentChange*>(action.event)->object() == d->target)) {
+
+ QSGParentChange *pc = static_cast<QSGParentChange*>(action.event);
+ QDeclarativeAction myAction = action;
+ data->reverse = action.reverseEvent;
+
+ //### this logic differs from PropertyAnimation
+ // (probably a result of modified vs. done)
+ if (d->newParent) {
+ QSGParentChange *epc = new QSGParentChange;
+ epc->setObject(static_cast<QSGParentChange*>(action.event)->object());
+ epc->setParent(d->newParent);
+ myAction.event = epc;
+ data->pc << epc;
+ data->actions << myAction;
+ pc = epc;
+ } else {
+ action.actionDone = true;
+ data->actions << myAction;
+ }
+
+ if (d->via) {
+ viaData->reverse = false;
+ QDeclarativeAction myAction;
+ QSGParentChange *vpc = new QSGParentChange;
+ vpc->setObject(pc->object());
+ vpc->setParent(d->via);
+ myAction.event = vpc;
+ viaData->pc << vpc;
+ viaData->actions << myAction;
+ QDeclarativeAction dummyAction;
+ QDeclarativeAction &xAction = pc->xIsSet() && i < actions.size()-1 ? actions[++i] : dummyAction;
+ QDeclarativeAction &yAction = pc->yIsSet() && i < actions.size()-1 ? actions[++i] : dummyAction;
+ QDeclarativeAction &sAction = pc->scaleIsSet() && i < actions.size()-1 ? actions[++i] : dummyAction;
+ QDeclarativeAction &rAction = pc->rotationIsSet() && i < actions.size()-1 ? actions[++i] : dummyAction;
+ QSGItem *target = pc->object();
+ QSGItem *targetParent = action.reverseEvent ? pc->originalParent() : pc->parent();
+
+ //### this mirrors the logic in QSGParentChange.
+ bool ok;
+ const QTransform &transform = targetParent->itemTransform(d->via, &ok);
+ if (transform.type() >= QTransform::TxShear || !ok) {
+ qmlInfo(this) << QSGParentAnimation::tr("Unable to preserve appearance under complex transform");
+ ok = false;
+ }
+
+ qreal scale = 1;
+ qreal rotation = 0;
+ bool isRotate = (transform.type() == QTransform::TxRotate) || (transform.m11() < 0);
+ if (ok && !isRotate) {
+ if (transform.m11() == transform.m22())
+ scale = transform.m11();
+ else {
+ qmlInfo(this) << QSGParentAnimation::tr("Unable to preserve appearance under non-uniform scale");
+ ok = false;
+ }
+ } else if (ok && isRotate) {
+ if (transform.m11() == transform.m22())
+ scale = qSqrt(transform.m11()*transform.m11() + transform.m12()*transform.m12());
+ else {
+ qmlInfo(this) << QSGParentAnimation::tr("Unable to preserve appearance under non-uniform scale");
+ ok = false;
+ }
+
+ if (scale != 0)
+ rotation = atan2(transform.m12()/scale, transform.m11()/scale) * 180/M_PI;
+ else {
+ qmlInfo(this) << QSGParentAnimation::tr("Unable to preserve appearance under scale of 0");
+ ok = false;
+ }
+ }
+
+ const QPointF &point = transform.map(QPointF(xAction.toValue.toReal(),yAction.toValue.toReal()));
+ qreal x = point.x();
+ qreal y = point.y();
+ if (ok && target->transformOrigin() != QSGItem::TopLeft) {
+ qreal w = target->width();
+ qreal h = target->height();
+ if (pc->widthIsSet() && i < actions.size() - 1)
+ w = actions[++i].toValue.toReal();
+ if (pc->heightIsSet() && i < actions.size() - 1)
+ h = actions[++i].toValue.toReal();
+ const QPointF &transformOrigin
+ = d->computeTransformOrigin(target->transformOrigin(), w,h);
+ qreal tempxt = transformOrigin.x();
+ qreal tempyt = transformOrigin.y();
+ QTransform t;
+ t.translate(-tempxt, -tempyt);
+ t.rotate(rotation);
+ t.scale(scale, scale);
+ t.translate(tempxt, tempyt);
+ const QPointF &offset = t.map(QPointF(0,0));
+ x += offset.x();
+ y += offset.y();
+ }
+
+ if (ok) {
+ //qDebug() << x << y << rotation << scale;
+ xAction.toValue = x;
+ yAction.toValue = y;
+ sAction.toValue = sAction.toValue.toReal() * scale;
+ rAction.toValue = rAction.toValue.toReal() + rotation;
+ }
+ }
+ }
+ }
+
+ if (data->actions.count()) {
+ if (direction == QDeclarativeAbstractAnimation::Forward) {
+ d->startAction->setAnimAction(d->via ? viaData : data, QActionAnimation::DeleteWhenStopped);
+ d->endAction->setAnimAction(d->via ? data : 0, QActionAnimation::DeleteWhenStopped);
+ } else {
+ d->endAction->setAnimAction(d->via ? viaData : data, QActionAnimation::DeleteWhenStopped);
+ d->startAction->setAnimAction(d->via ? data : 0, QActionAnimation::DeleteWhenStopped);
+ }
+ } else {
+ delete data;
+ delete viaData;
+ }
+
+ //take care of any child animations
+ bool valid = d->defaultProperty.isValid();
+ for (int ii = 0; ii < d->animations.count(); ++ii) {
+ if (valid)
+ d->animations.at(ii)->setDefaultTarget(d->defaultProperty);
+ d->animations.at(ii)->transition(actions, modified, direction);
+ }
+
+}
+
+QAbstractAnimation *QSGParentAnimation::qtAnimation()
+{
+ Q_D(QSGParentAnimation);
+ return d->topLevelGroup;
+}
+
+QSGAnchorAnimation::QSGAnchorAnimation(QObject *parent)
+: QDeclarativeAbstractAnimation(*(new QSGAnchorAnimationPrivate), parent)
+{
+ Q_D(QSGAnchorAnimation);
+ d->va = new QDeclarativeBulkValueAnimator;
+ QDeclarative_setParent_noEvent(d->va, this);
+}
+
+QSGAnchorAnimation::~QSGAnchorAnimation()
+{
+}
+
+QAbstractAnimation *QSGAnchorAnimation::qtAnimation()
+{
+ Q_D(QSGAnchorAnimation);
+ return d->va;
+}
+
+QDeclarativeListProperty<QSGItem> QSGAnchorAnimation::targets()
+{
+ Q_D(QSGAnchorAnimation);
+ return QDeclarativeListProperty<QSGItem>(this, d->targets);
+}
+
+int QSGAnchorAnimation::duration() const
+{
+ Q_D(const QSGAnchorAnimation);
+ return d->va->duration();
+}
+
+void QSGAnchorAnimation::setDuration(int duration)
+{
+ if (duration < 0) {
+ qmlInfo(this) << tr("Cannot set a duration of < 0");
+ return;
+ }
+
+ Q_D(QSGAnchorAnimation);
+ if (d->va->duration() == duration)
+ return;
+ d->va->setDuration(duration);
+ emit durationChanged(duration);
+}
+
+QEasingCurve QSGAnchorAnimation::easing() const
+{
+ Q_D(const QSGAnchorAnimation);
+ return d->va->easingCurve();
+}
+
+void QSGAnchorAnimation::setEasing(const QEasingCurve &e)
+{
+ Q_D(QSGAnchorAnimation);
+ if (d->va->easingCurve() == e)
+ return;
+
+ d->va->setEasingCurve(e);
+ emit easingChanged(e);
+}
+
+void QSGAnchorAnimation::transition(QDeclarativeStateActions &actions,
+ QDeclarativeProperties &modified,
+ TransitionDirection direction)
+{
+ Q_UNUSED(modified);
+ Q_D(QSGAnchorAnimation);
+ QDeclarativeAnimationPropertyUpdater *data = new QDeclarativeAnimationPropertyUpdater;
+ data->interpolatorType = QMetaType::QReal;
+ data->interpolator = d->interpolator;
+
+ data->reverse = direction == Backward ? true : false;
+ data->fromSourced = false;
+ data->fromDefined = false;
+
+ for (int ii = 0; ii < actions.count(); ++ii) {
+ QDeclarativeAction &action = actions[ii];
+ if (action.event && action.event->typeName() == QLatin1String("AnchorChanges")
+ && (d->targets.isEmpty() || d->targets.contains(static_cast<QSGAnchorChanges*>(action.event)->object()))) {
+ data->actions << static_cast<QSGAnchorChanges*>(action.event)->additionalActions();
+ }
+ }
+
+ if (data->actions.count()) {
+ if (!d->rangeIsSet) {
+ d->va->setStartValue(qreal(0));
+ d->va->setEndValue(qreal(1));
+ d->rangeIsSet = true;
+ }
+ d->va->setAnimValue(data, QAbstractAnimation::DeleteWhenStopped);
+ d->va->setFromSourcedValue(&data->fromSourced);
+ } else {
+ delete data;
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/items/qsganimation_p.h b/src/declarative/items/qsganimation_p.h
new file mode 100644
index 0000000000..7c63331cfe
--- /dev/null
+++ b/src/declarative/items/qsganimation_p.h
@@ -0,0 +1,132 @@
+// Commit: e39a2e39451bf106a9845f8a60fc571faaa4dde5
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGANIMATION_H
+#define QSGANIMATION_H
+
+#include "qsgitem.h"
+
+#include <private/qdeclarativeanimation_p.h>
+
+#include <QtCore/qabstractanimation.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QSGParentAnimationPrivate;
+class QSGParentAnimation : public QDeclarativeAnimationGroup
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QSGParentAnimation)
+
+ Q_PROPERTY(QSGItem *target READ target WRITE setTarget NOTIFY targetChanged)
+ Q_PROPERTY(QSGItem *newParent READ newParent WRITE setNewParent NOTIFY newParentChanged)
+ Q_PROPERTY(QSGItem *via READ via WRITE setVia NOTIFY viaChanged)
+
+public:
+ QSGParentAnimation(QObject *parent=0);
+ virtual ~QSGParentAnimation();
+
+ QSGItem *target() const;
+ void setTarget(QSGItem *);
+
+ QSGItem *newParent() const;
+ void setNewParent(QSGItem *);
+
+ QSGItem *via() const;
+ void setVia(QSGItem *);
+
+Q_SIGNALS:
+ void targetChanged();
+ void newParentChanged();
+ void viaChanged();
+
+protected:
+ virtual void transition(QDeclarativeStateActions &actions,
+ QDeclarativeProperties &modified,
+ TransitionDirection direction);
+ virtual QAbstractAnimation *qtAnimation();
+};
+
+class QSGAnchorAnimationPrivate;
+class QSGAnchorAnimation : public QDeclarativeAbstractAnimation
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QSGAnchorAnimation)
+ Q_PROPERTY(QDeclarativeListProperty<QSGItem> targets READ targets)
+ Q_PROPERTY(int duration READ duration WRITE setDuration NOTIFY durationChanged)
+ Q_PROPERTY(QEasingCurve easing READ easing WRITE setEasing NOTIFY easingChanged)
+
+public:
+ QSGAnchorAnimation(QObject *parent=0);
+ virtual ~QSGAnchorAnimation();
+
+ QDeclarativeListProperty<QSGItem> targets();
+
+ int duration() const;
+ void setDuration(int);
+
+ QEasingCurve easing() const;
+ void setEasing(const QEasingCurve &);
+
+Q_SIGNALS:
+ void durationChanged(int);
+ void easingChanged(const QEasingCurve&);
+
+protected:
+ virtual void transition(QDeclarativeStateActions &actions,
+ QDeclarativeProperties &modified,
+ TransitionDirection direction);
+ virtual QAbstractAnimation *qtAnimation();
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QSGParentAnimation)
+QML_DECLARE_TYPE(QSGAnchorAnimation)
+
+QT_END_HEADER
+
+#endif // QSGANIMATION_H
diff --git a/src/declarative/items/qsganimation_p_p.h b/src/declarative/items/qsganimation_p_p.h
new file mode 100644
index 0000000000..10457d6b52
--- /dev/null
+++ b/src/declarative/items/qsganimation_p_p.h
@@ -0,0 +1,97 @@
+// Commit: 0ade09152067324f74678f2de4d447b6e0280600
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGANIMATION_P_H
+#define QSGANIMATION_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 "qsganimation_p.h"
+
+#include <private/qdeclarativeanimation_p_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QSGParentAnimationPrivate : public QDeclarativeAnimationGroupPrivate
+{
+ Q_DECLARE_PUBLIC(QSGParentAnimation)
+public:
+ QSGParentAnimationPrivate()
+ : QDeclarativeAnimationGroupPrivate(), target(0), newParent(0),
+ via(0), topLevelGroup(0), startAction(0), endAction(0) {}
+
+ QSGItem *target;
+ QSGItem *newParent;
+ QSGItem *via;
+
+ QSequentialAnimationGroup *topLevelGroup;
+ QActionAnimation *startAction;
+ QActionAnimation *endAction;
+
+ QPointF computeTransformOrigin(QSGItem::TransformOrigin origin, qreal width, qreal height) const;
+};
+
+class QSGAnchorAnimationPrivate : public QDeclarativeAbstractAnimationPrivate
+{
+ Q_DECLARE_PUBLIC(QSGAnchorAnimation)
+public:
+ QSGAnchorAnimationPrivate() : rangeIsSet(false), va(0),
+ interpolator(QVariantAnimationPrivate::getInterpolator(QMetaType::QReal)) {}
+
+ bool rangeIsSet;
+ QDeclarativeBulkValueAnimator *va;
+ QVariantAnimation::Interpolator interpolator;
+ QList<QSGItem*> targets;
+};
+
+QT_END_NAMESPACE
+
+#endif // QSGANIMATION_P_H
diff --git a/src/declarative/items/qsgborderimage.cpp b/src/declarative/items/qsgborderimage.cpp
new file mode 100644
index 0000000000..81df0a31e7
--- /dev/null
+++ b/src/declarative/items/qsgborderimage.cpp
@@ -0,0 +1,362 @@
+// Commit: 462429f5692f810bdd4e04b916db5f9af428d9e4
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgborderimage_p.h"
+#include "qsgborderimage_p_p.h"
+#include "qsgninepatchnode_p.h"
+
+#include <QtDeclarative/qdeclarativeinfo.h>
+#include <QtCore/qfile.h>
+
+#include <private/qdeclarativeengine_p.h>
+
+QT_BEGIN_NAMESPACE
+
+QSGBorderImage::QSGBorderImage(QSGItem *parent)
+: QSGImageBase(*(new QSGBorderImagePrivate), parent)
+{
+}
+
+QSGBorderImage::~QSGBorderImage()
+{
+ Q_D(QSGBorderImage);
+ if (d->sciReply)
+ d->sciReply->deleteLater();
+}
+
+void QSGBorderImage::setSource(const QUrl &url)
+{
+ Q_D(QSGBorderImage);
+ //equality is fairly expensive, so we bypass for simple, common case
+ if ((d->url.isEmpty() == url.isEmpty()) && url == d->url)
+ return;
+
+ if (d->sciReply) {
+ d->sciReply->deleteLater();
+ d->sciReply = 0;
+ }
+
+ d->url = url;
+ d->sciurl = QUrl();
+ emit sourceChanged(d->url);
+
+ if (isComponentComplete())
+ load();
+}
+
+void QSGBorderImage::load()
+{
+ Q_D(QSGBorderImage);
+ if (d->progress != 0.0) {
+ d->progress = 0.0;
+ emit progressChanged(d->progress);
+ }
+
+ if (d->url.isEmpty()) {
+ d->pix.clear(this);
+ d->status = Null;
+ setImplicitWidth(0);
+ setImplicitHeight(0);
+ emit statusChanged(d->status);
+ update();
+ } else {
+ d->status = Loading;
+ if (d->url.path().endsWith(QLatin1String("sci"))) {
+#ifndef QT_NO_LOCALFILE_OPTIMIZED_QML
+ QString lf = QDeclarativeEnginePrivate::urlToLocalFileOrQrc(d->url);
+ if (!lf.isEmpty()) {
+ QFile file(lf);
+ file.open(QIODevice::ReadOnly);
+ setGridScaledImage(QSGGridScaledImage(&file));
+ } else
+#endif
+ {
+ QNetworkRequest req(d->url);
+ d->sciReply = qmlEngine(this)->networkAccessManager()->get(req);
+
+ static int sciReplyFinished = -1;
+ static int thisSciRequestFinished = -1;
+ if (sciReplyFinished == -1) {
+ sciReplyFinished =
+ QNetworkReply::staticMetaObject.indexOfSignal("finished()");
+ thisSciRequestFinished =
+ QSGBorderImage::staticMetaObject.indexOfSlot("sciRequestFinished()");
+ }
+
+ QMetaObject::connect(d->sciReply, sciReplyFinished, this,
+ thisSciRequestFinished, Qt::DirectConnection);
+ }
+ } else {
+
+ QDeclarativePixmap::Options options;
+ if (d->async)
+ options |= QDeclarativePixmap::Asynchronous;
+ if (d->cache)
+ options |= QDeclarativePixmap::Cache;
+ d->pix.clear(this);
+ d->pix.load(qmlEngine(this), d->url, options);
+
+ if (d->pix.isLoading()) {
+ d->pix.connectFinished(this, SLOT(requestFinished()));
+ d->pix.connectDownloadProgress(this, SLOT(requestProgress(qint64,qint64)));
+ } else {
+ QSize impsize = d->pix.implicitSize();
+ setImplicitWidth(impsize.width());
+ setImplicitHeight(impsize.height());
+
+ if (d->pix.isReady()) {
+ d->status = Ready;
+ } else {
+ d->status = Error;
+ qmlInfo(this) << d->pix.error();
+ }
+
+ d->progress = 1.0;
+ emit statusChanged(d->status);
+ emit progressChanged(d->progress);
+ update();
+ }
+ }
+ }
+
+ emit statusChanged(d->status);
+}
+
+QSGScaleGrid *QSGBorderImage::border()
+{
+ Q_D(QSGBorderImage);
+ return d->getScaleGrid();
+}
+
+QSGBorderImage::TileMode QSGBorderImage::horizontalTileMode() const
+{
+ Q_D(const QSGBorderImage);
+ return d->horizontalTileMode;
+}
+
+void QSGBorderImage::setHorizontalTileMode(TileMode t)
+{
+ Q_D(QSGBorderImage);
+ if (t != d->horizontalTileMode) {
+ d->horizontalTileMode = t;
+ emit horizontalTileModeChanged();
+ update();
+ }
+}
+
+QSGBorderImage::TileMode QSGBorderImage::verticalTileMode() const
+{
+ Q_D(const QSGBorderImage);
+ return d->verticalTileMode;
+}
+
+void QSGBorderImage::setVerticalTileMode(TileMode t)
+{
+ Q_D(QSGBorderImage);
+ if (t != d->verticalTileMode) {
+ d->verticalTileMode = t;
+ emit verticalTileModeChanged();
+ update();
+ }
+}
+
+void QSGBorderImage::setGridScaledImage(const QSGGridScaledImage& sci)
+{
+ Q_D(QSGBorderImage);
+ if (!sci.isValid()) {
+ d->status = Error;
+ emit statusChanged(d->status);
+ } else {
+ QSGScaleGrid *sg = border();
+ sg->setTop(sci.gridTop());
+ sg->setBottom(sci.gridBottom());
+ sg->setLeft(sci.gridLeft());
+ sg->setRight(sci.gridRight());
+ d->horizontalTileMode = sci.horizontalTileRule();
+ d->verticalTileMode = sci.verticalTileRule();
+
+ d->sciurl = d->url.resolved(QUrl(sci.pixmapUrl()));
+
+ QDeclarativePixmap::Options options;
+ if (d->async)
+ options |= QDeclarativePixmap::Asynchronous;
+ if (d->cache)
+ options |= QDeclarativePixmap::Cache;
+ d->pix.clear(this);
+ d->pix.load(qmlEngine(this), d->sciurl, options);
+
+ if (d->pix.isLoading()) {
+ static int thisRequestProgress = -1;
+ static int thisRequestFinished = -1;
+ if (thisRequestProgress == -1) {
+ thisRequestProgress =
+ QSGBorderImage::staticMetaObject.indexOfSlot("requestProgress(qint64,qint64)");
+ thisRequestFinished =
+ QSGBorderImage::staticMetaObject.indexOfSlot("requestFinished()");
+ }
+
+ d->pix.connectFinished(this, thisRequestFinished);
+ d->pix.connectDownloadProgress(this, thisRequestProgress);
+
+ } else {
+
+ QSize impsize = d->pix.implicitSize();
+ setImplicitWidth(impsize.width());
+ setImplicitHeight(impsize.height());
+
+ if (d->pix.isReady()) {
+ d->status = Ready;
+ } else {
+ d->status = Error;
+ qmlInfo(this) << d->pix.error();
+ }
+
+ d->progress = 1.0;
+ emit statusChanged(d->status);
+ emit progressChanged(1.0);
+ update();
+
+ }
+ }
+}
+
+void QSGBorderImage::requestFinished()
+{
+ Q_D(QSGBorderImage);
+
+ QSize impsize = d->pix.implicitSize();
+ if (d->pix.isError()) {
+ d->status = Error;
+ qmlInfo(this) << d->pix.error();
+ } else {
+ d->status = Ready;
+ }
+
+ setImplicitWidth(impsize.width());
+ setImplicitHeight(impsize.height());
+
+ if (d->sourcesize.width() != d->pix.width() || d->sourcesize.height() != d->pix.height())
+ emit sourceSizeChanged();
+
+ d->progress = 1.0;
+ emit statusChanged(d->status);
+ emit progressChanged(1.0);
+ update();
+}
+
+#define BORDERIMAGE_MAX_REDIRECT 16
+
+void QSGBorderImage::sciRequestFinished()
+{
+ Q_D(QSGBorderImage);
+
+ d->redirectCount++;
+ if (d->redirectCount < BORDERIMAGE_MAX_REDIRECT) {
+ QVariant redirect = d->sciReply->attribute(QNetworkRequest::RedirectionTargetAttribute);
+ if (redirect.isValid()) {
+ QUrl url = d->sciReply->url().resolved(redirect.toUrl());
+ setSource(url);
+ return;
+ }
+ }
+ d->redirectCount=0;
+
+ if (d->sciReply->error() != QNetworkReply::NoError) {
+ d->status = Error;
+ d->sciReply->deleteLater();
+ d->sciReply = 0;
+ emit statusChanged(d->status);
+ } else {
+ QSGGridScaledImage sci(d->sciReply);
+ d->sciReply->deleteLater();
+ d->sciReply = 0;
+ setGridScaledImage(sci);
+ }
+}
+
+void QSGBorderImage::doUpdate()
+{
+ update();
+}
+
+QSGNode *QSGBorderImage::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
+{
+ Q_D(QSGBorderImage);
+
+ QSGTexture *texture = d->pix.texture(d->sceneGraphContext());
+
+ if (!texture || width() <= 0 || height() <= 0) {
+ delete oldNode;
+ return 0;
+ }
+
+ QSGNinePatchNode *node = static_cast<QSGNinePatchNode *>(oldNode);
+
+ if (!node) {
+ node = new QSGNinePatchNode();
+ }
+
+ node->setTexture(texture);
+
+ const QSGScaleGrid *border = d->getScaleGrid();
+ node->setInnerRect(QRectF(border->left(),
+ border->top(),
+ d->pix.width() - border->right() - border->left(),
+ d->pix.height() - border->bottom() - border->top()));
+ node->setRect(QRectF(0, 0, width(), height()));
+ node->setFiltering(d->smooth ? QSGTexture::Linear : QSGTexture::Nearest);
+ node->setHorzontalTileMode(d->horizontalTileMode);
+ node->setVerticalTileMode(d->verticalTileMode);
+ node->setMirror(d->mirror);
+ node->update();
+
+ return node;
+}
+
+void QSGBorderImage::pixmapChange()
+{
+ Q_D(QSGBorderImage);
+
+ d->pixmapChanged = true;
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/items/qsgborderimage_p.h b/src/declarative/items/qsgborderimage_p.h
new file mode 100644
index 0000000000..1386264779
--- /dev/null
+++ b/src/declarative/items/qsgborderimage_p.h
@@ -0,0 +1,110 @@
+// Commit: ebd4bc73c46c2962742a682b6a391fb68c482aec
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGBORDERIMAGE_P_H
+#define QSGBORDERIMAGE_P_H
+
+#include "qsgimagebase_p.h"
+
+QT_BEGIN_HEADER
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QSGScaleGrid;
+class QSGGridScaledImage;
+class QSGBorderImagePrivate;
+class Q_AUTOTEST_EXPORT QSGBorderImage : public QSGImageBase
+{
+ Q_OBJECT
+ Q_ENUMS(TileMode)
+
+ Q_PROPERTY(QSGScaleGrid *border READ border CONSTANT)
+ Q_PROPERTY(TileMode horizontalTileMode READ horizontalTileMode WRITE setHorizontalTileMode NOTIFY horizontalTileModeChanged)
+ Q_PROPERTY(TileMode verticalTileMode READ verticalTileMode WRITE setVerticalTileMode NOTIFY verticalTileModeChanged)
+ // read-only for BorderImage
+ Q_PROPERTY(QSize sourceSize READ sourceSize NOTIFY sourceSizeChanged)
+
+public:
+ QSGBorderImage(QSGItem *parent=0);
+ ~QSGBorderImage();
+
+ QSGScaleGrid *border();
+
+ enum TileMode { Stretch = Qt::StretchTile, Repeat = Qt::RepeatTile, Round = Qt::RoundTile };
+
+ TileMode horizontalTileMode() const;
+ void setHorizontalTileMode(TileMode);
+
+ TileMode verticalTileMode() const;
+ void setVerticalTileMode(TileMode);
+
+ void setSource(const QUrl &url);
+
+Q_SIGNALS:
+ void horizontalTileModeChanged();
+ void verticalTileModeChanged();
+ void sourceSizeChanged();
+
+protected:
+ virtual void load();
+ virtual void pixmapChange();
+ virtual QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *);
+
+private:
+ void setGridScaledImage(const QSGGridScaledImage& sci);
+
+private Q_SLOTS:
+ void doUpdate();
+ void requestFinished();
+ void sciRequestFinished();
+
+private:
+ Q_DISABLE_COPY(QSGBorderImage)
+ Q_DECLARE_PRIVATE(QSGBorderImage)
+};
+
+QT_END_NAMESPACE
+QML_DECLARE_TYPE(QSGBorderImage)
+QT_END_HEADER
+
+#endif // QSGBORDERIMAGE_P_H
diff --git a/src/declarative/items/qsgborderimage_p_p.h b/src/declarative/items/qsgborderimage_p_p.h
new file mode 100644
index 0000000000..2fb88d9ffd
--- /dev/null
+++ b/src/declarative/items/qsgborderimage_p_p.h
@@ -0,0 +1,109 @@
+// Commit: ac5c099cc3c5b8c7eec7a49fdeb8a21037230350
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGBORDERIMAGE_P_P_H
+#define QSGBORDERIMAGE_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 "qsgimagebase_p_p.h"
+#include "qsgscalegrid_p_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QNetworkReply;
+class QSGBorderImagePrivate : public QSGImageBasePrivate
+{
+ Q_DECLARE_PUBLIC(QSGBorderImage)
+
+public:
+ QSGBorderImagePrivate()
+ : border(0), sciReply(0),
+ horizontalTileMode(QSGBorderImage::Stretch),
+ verticalTileMode(QSGBorderImage::Stretch),
+ redirectCount(0), pixmapChanged(false)
+ {
+ }
+
+ ~QSGBorderImagePrivate()
+ {
+ }
+
+
+ QSGScaleGrid *getScaleGrid()
+ {
+ Q_Q(QSGBorderImage);
+ if (!border) {
+ border = new QSGScaleGrid(q);
+ static int borderChangedSignalIdx = -1;
+ static int doUpdateSlotIdx = -1;
+ if (borderChangedSignalIdx < 0)
+ borderChangedSignalIdx = QSGScaleGrid::staticMetaObject.indexOfSignal("borderChanged()");
+ if (doUpdateSlotIdx < 0)
+ doUpdateSlotIdx = QSGBorderImage::staticMetaObject.indexOfSlot("doUpdate()");
+ QMetaObject::connect(border, borderChangedSignalIdx, q, doUpdateSlotIdx);
+ }
+ return border;
+ }
+
+ QSGScaleGrid *border;
+ QUrl sciurl;
+ QNetworkReply *sciReply;
+ QSGBorderImage::TileMode horizontalTileMode;
+ QSGBorderImage::TileMode verticalTileMode;
+ int redirectCount;
+
+ bool pixmapChanged : 1;
+};
+
+QT_END_NAMESPACE
+
+#endif // QSGBORDERIMAGE_P_P_H
diff --git a/src/declarative/items/qsgcanvas.cpp b/src/declarative/items/qsgcanvas.cpp
new file mode 100644
index 0000000000..16bd8ce44c
--- /dev/null
+++ b/src/declarative/items/qsgcanvas.cpp
@@ -0,0 +1,1934 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgcanvas.h"
+#include "qsgcanvas_p.h"
+
+#include "qsgitem.h"
+#include "qsgitem_p.h"
+
+#include <private/qsgrenderer_p.h>
+#include <private/qsgflashnode_p.h>
+
+#include <private/qabstractanimation_p.h>
+
+#include <QtGui/qpainter.h>
+#include <QtGui/qgraphicssceneevent.h>
+#include <QtGui/qmatrix4x4.h>
+#include <QtGui/qinputcontext.h>
+#include <QtCore/qvarlengtharray.h>
+#include <QtCore/qabstractanimation.h>
+
+#include <private/qdeclarativedebugtrace_p.h>
+
+QT_BEGIN_NAMESPACE
+
+DEFINE_BOOL_CONFIG_OPTION(qmlNoThreadedRenderer, QML_NO_THREADED_RENDERER)
+DEFINE_BOOL_CONFIG_OPTION(qmlFixedAnimationStep, QML_FIXED_ANIMATION_STEP)
+
+/*
+Focus behavior
+==============
+
+Prior to being added to a valid canvas items can set and clear focus with no
+effect. Only once items are added to a canvas (by way of having a parent set that
+already belongs to a canvas) do the focus rules apply. Focus goes back to
+having no effect if an item is removed from a canvas.
+
+When an item is moved into a new focus scope (either being added to a canvas
+for the first time, or having its parent changed), if the focus scope already has
+a scope focused item that takes precedence over the item being added. Otherwise,
+the focus of the added tree is used. In the case of of a tree of items being
+added to a canvas for the first time, which may have a conflicted focus state (two
+or more items in one scope having focus set), the same rule is applied item by item -
+thus the first item that has focus will get it (assuming the scope doesn't already
+have a scope focused item), and the other items will have their focus cleared.
+*/
+
+// #define FOCUS_DEBUG
+// #define MOUSE_DEBUG
+// #define TOUCH_DEBUG
+// #define DIRTY_DEBUG
+// #define THREAD_DEBUG
+
+// #define FRAME_TIMING
+
+#ifdef FRAME_TIMING
+static QTime frameTimer;
+int sceneGraphRenderTime;
+int readbackTime;
+#endif
+
+QSGItem::UpdatePaintNodeData::UpdatePaintNodeData()
+: transformNode(0)
+{
+}
+
+QSGRootItem::QSGRootItem()
+{
+}
+
+void QSGCanvasPrivate::stopRenderingThread()
+{
+ if (thread->isRunning()) {
+ mutex.lock();
+ exitThread = true;
+ wait.wakeOne();
+ wait.wait(&mutex);
+ exitThread = false;
+ mutex.unlock();
+ thread->wait();
+ }
+}
+
+void QSGCanvasPrivate::_q_animationStarted()
+{
+#ifdef THREAD_DEBUG
+ qWarning("AnimationDriver: Main Thread: started");
+#endif
+ mutex.lock();
+ animationRunning = true;
+ if (idle)
+ wait.wakeOne();
+ mutex.unlock();
+}
+
+void QSGCanvasPrivate::_q_animationStopped()
+{
+#ifdef THREAD_DEBUG
+ qWarning("AnimationDriver: Main Thread: stopped");
+#endif
+ mutex.lock();
+ animationRunning = false;
+ mutex.unlock();
+}
+
+void QSGCanvas::paintEvent(QPaintEvent *)
+{
+ Q_D(QSGCanvas);
+
+ if (!d->threadedRendering) {
+#ifdef FRAME_TIMING
+ int lastFrame = frameTimer.restart();
+#endif
+
+ if (d->animationDriver->isRunning())
+ d->animationDriver->advance();
+
+#ifdef FRAME_TIMING
+ int animationTime = frameTimer.elapsed();
+#endif
+
+ Q_ASSERT(d->context);
+
+ d->polishItems();
+
+ QDeclarativeDebugTrace::addEvent(QDeclarativeDebugTrace::FramePaint);
+ QDeclarativeDebugTrace::startRange(QDeclarativeDebugTrace::Painting);
+
+#ifdef FRAME_TIMING
+ int polishTime = frameTimer.elapsed();
+#endif
+
+ makeCurrent();
+
+#ifdef FRAME_TIMING
+ int makecurrentTime = frameTimer.elapsed();
+#endif
+
+ d->syncSceneGraph();
+
+#ifdef FRAME_TIMING
+ int syncTime = frameTimer.elapsed();
+#endif
+
+ d->renderSceneGraph();
+
+#ifdef FRAME_TIMING
+ printf("FrameTimes, last=%d, animations=%d, polish=%d, makeCurrent=%d, sync=%d, sgrender=%d, readback=%d, total=%d\n",
+ lastFrame,
+ animationTime,
+ polishTime - animationTime,
+ makecurrentTime - polishTime,
+ syncTime - makecurrentTime,
+ sceneGraphRenderTime - syncTime,
+ readbackTime - sceneGraphRenderTime,
+ frameTimer.elapsed());
+#endif
+
+ QDeclarativeDebugTrace::endRange(QDeclarativeDebugTrace::Painting);
+
+ if (d->animationDriver->isRunning())
+ update();
+ }
+}
+
+void QSGCanvas::resizeEvent(QResizeEvent *e)
+{
+ Q_D(QSGCanvas);
+ if (d->threadedRendering) {
+ d->mutex.lock();
+ QGLWidget::resizeEvent(e);
+ d->widgetSize = e->size();
+ d->mutex.unlock();
+ } else {
+ d->widgetSize = e->size();
+ d->viewportSize = d->widgetSize;
+ QGLWidget::resizeEvent(e);
+ }
+}
+
+void QSGCanvas::showEvent(QShowEvent *e)
+{
+ Q_D(QSGCanvas);
+
+ QGLWidget::showEvent(e);
+
+ if (d->threadedRendering) {
+ d->contextInThread = true;
+ doneCurrent();
+ if (!d->animationDriver) {
+ d->animationDriver = d->context->createAnimationDriver(this);
+ connect(d->animationDriver, SIGNAL(started()), this, SLOT(_q_animationStarted()), Qt::DirectConnection);
+ connect(d->animationDriver, SIGNAL(stopped()), this, SLOT(_q_animationStopped()), Qt::DirectConnection);
+ }
+ d->animationDriver->install();
+ d->mutex.lock();
+ d->thread->start();
+ d->wait.wait(&d->mutex);
+ d->mutex.unlock();
+ } else {
+ makeCurrent();
+
+ if (!d->context || !d->context->isReady()) {
+ d->initializeSceneGraph();
+ d->animationDriver = d->context->createAnimationDriver(this);
+ connect(d->animationDriver, SIGNAL(started()), this, SLOT(update()));
+ }
+
+ d->animationDriver->install();
+ }
+}
+
+void QSGCanvas::hideEvent(QHideEvent *e)
+{
+ Q_D(QSGCanvas);
+
+ if (d->threadedRendering)
+ d->stopRenderingThread();
+
+ d->animationDriver->uninstall();
+
+ QGLWidget::hideEvent(e);
+}
+
+void QSGCanvas::focusOutEvent(QFocusEvent *event)
+{
+ Q_D(QSGCanvas);
+ d->rootItem->setFocus(false);
+ QGLWidget::focusOutEvent(event);
+}
+
+void QSGCanvas::focusInEvent(QFocusEvent *event)
+{
+ Q_D(QSGCanvas);
+ d->rootItem->setFocus(true);
+ QGLWidget::focusInEvent(event);
+}
+
+void QSGCanvasPrivate::initializeSceneGraph()
+{
+ if (!context)
+ context = QSGContext::createDefaultContext();
+
+ if (context->isReady())
+ return;
+
+ QGLContext *glctx = const_cast<QGLContext *>(QGLContext::currentContext());
+ context->initialize(glctx);
+
+ if (!threadedRendering) {
+ Q_Q(QSGCanvas);
+ QObject::connect(context->renderer(), SIGNAL(sceneGraphChanged()), q, SLOT(maybeUpdate()),
+ Qt::DirectConnection);
+ }
+
+ if (!QSGItemPrivate::get(rootItem)->itemNode()->parent()) {
+ context->rootNode()->appendChildNode(QSGItemPrivate::get(rootItem)->itemNode());
+ }
+
+ emit q_func()->sceneGraphInitialized();
+}
+
+void QSGCanvasPrivate::polishItems()
+{
+ while (!itemsToPolish.isEmpty()) {
+ QSet<QSGItem *>::Iterator iter = itemsToPolish.begin();
+ QSGItem *item = *iter;
+ itemsToPolish.erase(iter);
+ QSGItemPrivate::get(item)->polishScheduled = false;
+ item->updatePolish();
+ }
+}
+
+
+void QSGCanvasPrivate::syncSceneGraph()
+{
+ inSync = true;
+ updateDirtyNodes();
+ inSync = false;
+}
+
+
+void QSGCanvasPrivate::renderSceneGraph()
+{
+ QGLContext *glctx = const_cast<QGLContext *>(QGLContext::currentContext());
+
+ context->renderer()->setDeviceRect(QRect(QPoint(0, 0), viewportSize));
+ context->renderer()->setViewportRect(QRect(QPoint(0, 0), viewportSize));
+ context->renderer()->setProjectMatrixToDeviceRect();
+
+ context->renderNextFrame();
+
+#ifdef FRAME_TIMING
+ sceneGraphRenderTime = frameTimer.elapsed();
+#endif
+
+
+#ifdef FRAME_TIMING
+// int pixel;
+// glReadPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &pixel);
+ readbackTime = frameTimer.elapsed();
+#endif
+
+ glctx->swapBuffers();
+}
+
+
+void QSGCanvas::sceneGraphChanged()
+{
+ Q_D(QSGCanvas);
+ d->needsRepaint = true;
+}
+
+
+void QSGCanvasPrivate::runThread()
+{
+#ifdef THREAD_DEBUG
+ qWarning("QSGRenderer: Render thread running");
+#endif
+ Q_Q(QSGCanvas);
+
+ printf("QSGCanvas::runThread(), rendering in a thread...\n");
+
+ q->makeCurrent();
+ initializeSceneGraph();
+
+ QObject::connect(context->renderer(), SIGNAL(sceneGraphChanged()),
+ q, SLOT(sceneGraphChanged()),
+ Qt::DirectConnection);
+
+ mutex.lock();
+ wait.wakeOne(); // Wake the main thread waiting for us to start
+
+ while (true) {
+ QSize s;
+ s = widgetSize;
+
+ if (exitThread)
+ break;
+
+ if (s != viewportSize) {
+ glViewport(0, 0, s.width(), s.height());
+ viewportSize = s;
+ }
+
+#ifdef THREAD_DEBUG
+ qWarning("QSGRenderer: Render Thread: Waiting for main thread to stop");
+#endif
+ QCoreApplication::postEvent(q, new QEvent(QEvent::User));
+ wait.wait(&mutex);
+
+ if (exitThread) {
+#ifdef THREAD_DEBUG
+ qWarning("QSGRenderer: Render Thread: Shutting down...");
+#endif
+ break;
+ }
+
+#ifdef THREAD_DEBUG
+ qWarning("QSGRenderer: Render Thread: Main thread has stopped, syncing scene");
+#endif
+
+ // Do processing while main thread is frozen
+ syncSceneGraph();
+
+#ifdef THREAD_DEBUG
+ qWarning("QSGRenderer: Render Thread: Resuming main thread");
+#endif
+
+ // Read animationRunning while inside the locked section
+ bool continous = animationRunning;
+
+ wait.wakeOne();
+ mutex.unlock();
+
+ bool enterIdle = false;
+ if (needsRepaint) {
+#ifdef THREAD_DEBUG
+ qWarning("QSGRenderer: Render Thread: rendering scene");
+#endif
+ renderSceneGraph();
+ needsRepaint = false;
+ } else if (continous) {
+#ifdef THREAD_DEBUG
+ qWarning("QSGRenderer: Render Thread: waiting a while...");
+#endif
+ MyThread::doWait();
+ } else {
+ enterIdle = true;
+ }
+
+ mutex.lock();
+
+ if (enterIdle) {
+#ifdef THREAD_DEBUG
+ qWarning("QSGRenderer: Render Thread: Nothing has changed, going idle...");
+#endif
+ idle = true;
+ wait.wait(&mutex);
+ idle = false;
+#ifdef THREAD_DEBUG
+ qWarning("QSGRenderer: Render Thread: waking up from idle");
+#endif
+ }
+
+ }
+
+
+#ifdef THREAD_DEBUG
+ qWarning("QSGRenderer: Render Thread: shutting down, waking up main thread");
+#endif
+ wait.wakeOne();
+ mutex.unlock();
+
+ q->doneCurrent();
+}
+
+QSGCanvasPrivate::QSGCanvasPrivate()
+ : rootItem(0)
+ , activeFocusItem(0)
+ , mouseGrabberItem(0)
+ , hoverItem(0)
+ , dirtyItemList(0)
+ , context(0)
+ , contextInThread(false)
+ , threadedRendering(false)
+ , exitThread(false)
+ , animationRunning(false)
+ , idle(false)
+ , needsRepaint(true)
+ , renderThreadAwakened(false)
+ , inSync(false)
+ , thread(new MyThread(this))
+ , animationDriver(0)
+{
+ threadedRendering = !qmlNoThreadedRenderer();
+}
+
+QSGCanvasPrivate::~QSGCanvasPrivate()
+{
+}
+
+void QSGCanvasPrivate::init(QSGCanvas *c)
+{
+ QUnifiedTimer::instance(true)->setConsistentTiming(qmlFixedAnimationStep());
+
+ q_ptr = c;
+
+ Q_Q(QSGCanvas);
+
+ q->setAttribute(Qt::WA_AcceptTouchEvents);
+ q->setFocusPolicy(Qt::StrongFocus);
+
+ rootItem = new QSGRootItem;
+ QSGItemPrivate *rootItemPrivate = QSGItemPrivate::get(rootItem);
+ rootItemPrivate->canvas = q;
+ rootItemPrivate->flags |= QSGItem::ItemIsFocusScope;
+
+ context = QSGContext::createDefaultContext();
+}
+
+void QSGCanvasPrivate::sceneMouseEventForTransform(QGraphicsSceneMouseEvent &sceneEvent,
+ const QTransform &transform)
+{
+ sceneEvent.setPos(transform.map(sceneEvent.scenePos()));
+ sceneEvent.setLastPos(transform.map(sceneEvent.lastScenePos()));
+ for (int ii = 0; ii < 5; ++ii) {
+ if (sceneEvent.buttons() & (1 << ii)) {
+ sceneEvent.setButtonDownPos((Qt::MouseButton)(1 << ii),
+ transform.map(sceneEvent.buttonDownScenePos((Qt::MouseButton)(1 << ii))));
+ }
+ }
+}
+
+void QSGCanvasPrivate::transformTouchPoints(QList<QTouchEvent::TouchPoint> &touchPoints, const QTransform &transform)
+{
+ for (int i=0; i<touchPoints.count(); i++) {
+ QTouchEvent::TouchPoint &touchPoint = touchPoints[i];
+ touchPoint.setRect(transform.mapRect(touchPoint.sceneRect()));
+ touchPoint.setStartPos(transform.map(touchPoint.startScenePos()));
+ touchPoint.setLastPos(transform.map(touchPoint.lastScenePos()));
+ }
+}
+
+QEvent::Type QSGCanvasPrivate::sceneMouseEventTypeFromMouseEvent(QMouseEvent *event)
+{
+ switch(event->type()) {
+ default:
+ Q_ASSERT(!"Unknown event type");
+ case QEvent::MouseButtonPress:
+ return QEvent::GraphicsSceneMousePress;
+ case QEvent::MouseButtonRelease:
+ return QEvent::GraphicsSceneMouseRelease;
+ case QEvent::MouseButtonDblClick:
+ return QEvent::GraphicsSceneMouseDoubleClick;
+ case QEvent::MouseMove:
+ return QEvent::GraphicsSceneMouseMove;
+ }
+}
+
+/*!
+Fill in the data in \a sceneEvent based on \a event. This method leaves the item local positions in
+\a sceneEvent untouched. Use sceneMouseEventForTransform() to fill in those details.
+*/
+void QSGCanvasPrivate::sceneMouseEventFromMouseEvent(QGraphicsSceneMouseEvent &sceneEvent, QMouseEvent *event)
+{
+ Q_Q(QSGCanvas);
+
+ Q_ASSERT(event);
+
+ if (event->type() == QEvent::MouseButtonPress || event->type() == QEvent::MouseButtonDblClick) {
+ if ((event->button() & event->buttons()) == event->buttons()) {
+ lastMousePosition = event->pos();
+ }
+
+ switch (event->button()) {
+ default:
+ Q_ASSERT(!"Unknown button");
+ case Qt::LeftButton:
+ buttonDownPositions[0] = event->pos();
+ break;
+ case Qt::RightButton:
+ buttonDownPositions[1] = event->pos();
+ break;
+ case Qt::MiddleButton:
+ buttonDownPositions[2] = event->pos();
+ break;
+ case Qt::XButton1:
+ buttonDownPositions[3] = event->pos();
+ break;
+ case Qt::XButton2:
+ buttonDownPositions[4] = event->pos();
+ break;
+ }
+ }
+
+ sceneEvent.setScenePos(event->pos());
+ sceneEvent.setScreenPos(event->globalPos());
+ sceneEvent.setLastScenePos(lastMousePosition);
+ sceneEvent.setLastScreenPos(q->mapToGlobal(lastMousePosition));
+ sceneEvent.setButtons(event->buttons());
+ sceneEvent.setButton(event->button());
+ sceneEvent.setModifiers(event->modifiers());
+ sceneEvent.setWidget(q);
+
+ for (int ii = 0; ii < 5; ++ii) {
+ if (sceneEvent.buttons() & (1 << ii)) {
+ sceneEvent.setButtonDownScenePos((Qt::MouseButton)(1 << ii), buttonDownPositions[ii]);
+ sceneEvent.setButtonDownScreenPos((Qt::MouseButton)(1 << ii), q->mapToGlobal(buttonDownPositions[ii]));
+ }
+ }
+
+ lastMousePosition = event->pos();
+}
+
+/*!
+Fill in the data in \a hoverEvent based on \a mouseEvent. This method leaves the item local positions in
+\a hoverEvent untouched (these are filled in later).
+*/
+void QSGCanvasPrivate::sceneHoverEventFromMouseEvent(QGraphicsSceneHoverEvent &hoverEvent, QMouseEvent *mouseEvent)
+{
+ Q_Q(QSGCanvas);
+ hoverEvent.setWidget(q);
+ hoverEvent.setScenePos(mouseEvent->pos());
+ hoverEvent.setScreenPos(mouseEvent->globalPos());
+ if (lastMousePosition.isNull()) lastMousePosition = mouseEvent->pos();
+ hoverEvent.setLastScenePos(lastMousePosition);
+ hoverEvent.setLastScreenPos(q->mapToGlobal(lastMousePosition));
+ hoverEvent.setModifiers(mouseEvent->modifiers());
+ hoverEvent.setAccepted(mouseEvent->isAccepted());
+
+ lastMousePosition = mouseEvent->pos();
+}
+
+/*!
+Translates the data in \a touchEvent to this canvas. This method leaves the item local positions in
+\a touchEvent untouched (these are filled in later).
+*/
+void QSGCanvasPrivate::translateTouchEvent(QTouchEvent *touchEvent)
+{
+ Q_Q(QSGCanvas);
+
+ touchEvent->setWidget(q);
+
+ QList<QTouchEvent::TouchPoint> touchPoints = touchEvent->touchPoints();
+ for (int i = 0; i < touchPoints.count(); ++i) {
+ QTouchEvent::TouchPoint &touchPoint = touchPoints[i];
+
+ touchPoint.setScreenRect(touchPoint.sceneRect());
+ touchPoint.setStartScreenPos(touchPoint.startScenePos());
+ touchPoint.setLastScreenPos(touchPoint.lastScenePos());
+
+ touchPoint.setSceneRect(touchPoint.rect());
+ touchPoint.setStartScenePos(touchPoint.startPos());
+ touchPoint.setLastScenePos(touchPoint.lastPos());
+
+ if (touchPoint.isPrimary())
+ lastMousePosition = touchPoint.pos().toPoint();
+ }
+ touchEvent->setTouchPoints(touchPoints);
+}
+
+void QSGCanvasPrivate::setFocusInScope(QSGItem *scope, QSGItem *item, FocusOptions options)
+{
+ Q_Q(QSGCanvas);
+
+ Q_ASSERT(item);
+ Q_ASSERT(scope || item == rootItem);
+
+#ifdef FOCUS_DEBUG
+ qWarning() << "QSGCanvasPrivate::setFocusInScope():";
+ qWarning() << " scope:" << (QObject *)scope;
+ if (scope)
+ qWarning() << " scopeSubFocusItem:" << (QObject *)QSGItemPrivate::get(scope)->subFocusItem;
+ qWarning() << " item:" << (QObject *)item;
+ qWarning() << " activeFocusItem:" << (QObject *)activeFocusItem;
+#endif
+
+ QSGItemPrivate *scopePrivate = scope ? QSGItemPrivate::get(scope) : 0;
+ QSGItemPrivate *itemPrivate = QSGItemPrivate::get(item);
+
+ QSGItem *oldActiveFocusItem = 0;
+ QSGItem *newActiveFocusItem = 0;
+
+ QVarLengthArray<QSGItem *, 20> changed;
+
+ // Does this change the active focus?
+ if (item == rootItem || scopePrivate->activeFocus) {
+ oldActiveFocusItem = activeFocusItem;
+ newActiveFocusItem = item;
+ while (newActiveFocusItem->isFocusScope() && newActiveFocusItem->scopedFocusItem())
+ newActiveFocusItem = newActiveFocusItem->scopedFocusItem();
+
+ if (oldActiveFocusItem) {
+#ifndef QT_NO_IM
+ if (QInputContext *ic = inputContext())
+ ic->reset();
+#endif
+
+ activeFocusItem = 0;
+ QFocusEvent event(QEvent::FocusOut, Qt::OtherFocusReason);
+ q->sendEvent(oldActiveFocusItem, &event);
+
+ QSGItem *afi = oldActiveFocusItem;
+ while (afi != scope) {
+ if (QSGItemPrivate::get(afi)->activeFocus) {
+ QSGItemPrivate::get(afi)->activeFocus = false;
+ changed << afi;
+ }
+ afi = afi->parentItem();
+ }
+ }
+ }
+
+ if (item != rootItem) {
+ QSGItem *oldSubFocusItem = scopePrivate->subFocusItem;
+ // Correct focus chain in scope
+ if (oldSubFocusItem) {
+ QSGItem *sfi = scopePrivate->subFocusItem->parentItem();
+ while (sfi != scope) {
+ QSGItemPrivate::get(sfi)->subFocusItem = 0;
+ sfi = sfi->parentItem();
+ }
+ }
+ {
+ scopePrivate->subFocusItem = item;
+ QSGItem *sfi = scopePrivate->subFocusItem->parentItem();
+ while (sfi != scope) {
+ QSGItemPrivate::get(sfi)->subFocusItem = item;
+ sfi = sfi->parentItem();
+ }
+ }
+
+ if (oldSubFocusItem) {
+ QSGItemPrivate::get(oldSubFocusItem)->focus = false;
+ changed << oldSubFocusItem;
+ }
+ }
+
+ if (!(options & DontChangeFocusProperty)) {
+ if (item != rootItem || q->hasFocus()) {
+ itemPrivate->focus = true;
+ changed << item;
+ }
+ }
+
+ if (newActiveFocusItem && q->hasFocus()) {
+ activeFocusItem = newActiveFocusItem;
+
+ QSGItemPrivate::get(newActiveFocusItem)->activeFocus = true;
+ changed << newActiveFocusItem;
+
+ QSGItem *afi = newActiveFocusItem->parentItem();
+ while (afi && afi != scope) {
+ if (afi->isFocusScope()) {
+ QSGItemPrivate::get(afi)->activeFocus = true;
+ changed << afi;
+ }
+ afi = afi->parentItem();
+ }
+
+ updateInputMethodData();
+
+ QFocusEvent event(QEvent::FocusIn, Qt::OtherFocusReason);
+ q->sendEvent(newActiveFocusItem, &event);
+ } else {
+ updateInputMethodData();
+ }
+
+ if (!changed.isEmpty())
+ notifyFocusChangesRecur(changed.data(), changed.count() - 1);
+}
+
+void QSGCanvasPrivate::clearFocusInScope(QSGItem *scope, QSGItem *item, FocusOptions options)
+{
+ Q_Q(QSGCanvas);
+
+ Q_UNUSED(item);
+ Q_ASSERT(item);
+ Q_ASSERT(scope || item == rootItem);
+
+#ifdef FOCUS_DEBUG
+ qWarning() << "QSGCanvasPrivate::clearFocusInScope():";
+ qWarning() << " scope:" << (QObject *)scope;
+ qWarning() << " item:" << (QObject *)item;
+ qWarning() << " activeFocusItem:" << (QObject *)activeFocusItem;
+#endif
+
+ QSGItemPrivate *scopePrivate = scope ? QSGItemPrivate::get(scope) : 0;
+
+ QSGItem *oldActiveFocusItem = 0;
+ QSGItem *newActiveFocusItem = 0;
+
+ QVarLengthArray<QSGItem *, 20> changed;
+
+ Q_ASSERT(item == rootItem || item == scopePrivate->subFocusItem);
+
+ // Does this change the active focus?
+ if (item == rootItem || scopePrivate->activeFocus) {
+ oldActiveFocusItem = activeFocusItem;
+ newActiveFocusItem = scope;
+
+ Q_ASSERT(oldActiveFocusItem);
+
+#ifndef QT_NO_IM
+ if (QInputContext *ic = inputContext())
+ ic->reset();
+#endif
+
+ activeFocusItem = 0;
+ QFocusEvent event(QEvent::FocusOut, Qt::OtherFocusReason);
+ q->sendEvent(oldActiveFocusItem, &event);
+
+ QSGItem *afi = oldActiveFocusItem;
+ while (afi != scope) {
+ if (QSGItemPrivate::get(afi)->activeFocus) {
+ QSGItemPrivate::get(afi)->activeFocus = false;
+ changed << afi;
+ }
+ afi = afi->parentItem();
+ }
+ }
+
+ if (item != rootItem) {
+ QSGItem *oldSubFocusItem = scopePrivate->subFocusItem;
+ // Correct focus chain in scope
+ if (oldSubFocusItem) {
+ QSGItem *sfi = scopePrivate->subFocusItem->parentItem();
+ while (sfi != scope) {
+ QSGItemPrivate::get(sfi)->subFocusItem = 0;
+ sfi = sfi->parentItem();
+ }
+ }
+ scopePrivate->subFocusItem = 0;
+
+ if (oldSubFocusItem && !(options & DontChangeFocusProperty)) {
+ QSGItemPrivate::get(oldSubFocusItem)->focus = false;
+ changed << oldSubFocusItem;
+ }
+ } else if (!(options & DontChangeFocusProperty)) {
+ QSGItemPrivate::get(item)->focus = false;
+ changed << item;
+ }
+
+ if (newActiveFocusItem) {
+ Q_ASSERT(newActiveFocusItem == scope);
+ activeFocusItem = scope;
+
+ updateInputMethodData();
+
+ QFocusEvent event(QEvent::FocusIn, Qt::OtherFocusReason);
+ q->sendEvent(newActiveFocusItem, &event);
+ } else {
+ updateInputMethodData();
+ }
+
+ if (!changed.isEmpty())
+ notifyFocusChangesRecur(changed.data(), changed.count() - 1);
+}
+
+void QSGCanvasPrivate::notifyFocusChangesRecur(QSGItem **items, int remaining)
+{
+ QDeclarativeGuard<QSGItem> item(*items);
+
+ if (remaining)
+ notifyFocusChangesRecur(items + 1, remaining - 1);
+
+ if (item) {
+ QSGItemPrivate *itemPrivate = QSGItemPrivate::get(item);
+
+ if (itemPrivate->notifiedFocus != itemPrivate->focus) {
+ itemPrivate->notifiedFocus = itemPrivate->focus;
+ emit item->focusChanged(itemPrivate->focus);
+ }
+
+ if (item && itemPrivate->notifiedActiveFocus != itemPrivate->activeFocus) {
+ itemPrivate->notifiedActiveFocus = itemPrivate->activeFocus;
+ itemPrivate->itemChange(QSGItem::ItemActiveFocusHasChanged, itemPrivate->activeFocus);
+ emit item->activeFocusChanged(itemPrivate->activeFocus);
+ }
+ }
+}
+
+void QSGCanvasPrivate::updateInputMethodData()
+{
+ Q_Q(QSGCanvas);
+ bool enabled = activeFocusItem
+ && (QSGItemPrivate::get(activeFocusItem)->flags & QSGItem::ItemAcceptsInputMethod);
+ q->setAttribute(Qt::WA_InputMethodEnabled, enabled);
+ q->setInputMethodHints(enabled ? activeFocusItem->inputMethodHints() : Qt::ImhNone);
+}
+
+QVariant QSGCanvas::inputMethodQuery(Qt::InputMethodQuery query) const
+{
+ Q_D(const QSGCanvas);
+ if (!d->activeFocusItem || !(QSGItemPrivate::get(d->activeFocusItem)->flags & QSGItem::ItemAcceptsInputMethod))
+ return QVariant();
+ QVariant value = d->activeFocusItem->inputMethodQuery(query);
+
+ //map geometry types
+ QVariant::Type type = value.type();
+ if (type == QVariant::RectF || type == QVariant::Rect) {
+ const QTransform transform = QSGItemPrivate::get(d->activeFocusItem)->itemToCanvasTransform();
+ value = transform.mapRect(value.toRectF());
+ } else if (type == QVariant::PointF || type == QVariant::Point) {
+ const QTransform transform = QSGItemPrivate::get(d->activeFocusItem)->itemToCanvasTransform();
+ value = transform.map(value.toPointF());
+ }
+ return value;
+}
+
+void QSGCanvasPrivate::dirtyItem(QSGItem *)
+{
+ Q_Q(QSGCanvas);
+ q->maybeUpdate();
+}
+
+void QSGCanvasPrivate::cleanup(QSGNode *n)
+{
+ Q_Q(QSGCanvas);
+
+ Q_ASSERT(!cleanupNodeList.contains(n));
+ cleanupNodeList.append(n);
+ q->maybeUpdate();
+}
+
+static QGLFormat tweakFormat(const QGLFormat &format = QGLFormat::defaultFormat())
+{
+ QGLFormat f = format;
+ f.setSwapInterval(1);
+ return f;
+}
+
+QSGCanvas::QSGCanvas(QWidget *parent, Qt::WindowFlags f)
+ : QGLWidget(*(new QSGCanvasPrivate), tweakFormat(), parent, (QGLWidget *) 0, f)
+{
+ Q_D(QSGCanvas);
+
+ d->init(this);
+}
+
+QSGCanvas::QSGCanvas(const QGLFormat &format, QWidget *parent, Qt::WindowFlags f)
+ : QGLWidget(*(new QSGCanvasPrivate), tweakFormat(format), parent, (QGLWidget *) 0, f)
+{
+ Q_D(QSGCanvas);
+
+ d->init(this);
+}
+
+QSGCanvas::QSGCanvas(QSGCanvasPrivate &dd, QWidget *parent, Qt::WindowFlags f)
+: QGLWidget(dd, tweakFormat(), parent, 0, f)
+{
+ Q_D(QSGCanvas);
+
+ d->init(this);
+}
+
+QSGCanvas::QSGCanvas(QSGCanvasPrivate &dd, const QGLFormat &format, QWidget *parent, Qt::WindowFlags f)
+: QGLWidget(dd, tweakFormat(format), parent, 0, f)
+{
+ Q_D(QSGCanvas);
+
+ d->init(this);
+}
+
+QSGCanvas::~QSGCanvas()
+{
+ Q_D(QSGCanvas);
+
+ if (d->threadedRendering) {
+ d->stopRenderingThread();
+ delete d->thread;
+ }
+
+ // ### should we change ~QSGItem to handle this better?
+ // manually cleanup for the root item (item destructor only handles these when an item is parented)
+ QSGItemPrivate *rootItemPrivate = QSGItemPrivate::get(d->rootItem);
+ rootItemPrivate->removeFromDirtyList();
+ rootItemPrivate->canvas = 0;
+
+ delete d->rootItem; d->rootItem = 0;
+ d->cleanupNodes();
+
+
+ // We need to remove all references to textures pointing to "our" QSGContext
+ // from the QDeclarativePixmapCache. Call into the cache to remove the GL / Scene Graph
+ // part of those cache entries.
+ // To "play nice" with other GL apps that are potentially running in the GUI thread,
+ // We get the current context and only temporarily make our own current
+ QGLContext *currentContext = const_cast<QGLContext *>(QGLContext::currentContext());
+ makeCurrent();
+ extern void qt_declarative_pixmapstore_clean(QSGContext *context);
+ qt_declarative_pixmapstore_clean(d->context);
+ delete d->context;
+ if (currentContext)
+ currentContext->makeCurrent();
+}
+
+QSGItem *QSGCanvas::rootItem() const
+{
+ Q_D(const QSGCanvas);
+
+ return d->rootItem;
+}
+
+QSGItem *QSGCanvas::activeFocusItem() const
+{
+ Q_D(const QSGCanvas);
+
+ return d->activeFocusItem;
+}
+
+QSGItem *QSGCanvas::mouseGrabberItem() const
+{
+ Q_D(const QSGCanvas);
+
+ return d->mouseGrabberItem;
+}
+
+
+void QSGCanvasPrivate::clearHover()
+{
+ Q_Q(QSGCanvas);
+ if (!hoverItem)
+ return;
+
+ QGraphicsSceneHoverEvent hoverEvent;
+ hoverEvent.setWidget(q);
+
+ QPoint cursorPos = QCursor::pos();
+ hoverEvent.setScenePos(q->mapFromGlobal(cursorPos));
+ hoverEvent.setLastScenePos(hoverEvent.scenePos());
+ hoverEvent.setScreenPos(cursorPos);
+ hoverEvent.setLastScreenPos(hoverEvent.screenPos());
+
+ QSGItem *item = hoverItem;
+ hoverItem = 0;
+ sendHoverEvent(QEvent::GraphicsSceneHoverLeave, item, &hoverEvent);
+}
+
+
+bool QSGCanvas::event(QEvent *e)
+{
+ Q_D(QSGCanvas);
+
+ if (e->type() == QEvent::User) {
+ Q_ASSERT(d->threadedRendering);
+
+ d->mutex.lock();
+#ifdef THREAD_DEBUG
+ qWarning("QSGRenderer: Main Thread: Stopped");
+#endif
+
+ d->polishItems();
+
+ d->renderThreadAwakened = false;
+
+ d->wait.wakeOne();
+
+ // The thread is exited when the widget has been hidden. We then need to
+ // skip the waiting, otherwise we would be waiting for a wakeup that never
+ // comes.
+ if (d->thread->isRunning())
+ d->wait.wait(&d->mutex);
+#ifdef THREAD_DEBUG
+ qWarning("QSGRenderer: Main Thread: Resumed");
+#endif
+ d->mutex.unlock();
+
+ if (d->animationRunning)
+ d->animationDriver->advance();
+ }
+
+ switch (e->type()) {
+
+ case QEvent::TouchBegin:
+ case QEvent::TouchUpdate:
+ case QEvent::TouchEnd:
+ {
+ QTouchEvent *touch = static_cast<QTouchEvent *>(e);
+ d->translateTouchEvent(touch);
+ d->deliverTouchEvent(touch);
+ if (!touch->isAccepted())
+ return false;
+ }
+ case QEvent::Leave:
+ d->clearHover();
+ d->lastMousePosition = QPoint();
+ break;
+ default:
+ break;
+ }
+
+ return QGLWidget::event(e);
+}
+
+void QSGCanvas::keyPressEvent(QKeyEvent *e)
+{
+ Q_D(QSGCanvas);
+
+ if (d->activeFocusItem)
+ sendEvent(d->activeFocusItem, e);
+}
+
+void QSGCanvas::keyReleaseEvent(QKeyEvent *e)
+{
+ Q_D(QSGCanvas);
+
+ if (d->activeFocusItem)
+ sendEvent(d->activeFocusItem, e);
+}
+
+void QSGCanvas::inputMethodEvent(QInputMethodEvent *e)
+{
+ Q_D(QSGCanvas);
+
+ if (d->activeFocusItem)
+ sendEvent(d->activeFocusItem, e);
+}
+
+bool QSGCanvasPrivate::deliverInitialMousePressEvent(QSGItem *item, QGraphicsSceneMouseEvent *event)
+{
+ Q_Q(QSGCanvas);
+
+ QSGItemPrivate *itemPrivate = QSGItemPrivate::get(item);
+ if (itemPrivate->opacity == 0.0)
+ return false;
+
+ if (itemPrivate->flags & QSGItem::ItemClipsChildrenToShape) {
+ QPointF p = item->mapFromScene(event->scenePos());
+ if (!QRectF(0, 0, item->width(), item->height()).contains(p))
+ return false;
+ }
+
+ QList<QSGItem *> children = itemPrivate->paintOrderChildItems();
+ for (int ii = children.count() - 1; ii >= 0; --ii) {
+ QSGItem *child = children.at(ii);
+ if (!child->isVisible() || !child->isEnabled())
+ continue;
+ if (deliverInitialMousePressEvent(child, event))
+ return true;
+ }
+
+ if (itemPrivate->acceptedMouseButtons & event->button()) {
+ QPointF p = item->mapFromScene(event->scenePos());
+ if (QRectF(0, 0, item->width(), item->height()).contains(p)) {
+ sceneMouseEventForTransform(*event, itemPrivate->canvasToItemTransform());
+ event->accept();
+ mouseGrabberItem = item;
+ q->sendEvent(item, event);
+ if (event->isAccepted())
+ return true;
+ mouseGrabberItem->ungrabMouse();
+ mouseGrabberItem = 0;
+ }
+ }
+
+ return false;
+}
+
+bool QSGCanvasPrivate::deliverMouseEvent(QGraphicsSceneMouseEvent *sceneEvent)
+{
+ Q_Q(QSGCanvas);
+
+ if (!mouseGrabberItem &&
+ sceneEvent->type() == QEvent::GraphicsSceneMousePress &&
+ (sceneEvent->button() & sceneEvent->buttons()) == sceneEvent->buttons()) {
+
+ return deliverInitialMousePressEvent(rootItem, sceneEvent);
+ }
+
+ if (mouseGrabberItem) {
+ QSGItemPrivate *mgPrivate = QSGItemPrivate::get(mouseGrabberItem);
+ sceneMouseEventForTransform(*sceneEvent, mgPrivate->canvasToItemTransform());
+
+ sceneEvent->accept();
+ q->sendEvent(mouseGrabberItem, sceneEvent);
+ if (sceneEvent->isAccepted())
+ return true;
+ }
+
+ return false;
+}
+
+void QSGCanvas::mousePressEvent(QMouseEvent *event)
+{
+ Q_D(QSGCanvas);
+
+#ifdef MOUSE_DEBUG
+ qWarning() << "QSGCanvas::mousePressEvent()" << event->pos() << event->button() << event->buttons();
+#endif
+
+ QGraphicsSceneMouseEvent sceneEvent(d->sceneMouseEventTypeFromMouseEvent(event));
+ d->sceneMouseEventFromMouseEvent(sceneEvent, event);
+
+ d->deliverMouseEvent(&sceneEvent);
+ event->setAccepted(sceneEvent.isAccepted());
+}
+
+void QSGCanvas::mouseReleaseEvent(QMouseEvent *event)
+{
+ Q_D(QSGCanvas);
+
+#ifdef MOUSE_DEBUG
+ qWarning() << "QSGCanvas::mouseReleaseEvent()" << event->pos() << event->button() << event->buttons();
+#endif
+
+ if (!d->mouseGrabberItem) {
+ QGLWidget::mouseReleaseEvent(event);
+ return;
+ }
+
+ QGraphicsSceneMouseEvent sceneEvent(d->sceneMouseEventTypeFromMouseEvent(event));
+ d->sceneMouseEventFromMouseEvent(sceneEvent, event);
+
+ d->deliverMouseEvent(&sceneEvent);
+ event->setAccepted(sceneEvent.isAccepted());
+
+ d->mouseGrabberItem = 0;
+}
+
+void QSGCanvas::mouseDoubleClickEvent(QMouseEvent *event)
+{
+ Q_D(QSGCanvas);
+
+#ifdef MOUSE_DEBUG
+ qWarning() << "QSGCanvas::mouseDoubleClickEvent()" << event->pos() << event->button() << event->buttons();
+#endif
+
+ QGraphicsSceneMouseEvent sceneEvent(d->sceneMouseEventTypeFromMouseEvent(event));
+ d->sceneMouseEventFromMouseEvent(sceneEvent, event);
+
+ if (!d->mouseGrabberItem && (event->button() & event->buttons()) == event->buttons()) {
+ if (d->deliverInitialMousePressEvent(d->rootItem, &sceneEvent))
+ event->accept();
+ else
+ event->ignore();
+ return;
+ }
+
+ d->deliverMouseEvent(&sceneEvent);
+ event->setAccepted(sceneEvent.isAccepted());
+}
+
+void QSGCanvasPrivate::sendHoverEvent(QEvent::Type type, QSGItem *item,
+ QGraphicsSceneHoverEvent *event)
+{
+ Q_Q(QSGCanvas);
+ const QTransform transform = QSGItemPrivate::get(item)->canvasToItemTransform();
+
+ //create copy of event
+ QGraphicsSceneHoverEvent hoverEvent(type);
+ hoverEvent.setWidget(event->widget());
+ hoverEvent.setPos(transform.map(event->scenePos()));
+ hoverEvent.setScenePos(event->scenePos());
+ hoverEvent.setScreenPos(event->screenPos());
+ hoverEvent.setLastPos(transform.map(event->lastScenePos()));
+ hoverEvent.setLastScenePos(event->lastScenePos());
+ hoverEvent.setLastScreenPos(event->lastScreenPos());
+ hoverEvent.setModifiers(event->modifiers());
+ hoverEvent.setAccepted(event->isAccepted());
+
+ q->sendEvent(item, &hoverEvent);
+}
+
+void QSGCanvas::mouseMoveEvent(QMouseEvent *event)
+{
+ Q_D(QSGCanvas);
+
+#ifdef MOUSE_DEBUG
+ qWarning() << "QSGCanvas::mouseMoveEvent()" << event->pos() << event->button() << event->buttons();
+#endif
+
+ if (!d->mouseGrabberItem) {
+ QGraphicsSceneHoverEvent hoverEvent;
+ d->sceneHoverEventFromMouseEvent(hoverEvent, event);
+
+ bool delivered = d->deliverHoverEvent(d->rootItem, &hoverEvent);
+ if (!delivered) {
+ //take care of any exits
+ if (d->hoverItem) {
+ QSGItem *item = d->hoverItem;
+ d->hoverItem = 0;
+ d->sendHoverEvent(QEvent::GraphicsSceneHoverLeave, item, &hoverEvent);
+ }
+ }
+ event->setAccepted(hoverEvent.isAccepted());
+ return;
+ }
+
+ QGraphicsSceneMouseEvent sceneEvent(d->sceneMouseEventTypeFromMouseEvent(event));
+ d->sceneMouseEventFromMouseEvent(sceneEvent, event);
+
+ d->deliverMouseEvent(&sceneEvent);
+ event->setAccepted(sceneEvent.isAccepted());
+}
+
+bool QSGCanvasPrivate::deliverHoverEvent(QSGItem *item, QGraphicsSceneHoverEvent *event)
+{
+ QSGItemPrivate *itemPrivate = QSGItemPrivate::get(item);
+ if (itemPrivate->opacity == 0.0)
+ return false;
+
+ if (itemPrivate->flags & QSGItem::ItemClipsChildrenToShape) {
+ QPointF p = item->mapFromScene(event->scenePos());
+ if (!QRectF(0, 0, item->width(), item->height()).contains(p))
+ return false;
+ }
+
+ QList<QSGItem *> children = itemPrivate->paintOrderChildItems();
+ for (int ii = children.count() - 1; ii >= 0; --ii) {
+ QSGItem *child = children.at(ii);
+ if (!child->isEnabled())
+ continue;
+ if (deliverHoverEvent(child, event))
+ return true;
+ }
+
+ if (itemPrivate->hoverEnabled) {
+ QPointF p = item->mapFromScene(event->scenePos());
+ if (QRectF(0, 0, item->width(), item->height()).contains(p)) {
+ if (hoverItem == item) {
+ //move
+ sendHoverEvent(QEvent::GraphicsSceneHoverMove, item, event);
+ } else {
+ //exit from previous
+ if (hoverItem) {
+ QSGItem *item = hoverItem;
+ hoverItem = 0;
+ sendHoverEvent(QEvent::GraphicsSceneHoverLeave, item, event);
+ }
+
+ //enter new item
+ hoverItem = item;
+ sendHoverEvent(QEvent::GraphicsSceneHoverEnter, item, event);
+ }
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool QSGCanvasPrivate::deliverWheelEvent(QSGItem *item, QGraphicsSceneWheelEvent *event)
+{
+ Q_Q(QSGCanvas);
+ QSGItemPrivate *itemPrivate = QSGItemPrivate::get(item);
+ if (itemPrivate->opacity == 0.0)
+ return false;
+
+ if (itemPrivate->flags & QSGItem::ItemClipsChildrenToShape) {
+ QPointF p = item->mapFromScene(event->scenePos());
+ if (!QRectF(0, 0, item->width(), item->height()).contains(p))
+ return false;
+ }
+
+ QList<QSGItem *> children = itemPrivate->paintOrderChildItems();
+ for (int ii = children.count() - 1; ii >= 0; --ii) {
+ QSGItem *child = children.at(ii);
+ if (!child->isEnabled())
+ continue;
+ if (deliverWheelEvent(child, event))
+ return true;
+ }
+
+ QPointF p = item->mapFromScene(event->scenePos());
+ if (QRectF(0, 0, item->width(), item->height()).contains(p)) {
+ event->setPos(itemPrivate->canvasToItemTransform().map(event->scenePos()));
+ event->accept();
+ q->sendEvent(item, event);
+ if (event->isAccepted())
+ return true;
+ }
+
+ return false;
+}
+
+#ifndef QT_NO_WHEELEVENT
+void QSGCanvas::wheelEvent(QWheelEvent *event)
+{
+ Q_D(QSGCanvas);
+#ifdef MOUSE_DEBUG
+ qWarning() << "QSGCanvas::wheelEvent()" << event->pos() << event->delta() << event->orientation();
+#endif
+ QGraphicsSceneWheelEvent wheelEvent(QEvent::GraphicsSceneWheel);
+ wheelEvent.setWidget(this);
+ wheelEvent.setScenePos(event->pos());
+ wheelEvent.setScreenPos(event->globalPos());
+ wheelEvent.setButtons(event->buttons());
+ wheelEvent.setModifiers(event->modifiers());
+ wheelEvent.setDelta(event->delta());
+ wheelEvent.setOrientation(event->orientation());
+ wheelEvent.setAccepted(false);
+
+ d->deliverWheelEvent(d->rootItem, &wheelEvent);
+ event->setAccepted(wheelEvent.isAccepted());
+}
+#endif // QT_NO_WHEELEVENT
+
+bool QSGCanvasPrivate::deliverTouchEvent(QTouchEvent *event)
+{
+#ifdef TOUCH_DEBUG
+ if (event->type() == QEvent::TouchBegin)
+ qWarning("touchBeginEvent");
+ else if (event->type() == QEvent::TouchUpdate)
+ qWarning("touchUpdateEvent");
+ else if (event->type() == QEvent::TouchEnd)
+ qWarning("touchEndEvent");
+#endif
+
+ QHash<QSGItem *, QList<QTouchEvent::TouchPoint> > updatedPoints;
+
+ if (event->type() == QTouchEvent::TouchBegin) { // all points are new touch points
+ QSet<int> acceptedNewPoints;
+ deliverTouchPoints(rootItem, event, event->touchPoints(), &acceptedNewPoints, &updatedPoints);
+ if (acceptedNewPoints.count() > 0)
+ event->accept();
+ return event->isAccepted();
+ }
+
+ const QList<QTouchEvent::TouchPoint> &touchPoints = event->touchPoints();
+ QList<QTouchEvent::TouchPoint> newPoints;
+ QSGItem *item = 0;
+ for (int i=0; i<touchPoints.count(); i++) {
+ const QTouchEvent::TouchPoint &touchPoint = touchPoints[i];
+ switch (touchPoint.state()) {
+ case Qt::TouchPointPressed:
+ newPoints << touchPoint;
+ break;
+ case Qt::TouchPointMoved:
+ case Qt::TouchPointStationary:
+ case Qt::TouchPointReleased:
+ if (itemForTouchPointId.contains(touchPoint.id())) {
+ item = itemForTouchPointId[touchPoint.id()];
+ if (item)
+ updatedPoints[item].append(touchPoint);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (newPoints.count() > 0 || updatedPoints.count() > 0) {
+ QSet<int> acceptedNewPoints;
+ int prevCount = updatedPoints.count();
+ deliverTouchPoints(rootItem, event, newPoints, &acceptedNewPoints, &updatedPoints);
+ if (acceptedNewPoints.count() > 0 || updatedPoints.count() != prevCount)
+ event->accept();
+ }
+
+ if (event->touchPointStates() & Qt::TouchPointReleased) {
+ for (int i=0; i<touchPoints.count(); i++) {
+ if (touchPoints[i].state() == Qt::TouchPointReleased)
+ itemForTouchPointId.remove(touchPoints[i].id());
+ }
+ }
+
+ return event->isAccepted();
+}
+
+bool QSGCanvasPrivate::deliverTouchPoints(QSGItem *item, QTouchEvent *event, const QList<QTouchEvent::TouchPoint> &newPoints, QSet<int> *acceptedNewPoints, QHash<QSGItem *, QList<QTouchEvent::TouchPoint> > *updatedPoints)
+{
+ Q_Q(QSGCanvas);
+ QSGItemPrivate *itemPrivate = QSGItemPrivate::get(item);
+
+ if (itemPrivate->opacity == 0.0)
+ return false;
+
+ if (itemPrivate->flags & QSGItem::ItemClipsChildrenToShape) {
+ QRectF bounds(0, 0, item->width(), item->height());
+ for (int i=0; i<newPoints.count(); i++) {
+ QPointF p = item->mapFromScene(newPoints[i].scenePos());
+ if (!bounds.contains(p))
+ return false;
+ }
+ }
+
+ QList<QSGItem *> children = itemPrivate->paintOrderChildItems();
+ for (int ii = children.count() - 1; ii >= 0; --ii) {
+ QSGItem *child = children.at(ii);
+ if (!child->isEnabled())
+ continue;
+ if (deliverTouchPoints(child, event, newPoints, acceptedNewPoints, updatedPoints))
+ return true;
+ }
+
+ QList<QTouchEvent::TouchPoint> matchingPoints;
+ if (newPoints.count() > 0 && acceptedNewPoints->count() < newPoints.count()) {
+ QRectF bounds(0, 0, item->width(), item->height());
+ for (int i=0; i<newPoints.count(); i++) {
+ if (acceptedNewPoints->contains(newPoints[i].id()))
+ continue;
+ QPointF p = item->mapFromScene(newPoints[i].scenePos());
+ if (bounds.contains(p))
+ matchingPoints << newPoints[i];
+ }
+ }
+
+ if (matchingPoints.count() > 0 || (*updatedPoints)[item].count() > 0) {
+ QList<QTouchEvent::TouchPoint> &eventPoints = (*updatedPoints)[item];
+ eventPoints.append(matchingPoints);
+ transformTouchPoints(eventPoints, itemPrivate->canvasToItemTransform());
+
+ Qt::TouchPointStates eventStates;
+ for (int i=0; i<eventPoints.count(); i++)
+ eventStates |= eventPoints[i].state();
+ // if all points have the same state, set the event type accordingly
+ QEvent::Type eventType;
+ switch (eventStates) {
+ case Qt::TouchPointPressed:
+ eventType = QEvent::TouchBegin;
+ break;
+ case Qt::TouchPointReleased:
+ eventType = QEvent::TouchEnd;
+ break;
+ default:
+ eventType = QEvent::TouchUpdate;
+ break;
+ }
+
+ if (eventStates != Qt::TouchPointStationary) {
+ QTouchEvent touchEvent(eventType);
+ touchEvent.setWidget(q);
+ touchEvent.setDeviceType(event->deviceType());
+ touchEvent.setModifiers(event->modifiers());
+ touchEvent.setTouchPointStates(eventStates);
+ touchEvent.setTouchPoints(eventPoints);
+
+ touchEvent.accept();
+ q->sendEvent(item, &touchEvent);
+
+ if (touchEvent.isAccepted()) {
+ for (int i=0; i<matchingPoints.count(); i++) {
+ itemForTouchPointId[matchingPoints[i].id()] = item;
+ acceptedNewPoints->insert(matchingPoints[i].id());
+ }
+ }
+ }
+ }
+
+ updatedPoints->remove(item);
+ if (acceptedNewPoints->count() == newPoints.count() && updatedPoints->isEmpty())
+ return true;
+
+ return false;
+}
+
+bool QSGCanvasPrivate::sendFilteredMouseEvent(QSGItem *target, QSGItem *item, QGraphicsSceneMouseEvent *event)
+{
+ if (!target)
+ return false;
+
+ if (sendFilteredMouseEvent(target->parentItem(), item, event))
+ return true;
+
+ QSGItemPrivate *targetPrivate = QSGItemPrivate::get(target);
+ if (targetPrivate->filtersChildMouseEvents)
+ if (target->childMouseEventFilter(item, event))
+ return true;
+
+ return false;
+}
+
+bool QSGCanvas::sendEvent(QSGItem *item, QEvent *e)
+{
+ Q_D(QSGCanvas);
+
+ if (!item) {
+ qWarning("QSGCanvas::sendEvent: Cannot send event to a null item");
+ return false;
+ }
+
+ Q_ASSERT(e);
+
+ switch (e->type()) {
+ case QEvent::KeyPress:
+ case QEvent::KeyRelease:
+ e->accept();
+ QSGItemPrivate::get(item)->deliverKeyEvent(static_cast<QKeyEvent *>(e));
+ while (!e->isAccepted() && (item = item->parentItem())) {
+ e->accept();
+ QSGItemPrivate::get(item)->deliverKeyEvent(static_cast<QKeyEvent *>(e));
+ }
+ break;
+ case QEvent::InputMethod:
+ e->accept();
+ QSGItemPrivate::get(item)->deliverInputMethodEvent(static_cast<QInputMethodEvent *>(e));
+ while (!e->isAccepted() && (item = item->parentItem())) {
+ e->accept();
+ QSGItemPrivate::get(item)->deliverInputMethodEvent(static_cast<QInputMethodEvent *>(e));
+ }
+ break;
+ case QEvent::FocusIn:
+ case QEvent::FocusOut:
+ QSGItemPrivate::get(item)->deliverFocusEvent(static_cast<QFocusEvent *>(e));
+ break;
+ case QEvent::GraphicsSceneMousePress:
+ case QEvent::GraphicsSceneMouseRelease:
+ case QEvent::GraphicsSceneMouseDoubleClick:
+ case QEvent::GraphicsSceneMouseMove:
+ // XXX todo - should sendEvent be doing this? how does it relate to forwarded events?
+ {
+ QGraphicsSceneMouseEvent *se = static_cast<QGraphicsSceneMouseEvent *>(e);
+ if (!d->sendFilteredMouseEvent(item->parentItem(), item, se)) {
+ se->accept();
+ QSGItemPrivate::get(item)->deliverMouseEvent(se);
+ }
+ }
+ break;
+ case QEvent::GraphicsSceneWheel:
+ QSGItemPrivate::get(item)->deliverWheelEvent(static_cast<QGraphicsSceneWheelEvent *>(e));
+ break;
+ case QEvent::GraphicsSceneHoverEnter:
+ case QEvent::GraphicsSceneHoverLeave:
+ case QEvent::GraphicsSceneHoverMove:
+ QSGItemPrivate::get(item)->deliverHoverEvent(static_cast<QGraphicsSceneHoverEvent *>(e));
+ break;
+ case QEvent::TouchBegin:
+ case QEvent::TouchUpdate:
+ case QEvent::TouchEnd:
+ QSGItemPrivate::get(item)->deliverTouchEvent(static_cast<QTouchEvent *>(e));
+ break;
+ default:
+ break;
+ }
+
+ return false;
+}
+
+void QSGCanvasPrivate::cleanupNodes()
+{
+ for (int ii = 0; ii < cleanupNodeList.count(); ++ii)
+ delete cleanupNodeList.at(ii);
+ cleanupNodeList.clear();
+}
+
+void QSGCanvasPrivate::updateDirtyNodes()
+{
+#ifdef DIRTY_DEBUG
+ qWarning() << "QSGCanvasPrivate::updateDirtyNodes():";
+#endif
+
+ cleanupNodes();
+
+ QSGItem *updateList = dirtyItemList;
+ dirtyItemList = 0;
+ if (updateList) QSGItemPrivate::get(updateList)->prevDirtyItem = &updateList;
+
+ while (updateList) {
+ QSGItem *item = updateList;
+ QSGItemPrivate *itemPriv = QSGItemPrivate::get(item);
+ itemPriv->removeFromDirtyList();
+
+#ifdef DIRTY_DEBUG
+ qWarning() << " QSGNode:" << item << qPrintable(itemPriv->dirtyToString());
+#endif
+ updateDirtyNode(item);
+ }
+}
+
+void QSGCanvasPrivate::updateDirtyNode(QSGItem *item)
+{
+#ifdef QML_RUNTIME_TESTING
+ bool didFlash = false;
+#endif
+
+ QSGItemPrivate *itemPriv = QSGItemPrivate::get(item);
+ quint32 dirty = itemPriv->dirtyAttributes;
+ itemPriv->dirtyAttributes = 0;
+
+ if ((dirty & QSGItemPrivate::TransformUpdateMask) ||
+ (dirty & QSGItemPrivate::Size && itemPriv->origin != QSGItem::TopLeft &&
+ (itemPriv->scale != 1. || itemPriv->rotation != 0.))) {
+
+ QMatrix4x4 matrix;
+
+ if (itemPriv->x != 0. || itemPriv->y != 0.)
+ matrix.translate(itemPriv->x, itemPriv->y);
+
+ if (dirty & QSGItemPrivate::ComplexTransformUpdateMask) {
+ for (int ii = itemPriv->transforms.count() - 1; ii >= 0; --ii)
+ itemPriv->transforms.at(ii)->applyTo(&matrix);
+ }
+
+ if (itemPriv->scale != 1. || itemPriv->rotation != 0.) {
+ QPointF origin = itemPriv->computeTransformOrigin();
+ matrix.translate(origin.x(), origin.y());
+ if (itemPriv->scale != 1.)
+ matrix.scale(itemPriv->scale, itemPriv->scale);
+ if (itemPriv->rotation != 0.)
+ matrix.rotate(itemPriv->rotation, 0, 0, 1);
+ matrix.translate(-origin.x(), -origin.y());
+ }
+
+ itemPriv->itemNode()->setMatrix(matrix);
+ }
+
+ bool clipEffectivelyChanged = dirty & QSGItemPrivate::Clip &&
+ ((item->clip() == false) != (itemPriv->clipNode == 0));
+ bool effectRefEffectivelyChanged = dirty & QSGItemPrivate::EffectReference &&
+ ((itemPriv->effectRefCount == 0) != (itemPriv->rootNode == 0));
+
+ if (clipEffectivelyChanged) {
+ QSGNode *parent = itemPriv->opacityNode ? (QSGNode *) itemPriv->opacityNode : (QSGNode *)itemPriv->itemNode();
+ QSGNode *child = itemPriv->rootNode ? (QSGNode *)itemPriv->rootNode : (QSGNode *)itemPriv->groupNode;
+
+ if (item->clip()) {
+ Q_ASSERT(itemPriv->clipNode == 0);
+ itemPriv->clipNode = new QSGDefaultClipNode(QRectF(0, 0, itemPriv->width, itemPriv->height));
+
+ if (child)
+ parent->removeChildNode(child);
+ parent->appendChildNode(itemPriv->clipNode);
+ if (child)
+ itemPriv->clipNode->appendChildNode(child);
+
+ } else {
+ Q_ASSERT(itemPriv->clipNode != 0);
+ parent->removeChildNode(itemPriv->clipNode);
+ if (child)
+ itemPriv->clipNode->removeChildNode(child);
+ delete itemPriv->clipNode;
+ itemPriv->clipNode = 0;
+ if (child)
+ parent->appendChildNode(child);
+ }
+ }
+
+ if (dirty & QSGItemPrivate::ChildrenUpdateMask) {
+ while (itemPriv->childContainerNode()->childCount())
+ itemPriv->childContainerNode()->removeChildNode(itemPriv->childContainerNode()->childAtIndex(0));
+ }
+
+ if (effectRefEffectivelyChanged) {
+ QSGNode *parent = itemPriv->clipNode;
+ if (!parent)
+ parent = itemPriv->opacityNode;
+ if (!parent)
+ parent = itemPriv->itemNode();
+ QSGNode *child = itemPriv->groupNode;
+
+ if (itemPriv->effectRefCount) {
+ Q_ASSERT(itemPriv->rootNode == 0);
+ itemPriv->rootNode = new QSGRootNode;
+
+ if (child)
+ parent->removeChildNode(child);
+ parent->appendChildNode(itemPriv->rootNode);
+ if (child)
+ itemPriv->rootNode->appendChildNode(child);
+ } else {
+ Q_ASSERT(itemPriv->rootNode != 0);
+ parent->removeChildNode(itemPriv->rootNode);
+ if (child)
+ itemPriv->rootNode->removeChildNode(child);
+ delete itemPriv->rootNode;
+ itemPriv->rootNode = 0;
+ if (child)
+ parent->appendChildNode(child);
+ }
+ }
+
+ if (dirty & QSGItemPrivate::ChildrenUpdateMask) {
+ QSGNode *groupNode = itemPriv->groupNode;
+ if (groupNode) {
+ for (int count = groupNode->childCount(); count; --count)
+ groupNode->removeChildNode(groupNode->childAtIndex(0));
+ }
+
+ QList<QSGItem *> orderedChildren = itemPriv->paintOrderChildItems();
+ int ii = 0;
+
+ itemPriv->paintNodeIndex = 0;
+ for (; ii < orderedChildren.count() && orderedChildren.at(ii)->z() < 0; ++ii) {
+ QSGItemPrivate *childPrivate = QSGItemPrivate::get(orderedChildren.at(ii));
+ if (!childPrivate->explicitVisible && !childPrivate->effectRefCount)
+ continue;
+ if (childPrivate->itemNode()->parent())
+ childPrivate->itemNode()->parent()->removeChildNode(childPrivate->itemNode());
+
+ itemPriv->childContainerNode()->appendChildNode(childPrivate->itemNode());
+ itemPriv->paintNodeIndex++;
+ }
+
+ if (itemPriv->paintNode)
+ itemPriv->childContainerNode()->appendChildNode(itemPriv->paintNode);
+
+ for (; ii < orderedChildren.count(); ++ii) {
+ QSGItemPrivate *childPrivate = QSGItemPrivate::get(orderedChildren.at(ii));
+ if (!childPrivate->explicitVisible && !childPrivate->effectRefCount)
+ continue;
+ if (childPrivate->itemNode()->parent())
+ childPrivate->itemNode()->parent()->removeChildNode(childPrivate->itemNode());
+
+ itemPriv->childContainerNode()->appendChildNode(childPrivate->itemNode());
+ }
+ }
+
+ if ((dirty & QSGItemPrivate::Size || clipEffectivelyChanged) && itemPriv->clipNode) {
+ itemPriv->clipNode->setRect(QRectF(0, 0, itemPriv->width, itemPriv->height));
+ itemPriv->clipNode->update();
+ }
+
+ if (dirty & (QSGItemPrivate::OpacityValue | QSGItemPrivate::Visible | QSGItemPrivate::HideReference)) {
+ qreal opacity = itemPriv->explicitVisible && itemPriv->hideRefCount == 0
+ ? itemPriv->opacity : qreal(0);
+
+ if (opacity != 1 && !itemPriv->opacityNode) {
+ itemPriv->opacityNode = new QSGOpacityNode;
+
+ QSGNode *parent = itemPriv->itemNode();
+ QSGNode *child = itemPriv->clipNode;
+ if (!child)
+ child = itemPriv->rootNode;
+ if (!child)
+ child = itemPriv->groupNode;
+
+ if (child)
+ parent->removeChildNode(child);
+ parent->appendChildNode(itemPriv->opacityNode);
+ if (child)
+ itemPriv->opacityNode->appendChildNode(child);
+ }
+ if (itemPriv->opacityNode)
+ itemPriv->opacityNode->setOpacity(opacity);
+ }
+
+ if (dirty & QSGItemPrivate::ContentUpdateMask) {
+
+ if (itemPriv->flags & QSGItem::ItemHasContents) {
+ updatePaintNodeData.transformNode = itemPriv->itemNode();
+ itemPriv->paintNode = item->updatePaintNode(itemPriv->paintNode, &updatePaintNodeData);
+
+ Q_ASSERT(itemPriv->paintNode == 0 ||
+ itemPriv->paintNode->parent() == 0 ||
+ itemPriv->paintNode->parent() == itemPriv->childContainerNode());
+
+ if (itemPriv->paintNode && itemPriv->paintNode->parent() == 0) {
+ if (itemPriv->childContainerNode()->childCount() == itemPriv->paintNodeIndex)
+ itemPriv->childContainerNode()->appendChildNode(itemPriv->paintNode);
+ else
+ itemPriv->childContainerNode()->insertChildNodeBefore(itemPriv->paintNode, itemPriv->childContainerNode()->childAtIndex(itemPriv->paintNodeIndex));
+ }
+ } else if (itemPriv->paintNode) {
+ delete itemPriv->paintNode;
+ itemPriv->paintNode = 0;
+ }
+ }
+
+#ifndef QT_NO_DEBUG
+ // Check consistency.
+ const QSGNode *nodeChain[] = {
+ itemPriv->itemNodeInstance,
+ itemPriv->opacityNode,
+ itemPriv->clipNode,
+ itemPriv->rootNode,
+ itemPriv->groupNode,
+ itemPriv->paintNode,
+ };
+
+ int ip = 0;
+ for (;;) {
+ while (ip < 5 && nodeChain[ip] == 0)
+ ++ip;
+ if (ip == 5)
+ break;
+ int ic = ip + 1;
+ while (ic < 5 && nodeChain[ic] == 0)
+ ++ic;
+ const QSGNode *parent = nodeChain[ip];
+ const QSGNode *child = nodeChain[ic];
+ if (child == 0) {
+ Q_ASSERT(parent == itemPriv->groupNode || parent->childCount() == 0);
+ } else {
+ Q_ASSERT(parent == itemPriv->groupNode || parent->childCount() == 1);
+ Q_ASSERT(child->parent() == parent);
+ bool containsChild = false;
+ for (int i = 0; i < parent->childCount(); ++i)
+ containsChild |= (parent->childAtIndex(i) == child);
+ Q_ASSERT(containsChild);
+ }
+ ip = ic;
+ }
+#endif
+
+#ifdef QML_RUNTIME_TESTING
+ if (itemPriv->sceneGraphContext()->isFlashModeEnabled()) {
+ QSGFlashNode *flash = new QSGFlashNode();
+ flash->setRect(item->boundingRect());
+ itemPriv->childContainerNode()->appendChildNode(flash);
+ didFlash = true;
+ }
+ Q_Q(QSGCanvas);
+ if (didFlash) {
+ q->maybeUpdate();
+ }
+#endif
+
+}
+
+void QSGCanvas::maybeUpdate()
+{
+ Q_D(QSGCanvas);
+
+ if (d->threadedRendering) {
+ if (!d->renderThreadAwakened) {
+ d->renderThreadAwakened = true;
+ bool locked = d->mutex.tryLock();
+ if (d->idle && locked) {
+#ifdef THREAD_DEBUG
+ qWarning("QSGRenderer: now maybe I should update...");
+#endif
+ d->wait.wakeOne();
+ } else if (d->inSync) {
+ // If we are in sync (on scene graph thread) someone has explicitely asked us
+ // to redraw, hence we tell the render loop to not go idle.
+ // The primary usecase for this is updatePaintNode() calling update() without
+ // changing the scene graph.
+ d->needsRepaint = true;
+ }
+ if (locked)
+ d->mutex.unlock();
+ }
+ } else if (!d->animationDriver || !d->animationDriver->isRunning()) {
+ update();
+ }
+}
+
+/*!
+ \fn void QSGEngine::sceneGraphInitialized();
+
+ This signal is emitted when the scene graph has been initialized.
+
+ This signal will be emitted from the scene graph rendering thread.
+ */
+
+/*!
+ Returns the QSGEngine used for this scene.
+
+ The engine will only be available once the scene graph has been
+ initialized. Register for the sceneGraphEngine() signal to get
+ notification about this.
+ */
+
+QSGEngine *QSGCanvas::sceneGraphEngine() const
+{
+ Q_D(const QSGCanvas);
+ if (d->context->isReady())
+ return d->context->engine();
+ return 0;
+}
+
+#include "moc_qsgcanvas.cpp"
+
+QT_END_NAMESPACE
diff --git a/src/declarative/items/qsgcanvas.h b/src/declarative/items/qsgcanvas.h
new file mode 100644
index 0000000000..6707d24b30
--- /dev/null
+++ b/src/declarative/items/qsgcanvas.h
@@ -0,0 +1,123 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGCANVAS_H
+#define QSGCANVAS_H
+
+#include <QtCore/qmetatype.h>
+#include <QtOpenGL/qgl.h>
+#include <QtGui/qwidget.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QSGItem;
+class QSGEngine;
+class QSGCanvasPrivate;
+class Q_DECLARATIVE_EXPORT QSGCanvas : public QGLWidget
+{
+Q_OBJECT
+Q_DECLARE_PRIVATE(QSGCanvas)
+public:
+ QSGCanvas(QWidget *parent = 0, Qt::WindowFlags f = 0);
+ QSGCanvas(const QGLFormat &format, QWidget *parent = 0, Qt::WindowFlags f = 0);
+ virtual ~QSGCanvas();
+
+ QSGItem *rootItem() const;
+ QSGItem *activeFocusItem() const;
+
+ QSGItem *mouseGrabberItem() const;
+
+ bool sendEvent(QSGItem *, QEvent *);
+
+ QVariant inputMethodQuery(Qt::InputMethodQuery query) const;
+
+ QSGEngine *sceneGraphEngine() const;
+
+Q_SIGNALS:
+ void sceneGraphInitialized();
+
+protected:
+ QSGCanvas(QSGCanvasPrivate &dd, QWidget *parent = 0, Qt::WindowFlags f = 0);
+ QSGCanvas(QSGCanvasPrivate &dd, const QGLFormat &format, QWidget *parent = 0, Qt::WindowFlags f = 0);
+
+ virtual void paintEvent(QPaintEvent *);
+ virtual void resizeEvent(QResizeEvent *);
+
+ virtual void showEvent(QShowEvent *);
+ virtual void hideEvent(QHideEvent *);
+
+ virtual void focusOutEvent(QFocusEvent *);
+ virtual void focusInEvent(QFocusEvent *);
+
+ virtual bool event(QEvent *);
+ virtual void keyPressEvent(QKeyEvent *);
+ virtual void keyReleaseEvent(QKeyEvent *);
+ virtual void inputMethodEvent(QInputMethodEvent *);
+ virtual void mousePressEvent(QMouseEvent *);
+ virtual void mouseReleaseEvent(QMouseEvent *);
+ virtual void mouseDoubleClickEvent(QMouseEvent *);
+ virtual void mouseMoveEvent(QMouseEvent *);
+#ifndef QT_NO_WHEELEVENT
+ virtual void wheelEvent(QWheelEvent *);
+#endif
+
+private Q_SLOTS:
+ void sceneGraphChanged();
+ void maybeUpdate();
+
+private:
+ Q_DISABLE_COPY(QSGCanvas)
+ Q_PRIVATE_SLOT(d_func(), void _q_animationStarted())
+ Q_PRIVATE_SLOT(d_func(), void _q_animationStopped())
+};
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(QSGCanvas *);
+
+QT_END_HEADER
+
+#endif // QSGCANVAS_H
+
diff --git a/src/declarative/items/qsgcanvas_p.h b/src/declarative/items/qsgcanvas_p.h
new file mode 100644
index 0000000000..6b8034f922
--- /dev/null
+++ b/src/declarative/items/qsgcanvas_p.h
@@ -0,0 +1,189 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGCANVAS_P_H
+#define QSGCANVAS_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 "qsgitem.h"
+#include "qsgcanvas.h"
+#include <private/qdeclarativeguard_p.h>
+
+#include <private/qsgcontext_p.h>
+
+#include <QtCore/qthread.h>
+#include <QtCore/qmutex.h>
+#include <QtCore/qwaitcondition.h>
+#include <private/qwidget_p.h>
+#include <private/qgl_p.h>
+
+QT_BEGIN_NAMESPACE
+
+//Make it easy to identify and customize the root item if needed
+class QSGRootItem : public QSGItem
+{
+ Q_OBJECT
+public:
+ QSGRootItem();
+};
+
+class QSGCanvasPrivate;
+
+class QTouchEvent;
+class QSGCanvasPrivate : public QGLWidgetPrivate
+{
+public:
+ Q_DECLARE_PUBLIC(QSGCanvas)
+
+ static inline QSGCanvasPrivate *get(QSGCanvas *c) { return c->d_func(); }
+
+ QSGCanvasPrivate();
+ virtual ~QSGCanvasPrivate();
+
+ void init(QSGCanvas *);
+
+ QSGRootItem *rootItem;
+
+ QSGItem *activeFocusItem;
+ QSGItem *mouseGrabberItem;
+
+ // Mouse positions are saved in widget coordinates
+ QPoint lastMousePosition;
+ QPoint buttonDownPositions[5]; // Left, Right, Middle, XButton1, XButton2
+ void sceneMouseEventFromMouseEvent(QGraphicsSceneMouseEvent &, QMouseEvent *);
+ void translateTouchEvent(QTouchEvent *touchEvent);
+ static QEvent::Type sceneMouseEventTypeFromMouseEvent(QMouseEvent *);
+ static void sceneMouseEventForTransform(QGraphicsSceneMouseEvent &, const QTransform &);
+ static void transformTouchPoints(QList<QTouchEvent::TouchPoint> &touchPoints, const QTransform &transform);
+ bool deliverInitialMousePressEvent(QSGItem *, QGraphicsSceneMouseEvent *);
+ bool deliverMouseEvent(QGraphicsSceneMouseEvent *);
+ bool sendFilteredMouseEvent(QSGItem *, QSGItem *, QGraphicsSceneMouseEvent *);
+ bool deliverWheelEvent(QSGItem *, QGraphicsSceneWheelEvent *);
+ bool deliverTouchPoints(QSGItem *, QTouchEvent *, const QList<QTouchEvent::TouchPoint> &, QSet<int> *,
+ QHash<QSGItem *, QList<QTouchEvent::TouchPoint> > *);
+ bool deliverTouchEvent(QTouchEvent *);
+ void sceneHoverEventFromMouseEvent(QGraphicsSceneHoverEvent &, QMouseEvent *);
+ bool deliverHoverEvent(QSGItem *, QGraphicsSceneHoverEvent *);
+ void sendHoverEvent(QEvent::Type, QSGItem *, QGraphicsSceneHoverEvent *);
+ void clearHover();
+
+ void stopRenderingThread();
+
+ QDeclarativeGuard<QSGItem> hoverItem;
+ enum FocusOption {
+ DontChangeFocusProperty = 0x01,
+ };
+ Q_DECLARE_FLAGS(FocusOptions, FocusOption)
+
+ void setFocusInScope(QSGItem *scope, QSGItem *item, FocusOptions = 0);
+ void clearFocusInScope(QSGItem *scope, QSGItem *item, FocusOptions = 0);
+ void notifyFocusChangesRecur(QSGItem **item, int remaining);
+
+ void updateInputMethodData();
+
+ void dirtyItem(QSGItem *);
+ void cleanup(QSGNode *);
+
+ void initializeSceneGraph();
+ void polishItems();
+ void syncSceneGraph();
+ void renderSceneGraph();
+ void runThread();
+
+ void _q_animationStarted();
+ void _q_animationStopped();
+
+ QSGItem::UpdatePaintNodeData updatePaintNodeData;
+
+ QSGItem *dirtyItemList;
+ QList<QSGNode *> cleanupNodeList;
+
+ QSet<QSGItem *> itemsToPolish;
+
+ void updateDirtyNodes();
+ void cleanupNodes();
+ bool updateEffectiveOpacity(QSGItem *);
+ void updateEffectiveOpacityRoot(QSGItem *, qreal);
+ void updateDirtyNode(QSGItem *);
+
+ QSGContext *context;
+
+ uint contextInThread : 1;
+ uint threadedRendering : 1;
+ uint exitThread : 1;
+ uint animationRunning: 1;
+ uint idle : 1; // Set to true when render thread sees no change and enters a wait()
+ uint needsRepaint : 1; // Set by callback from render if scene needs repainting.
+ uint renderThreadAwakened : 1;
+ uint inSync: 1;
+
+ struct MyThread : public QThread {
+ MyThread(QSGCanvasPrivate *r) : renderer(r) {}
+ virtual void run() { renderer->runThread(); }
+ static void doWait() { QThread::msleep(16); }
+ QSGCanvasPrivate *renderer;
+ };
+ MyThread *thread;
+ QMutex mutex;
+ QWaitCondition wait;
+ QSize widgetSize;
+ QSize viewportSize;
+
+ QAnimationDriver *animationDriver;
+
+ QHash<int, QSGItem *> itemForTouchPointId;
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QSGCanvasPrivate::FocusOptions)
+
+QT_END_NAMESPACE
+
+#endif // QSGCANVAS_P_H
diff --git a/src/declarative/items/qsgcanvasitem.cpp b/src/declarative/items/qsgcanvasitem.cpp
new file mode 100644
index 0000000000..ba3c4baa11
--- /dev/null
+++ b/src/declarative/items/qsgcanvasitem.cpp
@@ -0,0 +1,441 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtGui/qpainter.h>
+
+#include "private/qsgadaptationlayer_p.h"
+#include "qsgcanvasitem_p.h"
+#include "qsgpainteditem_p.h"
+#include "qsgcontext2d_p.h"
+#include "private/qsgpainternode_p.h"
+#include <qdeclarativeinfo.h>
+#include "qdeclarativeengine_p.h"
+#include <QtCore/QBuffer>
+
+QT_BEGIN_NAMESPACE
+
+class QSGCanvasItemPrivate : public QSGPaintedItemPrivate
+{
+public:
+ QSGCanvasItemPrivate();
+ QSGContext2D* context;
+};
+
+
+/*!
+ \internal
+*/
+QSGCanvasItemPrivate::QSGCanvasItemPrivate()
+ : QSGPaintedItemPrivate()
+ , context(0)
+{
+}
+
+/*!
+ Constructs a QSGCanvasItem with the given \a parent item.
+ */
+QSGCanvasItem::QSGCanvasItem(QSGItem *parent)
+ : QSGPaintedItem(*(new QSGCanvasItemPrivate), parent)
+{
+}
+
+/*!
+ Destroys the QSGCanvasItem.
+*/
+QSGCanvasItem::~QSGCanvasItem()
+{
+}
+
+void QSGCanvasItem::paint(QPainter *painter)
+{
+ Q_D(QSGCanvasItem);
+
+ if (d->context) {
+ d->context->paint(painter);
+ emit canvasUpdated();
+ }
+}
+
+
+QSGContext2D* QSGCanvasItem::getContext(const QString &contextId)
+{
+ Q_D(QSGCanvasItem);
+ if (contextId == QLatin1String("2d")) {
+ if (!d->context) {
+ d->context = new QSGContext2D(this);
+ connect(d->context, SIGNAL(changed()), this, SLOT(requestPaint()));
+ }
+ return d->context;
+ }
+ qDebug("Canvas:requesting unsupported context");
+ return 0;
+}
+
+void QSGCanvasItem::requestPaint()
+{
+ Q_D(QSGCanvasItem);
+ //TODO:update(d->context->dirtyRect());
+ update();
+}
+
+bool QSGCanvasItem::save(const QString &filename) const
+{
+ Q_D(const QSGCanvasItem);
+ QSGPainterNode* node = static_cast<QSGPainterNode*>(d->paintNode);
+ if (node) {
+ QImage image = node->toImage();
+ image.save(filename);
+ }
+ return false;
+}
+
+QString QSGCanvasItem::toDataURL(const QString& mimeType) const
+{
+ Q_D(const QSGCanvasItem);
+
+ QSGPainterNode* node = static_cast<QSGPainterNode*>(d->paintNode);
+ if (node) {
+ QImage image = node->toImage();
+ QByteArray ba;
+ QBuffer buffer(&ba);
+ buffer.open(QIODevice::WriteOnly);
+ QString mime = mimeType;
+ QString type;
+ if (mimeType == QLatin1String("image/bmp"))
+ type = "BMP";
+ else if (mimeType == QLatin1String("image/jpeg"))
+ type = "JPEG";
+ else if (mimeType == QLatin1String("image/x-portable-pixmap"))
+ type = "PPM";
+ else if (mimeType == QLatin1String("image/tiff"))
+ type = "TIFF";
+ else if (mimeType == QLatin1String("image/xbm"))
+ type = "XBM";
+ else if (mimeType == QLatin1String("image/xpm"))
+ type = "XPM";
+ else {
+ type = "PNG";
+ mime = QLatin1String("image/png");
+ }
+ image.save(&buffer, type.toAscii());
+ buffer.close();
+ QString dataUrl = QLatin1String("data:%1;base64,%2");
+ return dataUrl.arg(mime).arg(ba.toBase64().constData());
+ }
+ return QLatin1String("data:,");
+}
+//CanvasItemTextureProvider::CanvasItemTextureProvider(QObject *parent)
+// : QSGTextureProvider(parent)
+// , m_ctx2d(0)
+// , m_fbo(0)
+// , m_multisampledFbo(0)
+// , m_dirtyTexture(true)
+// , m_multisamplingSupportChecked(false)
+// , m_multisampling(false)
+//{
+//}
+
+//CanvasItemTextureProvider::~CanvasItemTextureProvider()
+//{
+// delete m_fbo;
+// delete m_multisampledFbo;
+//}
+
+//void CanvasItemTextureProvider::updateTexture()
+//{
+// if (m_dirtyTexture) {
+// if (!m_ctx2d->isDirty())
+// return;
+// if (m_size.isEmpty()) {
+// m_texture = QSGTextureRef();
+// delete m_fbo;
+// delete m_multisampledFbo;
+// m_multisampledFbo = m_fbo = 0;
+// return;
+// }
+
+//#ifndef QSGCANVASITEM_PAINTING_ON_IMAGE
+// //create texture
+// if (!m_fbo || m_fbo->size() != m_size )
+// {
+// const QGLContext *ctx = QSGContext::current->glContext();
+// if (!m_multisamplingSupportChecked) {
+// QList<QByteArray> extensions = QByteArray((const char *)glGetString(GL_EXTENSIONS)).split(' ');
+// m_multisampling = extensions.contains("GL_EXT_framebuffer_multisample")
+// && extensions.contains("GL_EXT_framebuffer_blit");
+// m_multisamplingSupportChecked = true;
+// }
+
+// if (ctx->format().sampleBuffers() && m_multisampling) {
+// delete m_fbo;
+// delete m_multisampledFbo;
+// QGLFramebufferObjectFormat format;
+
+// format.setAttachment(QGLFramebufferObject::CombinedDepthStencil);
+// format.setSamples(ctx->format().samples());
+// m_multisampledFbo = new QGLFramebufferObject(m_size, format);
+// {
+// QGLFramebufferObjectFormat format;
+// format.setAttachment(QGLFramebufferObject::NoAttachment);
+// m_fbo = new QGLFramebufferObject(m_size, format);
+// }
+
+// QSGPlainTexture *tex = new QSGPlainTexture;
+// tex->setTextureId(m_fbo->texture());
+// tex->setOwnsTexture(false);
+// tex->setHasAlphaChannel(true);
+// setOpaque(!tex->hasAlphaChannel());
+// m_texture = QSGTextureRef(tex);
+// } else {
+// delete m_fbo;
+// QGLFramebufferObjectFormat format;
+// format.setAttachment(QGLFramebufferObject::CombinedDepthStencil);
+// m_fbo = new QGLFramebufferObject(m_size, format);
+// QSGPlainTexture *tex = new QSGPlainTexture;
+// tex->setTextureId(m_fbo->texture());
+// tex->setOwnsTexture(false);
+// tex->setHasAlphaChannel(true);
+// setOpaque(!tex->hasAlphaChannel());
+// m_texture = QSGTextureRef(tex);
+// }
+// }
+//#endif
+
+//#ifdef QSGCANVASITEM_DEBUG
+// qDebug() << "painting interval:" << m_elapsedTimer.nsecsElapsed();
+// m_elapsedTimer.restart();
+//#endif
+// //paint 2d
+// if (m_ctx2d) {
+// QPainter p;
+//#ifndef QSGCANVASITEM_PAINTING_ON_IMAGE
+// if (m_multisampledFbo)
+// p.begin(m_multisampledFbo);
+// else if (m_fbo)
+// p.begin(m_fbo);
+// else
+// return;
+// // move the origin of coordinates to the down left corner and
+// // scale coordinates and turn y-axis up
+// QSize size = m_ctx2d->size();
+// p.translate( 0, size.height());
+// p.scale(1, -1);
+
+// m_ctx2d->paint(&p);
+
+// p.end();
+
+// if (m_multisampledFbo) {
+// QRect r(0, 0, m_fbo->width(), m_fbo->height());
+// QGLFramebufferObject::blitFramebuffer(m_fbo, r, m_multisampledFbo, r);
+// }
+
+// if (m_ctx2d->requireCachedImage())
+// m_ctx2d->setCachedImage(m_fbo->toImage());
+
+//#else
+// m_painter.begin(m_ctx2d->paintDevice());
+// m_ctx2d->paint(&m_painter);
+// m_painter.end();
+
+// if (m_texture.isNull()) {
+// m_texture = QSGContext::current->createTexture(m_ctx2d->toImage());
+// } else {
+// QSGPlainTexture* t =static_cast<QSGPlainTexture*>(m_texture.texture());
+// t->setImage(m_ctx2d->toImage());
+// }
+// m_ctx2d->setCachedImage(m_ctx2d->toImage());
+
+//#endif
+
+//#ifdef QSGCANVASITEM_DEBUG
+// qDebug() << "painting time:" << m_elapsedTimer.nsecsElapsed();
+// m_elapsedTimer.restart();
+//#endif
+// emit painted();
+// }
+// }
+//}
+
+//QSGTextureRef CanvasItemTextureProvider::texture()
+//{
+// return m_texture;
+//}
+//void CanvasItemTextureProvider::setContext2D(QSGContext2D *ctx2d)
+//{
+// if (ctx2d && m_ctx2d != ctx2d) {
+// m_ctx2d = ctx2d;
+// connect(this, SIGNAL(painted()), m_ctx2d, SIGNAL(painted()));
+// }
+//}
+//void CanvasItemTextureProvider::setRect(const QRectF &rect)
+//{
+// if (rect == m_rect)
+// return;
+// m_rect = rect;
+// markDirtyTexture();
+//}
+
+//void CanvasItemTextureProvider::setSize(const QSize &size)
+//{
+// if (size == m_size)
+// return;
+// m_size = size;
+// markDirtyTexture();
+//}
+
+//void CanvasItemTextureProvider::markDirtyTexture()
+//{
+// m_dirtyTexture = true;
+// emit textureChanged();
+//}
+//QSGCanvasItem::QSGCanvasItem(QSGItem *parent)
+// : TextureItem(parent)
+// , m_textureProvider(0)
+// , m_context2dChanged(false)
+// , m_context2d( new QSGContext2D(this))
+// , m_fillMode(QSGCanvasItem::Stretch)
+// , m_color(Qt::white)
+//{
+// m_textureProvider = new CanvasItemTextureProvider(this);
+// m_textureProvider->setContext2D(m_context2d);
+// setTextureProvider(m_textureProvider, true);
+// setFlag(QSGItem::ItemHasContents, true);
+//}
+
+//QSGCanvasItem::~QSGCanvasItem()
+//{
+//}
+
+//void QSGCanvasItem::componentComplete()
+//{
+// m_context2d->setSize(width(), height());
+// qDebug() << "m_context2d.size:" << m_context2d->size();
+// connect(m_context2d, SIGNAL(changed()), this, SLOT(requestPaint()));
+// QScriptEngine* scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(qmlEngine(this));
+// if (scriptEngine != m_context2d->scriptEngine())
+// m_context2d->setScriptEngine(scriptEngine);
+// QSGItem::componentComplete();
+//}
+
+
+//void QSGCanvasItem::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
+//{
+// if (width() == 0 && height()
+// && newGeometry.width() > 0 && newGeometry.height() > 0) {
+// m_context2d->setSize(width(), height());
+// }
+// TextureItem::geometryChanged(newGeometry, oldGeometry);
+//}
+
+//void QSGCanvasItem::setFillMode(FillMode mode)
+//{
+// if (m_fillMode == mode)
+// return;
+
+// m_fillMode = mode;
+// update();
+// emit fillModeChanged();
+//}
+
+//QColor QSGCanvasItem::color()
+//{
+// return m_color;
+//}
+
+//void QSGCanvasItem::setColor(const QColor &color)
+//{
+// if (m_color !=color) {
+// m_color = color;
+// colorChanged();
+// }
+//}
+
+//QSGCanvasItem::FillMode QSGCanvasItem::fillMode() const
+//{
+// return m_fillMode;
+//}
+
+
+
+//Node *QSGCanvasItem::updatePaintNode(Node *oldNode, UpdatePaintNodeData *data)
+//{
+// if (width() <= 0 || height() <= 0) {
+// delete oldNode;
+// return 0;
+// }
+
+// TextureNodeInterface *node = static_cast<TextureNodeInterface *>(oldNode);
+
+// if (node && m_context2d->isDirty()) {
+// QRectF bounds = boundingRect();
+
+// if (m_textureProvider) {
+// m_textureProvider->setRect(QRectF(bounds.x(), bounds.y(), width(), height()));
+
+// m_textureProvider->setSize(QSize(width(), height()));
+// //m_textureProvider->setOpaque(true);
+// m_textureProvider->setHorizontalWrapMode(QSGTextureProvider::ClampToEdge);
+// m_textureProvider->setVerticalWrapMode(QSGTextureProvider::ClampToEdge);
+// node->setTargetRect(bounds);
+// node->setSourceRect(QRectF(0, 0, 1, 1));
+// // node->setTargetRect(image.rect());
+//// node->setSourceRect(QRectF(0, 0, 1, 1));
+//// d->textureProvider->setHorizontalWrapMode(QSGTextureProvider::ClampToEdge);
+//// d->textureProvider->setVerticalWrapMode(QSGTextureProvider::ClampToEdge);
+//// d->textureProvider->setFiltering(d->smooth ? QSGTextureProvider::Linear : QSGTextureProvider::Nearest);
+// }
+
+// if (m_context2dChanged) {
+// //force textnode update the content
+// node->setTexture(0);
+// node->setTexture(m_textureProvider);
+// m_context2dChanged = false;
+// }
+// } else {
+// if (m_context2d->requireCachedImage())
+// m_context2d->setCachedImage(QImage(width(), height(), QImage::Format_ARGB32_Premultiplied));
+// }
+
+// return TextureItem::updatePaintNode(oldNode, data);
+//}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/items/qsgcanvasitem_p.h b/src/declarative/items/qsgcanvasitem_p.h
new file mode 100644
index 0000000000..a358c353ea
--- /dev/null
+++ b/src/declarative/items/qsgcanvasitem_p.h
@@ -0,0 +1,89 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGCANVASITEM_P_H
+#define QSGCANVASITEM_P_H
+
+#include "qsgpainteditem.h"
+
+#define QSGCANVASITEM_DEBUG //enable this for just DEBUG purpose!
+
+#ifdef QSGCANVASITEM_DEBUG
+#include <QElapsedTimer>
+#endif
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+class QSGContext2D;
+class QSGCanvasItemPrivate;
+class QSGCanvasItem : public QSGPaintedItem
+{
+ Q_OBJECT
+public:
+ QSGCanvasItem(QSGItem *parent = 0);
+ ~QSGCanvasItem();
+
+signals:
+ void canvasUpdated();
+public Q_SLOTS:
+ QString toDataURL(const QString& type = QLatin1String("image/png")) const;
+ QSGContext2D* getContext(const QString & = QLatin1String("2d"));
+ void requestPaint();
+
+ // Save current canvas to disk
+ bool save(const QString& filename) const;
+
+protected:
+ void paint(QPainter *painter);
+private:
+ Q_DECLARE_PRIVATE(QSGCanvasItem)
+ friend class QSGContext2D;
+};
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QSGCanvasItem)
+
+QT_END_HEADER
+
+#endif //QSGCANVASITEM_P_H
diff --git a/src/declarative/items/qsgclipnode.cpp b/src/declarative/items/qsgclipnode.cpp
new file mode 100644
index 0000000000..2e40972620
--- /dev/null
+++ b/src/declarative/items/qsgclipnode.cpp
@@ -0,0 +1,121 @@
+
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include "qsgclipnode_p.h"
+
+#include <QtGui/qvector2d.h>
+#include <QtCore/qmath.h>
+
+QSGDefaultClipNode::QSGDefaultClipNode(const QRectF &rect)
+ : m_rect(rect)
+ , m_radius(0)
+ , m_dirty_geometry(true)
+ , m_geometry(QSGGeometry::defaultAttributes_Point2D(), 0)
+{
+ setGeometry(&m_geometry);
+ setIsRectangular(true);
+}
+
+void QSGDefaultClipNode::setRect(const QRectF &rect)
+{
+ m_rect = rect;
+ m_dirty_geometry = true;
+}
+
+void QSGDefaultClipNode::setRadius(qreal radius)
+{
+ m_radius = radius;
+ m_dirty_geometry = true;
+ setIsRectangular(radius == 0);
+}
+
+void QSGDefaultClipNode::update()
+{
+ if (m_dirty_geometry) {
+ updateGeometry();
+ m_dirty_geometry = false;
+ }
+}
+
+void QSGDefaultClipNode::updateGeometry()
+{
+ QSGGeometry *g = geometry();
+
+ if (qFuzzyIsNull(m_radius)) {
+ g->allocate(4);
+ QSGGeometry::updateRectGeometry(g, m_rect);
+
+ } else {
+ int vertexCount = 0;
+
+ // Radius should never exceeds half of the width or half of the height
+ qreal radius = qMin(qMin(m_rect.width() / 2, m_rect.height() / 2), m_radius);
+ QRectF rect = m_rect;
+ rect.adjust(radius, radius, -radius, -radius);
+
+ int segments = qMin(30, qCeil(radius)); // Number of segments per corner.
+
+ g->allocate((segments + 1) * 2);
+
+ QVector2D *vertices = (QVector2D *)g->vertexData();
+
+ for (int part = 0; part < 2; ++part) {
+ for (int i = 0; i <= segments; ++i) {
+ //### Should change to calculate sin/cos only once.
+ qreal angle = qreal(0.5 * M_PI) * (part + i / qreal(segments));
+ qreal s = qFastSin(angle);
+ qreal c = qFastCos(angle);
+ qreal y = (part ? rect.bottom() : rect.top()) - radius * c; // current inner y-coordinate.
+ qreal lx = rect.left() - radius * s; // current inner left x-coordinate.
+ qreal rx = rect.right() + radius * s; // current inner right x-coordinate.
+
+ vertices[vertexCount++] = QVector2D(rx, y);
+ vertices[vertexCount++] = QVector2D(lx, y);
+ }
+ }
+
+ markDirty(DirtyGeometry);
+ }
+ setClipRect(m_rect);
+}
+
diff --git a/src/declarative/items/qsgclipnode_p.h b/src/declarative/items/qsgclipnode_p.h
new file mode 100644
index 0000000000..aa1d01efdd
--- /dev/null
+++ b/src/declarative/items/qsgclipnode_p.h
@@ -0,0 +1,71 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGCLIPNODE_P_H
+#define QSGCLIPNODE_P_H
+
+#include <qsgnode.h>
+
+class QSGDefaultClipNode : public QSGClipNode
+{
+public:
+ QSGDefaultClipNode(const QRectF &);
+
+ void setRect(const QRectF &);
+ QRectF rect() const { return m_rect; }
+
+ void setRadius(qreal radius);
+ qreal radius() const { return m_radius; }
+
+ virtual void update();
+
+private:
+ void updateGeometry();
+ QRectF m_rect;
+ qreal m_radius;
+
+ uint m_dirty_geometry : 1;
+ uint m_reserved : 31;
+
+ QSGGeometry m_geometry;
+};
+
+#endif // QSGCLIPNODE_P_H
diff --git a/src/declarative/items/qsgcontext2d.cpp b/src/declarative/items/qsgcontext2d.cpp
new file mode 100644
index 0000000000..6f7121ac30
--- /dev/null
+++ b/src/declarative/items/qsgcontext2d.cpp
@@ -0,0 +1,2716 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgcontext2d_p.h"
+#include "qsgcontext2d_p_p.h"
+#include "private/qsgadaptationlayer_p.h"
+#include "qsgcanvasitem_p.h"
+#include <QtOpenGL/qglframebufferobject.h>
+#include <QtCore/qdebug.h>
+#include "private/qsgcontext_p.h"
+
+#include <QtGui/qgraphicsitem.h>
+#include <QtGui/qapplication.h>
+#include <QtGui/qgraphicseffect.h>
+#include <qdeclarativeinfo.h>
+#include <QtCore/qmath.h>
+#include "qdeclarativepixmapcache_p.h"
+#include <QtScript/QScriptEngine>
+
+QT_BEGIN_NAMESPACE
+
+static const double Q_PI = 3.14159265358979323846; // pi
+template <class T>
+void memcpy_vector(QVector<T>* dst, const QVector<T>& src)
+{
+ int pos = dst->size();
+ dst->resize(pos + src.size());
+ memmove(dst->data() + pos, src.constData(), sizeof(T) * src.size());
+}
+
+template <class T>
+void copy_vector(QVector<T>* dst, const QVector<T>& src)
+{
+ int pos = dst->size();
+ dst->resize(pos + src.size());
+ for (int i = 0; i < src.size(); i++) {
+ (*dst)[pos + i] = src[i];
+ }
+}
+
+// Note, this is exported but in a private header as qtopengl depends on it.
+// But it really should be considered private API
+void qt_blurImage(QPainter *p, QImage &blurImage, qreal radius, bool quality, bool alphaOnly, int transposed = 0);
+void qt_blurImage(QImage &blurImage, qreal radius, bool quality, int transposed = 0);
+
+#define DEGREES(t) ((t) * 180.0 / Q_PI)
+#define qClamp(val, min, max) qMin(qMax(val, min), max)
+
+static inline int extractInt(const char **name)
+{
+ int result = 0;
+ bool negative = false;
+
+ //eat leading whitespace
+ while (isspace(*name[0]))
+ ++*name;
+
+ if (*name[0] == '-') {
+ ++*name;
+ negative = true;
+ } /*else if (name[0] == '+')
+ ++name; //ignore*/
+
+ //construct number
+ while (isdigit(*name[0])) {
+ result = result * 10 + (*name[0] - '0');
+ ++*name;
+ }
+ if (negative)
+ result = -result;
+
+ //handle optional percentage
+ if (*name[0] == '%')
+ result *= qreal(255)/100; //### floor or round?
+
+ //eat trailing whitespace
+ while (isspace(*name[0]))
+ ++*name;
+
+ return result;
+}
+
+static bool qt_get_rgb(const QString &string, QRgb *rgb)
+{
+ const char *name = string.toLatin1().constData();
+ int len = qstrlen(name);
+
+ if (len < 5)
+ return false;
+
+ bool handleAlpha = false;
+
+ if (name[0] != 'r')
+ return false;
+ if (name[1] != 'g')
+ return false;
+ if (name[2] != 'b')
+ return false;
+ if (name[3] == 'a') {
+ handleAlpha = true;
+ if(name[3] != '(')
+ return false;
+ } else if (name[3] != '(')
+ return false;
+
+ name += 4;
+
+ int r, g, b, a = 1;
+ int result;
+
+ //red
+ result = extractInt(&name);
+ if (name[0] == ',') {
+ r = result;
+ ++name;
+ } else
+ return false;
+
+ //green
+ result = extractInt(&name);
+ if (name[0] == ',') {
+ g = result;
+ ++name;
+ } else
+ return false;
+
+ char nextChar = handleAlpha ? ',' : ')';
+
+ //blue
+ result = extractInt(&name);
+ if (name[0] == nextChar) {
+ b = result;
+ ++name;
+ } else
+ return false;
+
+ //alpha
+ if (handleAlpha) {
+ result = extractInt(&name);
+ if (name[0] == ')') {
+ a = result * 255; //map 0-1 to 0-255
+ ++name;
+ } else
+ return false;
+ }
+
+ if (name[0] != '\0')
+ return false;
+
+ *rgb = qRgba(qClamp(r,0,255), qClamp(g,0,255), qClamp(b,0,255), qClamp(a,0,255));
+ return true;
+}
+
+//### unify with qt_get_rgb?
+static bool qt_get_hsl(const QString &string, QColor *color)
+{
+ const char *name = string.toLatin1().constData();
+ int len = qstrlen(name);
+
+ if (len < 5)
+ return false;
+
+ bool handleAlpha = false;
+
+ if (name[0] != 'h')
+ return false;
+ if (name[1] != 's')
+ return false;
+ if (name[2] != 'l')
+ return false;
+ if (name[3] == 'a') {
+ handleAlpha = true;
+ if(name[3] != '(')
+ return false;
+ } else if (name[3] != '(')
+ return false;
+
+ name += 4;
+
+ int h, s, l, a = 1;
+ int result;
+
+ //hue
+ result = extractInt(&name);
+ if (name[0] == ',') {
+ h = result;
+ ++name;
+ } else
+ return false;
+
+ //saturation
+ result = extractInt(&name);
+ if (name[0] == ',') {
+ s = result;
+ ++name;
+ } else
+ return false;
+
+ char nextChar = handleAlpha ? ',' : ')';
+
+ //lightness
+ result = extractInt(&name);
+ if (name[0] == nextChar) {
+ l = result;
+ ++name;
+ } else
+ return false;
+
+ //alpha
+ if (handleAlpha) {
+ result = extractInt(&name);
+ if (name[0] == ')') {
+ a = result * 255; //map 0-1 to 0-255
+ ++name;
+ } else
+ return false;
+ }
+
+ if (name[0] != '\0')
+ return false;
+
+ *color = QColor::fromHsl(qClamp(h,0,255), qClamp(s,0,255), qClamp(l,0,255), qClamp(a,0,255));
+ return true;
+}
+
+//### optimize further
+QColor colorFromString(const QString &name)
+{
+ if (name.startsWith(QLatin1String("rgb"))) {
+ QRgb rgb;
+ if (qt_get_rgb(name, &rgb))
+ return QColor(rgb);
+ } else if (name.startsWith(QLatin1String("hsl"))) {
+ QColor color;
+ if (qt_get_hsl(name, &color))
+ return color;
+ }
+
+ return QColor(name);
+}
+
+
+static QPainter::CompositionMode compositeOperatorFromString(const QString &compositeOperator)
+{
+ if (compositeOperator == QLatin1String("source-over")) {
+ return QPainter::CompositionMode_SourceOver;
+ } else if (compositeOperator == QLatin1String("source-out")) {
+ return QPainter::CompositionMode_SourceOut;
+ } else if (compositeOperator == QLatin1String("source-in")) {
+ return QPainter::CompositionMode_SourceIn;
+ } else if (compositeOperator == QLatin1String("source-atop")) {
+ return QPainter::CompositionMode_SourceAtop;
+ } else if (compositeOperator == QLatin1String("destination-atop")) {
+ return QPainter::CompositionMode_DestinationAtop;
+ } else if (compositeOperator == QLatin1String("destination-in")) {
+ return QPainter::CompositionMode_DestinationIn;
+ } else if (compositeOperator == QLatin1String("destination-out")) {
+ return QPainter::CompositionMode_DestinationOut;
+ } else if (compositeOperator == QLatin1String("destination-over")) {
+ return QPainter::CompositionMode_DestinationOver;
+ } else if (compositeOperator == QLatin1String("darker")) {
+ return QPainter::CompositionMode_SourceOver;
+ } else if (compositeOperator == QLatin1String("lighter")) {
+ return QPainter::CompositionMode_SourceOver;
+ } else if (compositeOperator == QLatin1String("copy")) {
+ return QPainter::CompositionMode_Source;
+ } else if (compositeOperator == QLatin1String("xor")) {
+ return QPainter::CompositionMode_Xor;
+ }
+
+ return QPainter::CompositionMode_SourceOver;
+}
+
+static QString compositeOperatorToString(QPainter::CompositionMode op)
+{
+ switch (op) {
+ case QPainter::CompositionMode_SourceOver:
+ return QLatin1String("source-over");
+ case QPainter::CompositionMode_DestinationOver:
+ return QLatin1String("destination-over");
+ case QPainter::CompositionMode_Clear:
+ return QLatin1String("clear");
+ case QPainter::CompositionMode_Source:
+ return QLatin1String("source");
+ case QPainter::CompositionMode_Destination:
+ return QLatin1String("destination");
+ case QPainter::CompositionMode_SourceIn:
+ return QLatin1String("source-in");
+ case QPainter::CompositionMode_DestinationIn:
+ return QLatin1String("destination-in");
+ case QPainter::CompositionMode_SourceOut:
+ return QLatin1String("source-out");
+ case QPainter::CompositionMode_DestinationOut:
+ return QLatin1String("destination-out");
+ case QPainter::CompositionMode_SourceAtop:
+ return QLatin1String("source-atop");
+ case QPainter::CompositionMode_DestinationAtop:
+ return QLatin1String("destination-atop");
+ case QPainter::CompositionMode_Xor:
+ return QLatin1String("xor");
+ case QPainter::CompositionMode_Plus:
+ return QLatin1String("plus");
+ case QPainter::CompositionMode_Multiply:
+ return QLatin1String("multiply");
+ case QPainter::CompositionMode_Screen:
+ return QLatin1String("screen");
+ case QPainter::CompositionMode_Overlay:
+ return QLatin1String("overlay");
+ case QPainter::CompositionMode_Darken:
+ return QLatin1String("darken");
+ case QPainter::CompositionMode_Lighten:
+ return QLatin1String("lighten");
+ case QPainter::CompositionMode_ColorDodge:
+ return QLatin1String("color-dodge");
+ case QPainter::CompositionMode_ColorBurn:
+ return QLatin1String("color-burn");
+ case QPainter::CompositionMode_HardLight:
+ return QLatin1String("hard-light");
+ case QPainter::CompositionMode_SoftLight:
+ return QLatin1String("soft-light");
+ case QPainter::CompositionMode_Difference:
+ return QLatin1String("difference");
+ case QPainter::CompositionMode_Exclusion:
+ return QLatin1String("exclusion");
+ default:
+ break;
+ }
+ return QString();
+}
+
+bool QSGContext2DPrivate::hasShadow() const
+{
+ return state.shadowColor.isValid()
+ && state.shadowColor.alpha()
+ && (state.shadowBlur || state.shadowOffsetX || state.shadowOffsetY);
+}
+
+void QSGContext2DPrivate::clearShadow()
+{
+ state.shadowOffsetX = 0;
+ state.shadowOffsetY = 0;
+ state.shadowBlur = 0;
+ state.shadowColor = QColor();
+}
+
+QImage QSGContext2DPrivate::makeShadowImage(const QPixmap& pix)
+{
+ QImage shadowImg(pix.width() + state.shadowBlur * 2 + qAbs(state.shadowOffsetX),
+ pix.height() + state.shadowBlur *2 + qAbs(state.shadowOffsetY),
+ QImage::Format_ARGB32);
+ shadowImg.fill(0);
+ QPainter tmpPainter(&shadowImg);
+ tmpPainter.setCompositionMode(QPainter::CompositionMode_Source);
+ qreal shadowX = state.shadowOffsetX > 0? state.shadowOffsetX : 0;
+ qreal shadowY = state.shadowOffsetY > 0? state.shadowOffsetY : 0;
+
+ tmpPainter.drawPixmap(shadowX, shadowY, pix);
+ tmpPainter.end();
+
+ // blur the alpha channel
+ if (state.shadowBlur > 0) {
+ QImage blurred(shadowImg.size(), QImage::Format_ARGB32);
+ blurred.fill(0);
+ QPainter blurPainter(&blurred);
+ qt_blurImage(&blurPainter, shadowImg, state.shadowBlur, false, true);
+ blurPainter.end();
+ shadowImg = blurred;
+ }
+
+ // blacken the image with shadow color...
+ tmpPainter.begin(&shadowImg);
+ tmpPainter.setCompositionMode(QPainter::CompositionMode_SourceIn);
+ tmpPainter.fillRect(shadowImg.rect(), state.shadowColor);
+ tmpPainter.end();
+ return shadowImg;
+}
+
+void QSGContext2DPrivate::fillRectShadow(QPainter* p, QRectF shadowRect)
+{
+ QRectF r = shadowRect;
+ r.moveTo(0, 0);
+
+ QImage shadowImage(r.size().width() + 1, r.size().height() + 1, QImage::Format_ARGB32);
+ QPainter tp;
+ tp.begin(&shadowImage);
+ tp.fillRect(r, p->brush());
+ tp.end();
+ shadowImage = makeShadowImage(QPixmap::fromImage(shadowImage));
+
+ qreal dx = shadowRect.left() + (state.shadowOffsetX < 0? state.shadowOffsetX:0);
+ qreal dy = shadowRect.top() + (state.shadowOffsetY < 0? state.shadowOffsetY:0);
+
+ p->drawImage(dx, dy, shadowImage);
+ p->fillRect(shadowRect, p->brush());
+}
+
+void QSGContext2DPrivate::fillShadowPath(QPainter* p, const QPainterPath& path)
+{
+ QRectF r = path.boundingRect();
+ QImage img(r.size().width() + r.left() + 1,
+ r.size().height() + r.top() + 1,
+ QImage::Format_ARGB32);
+ img.fill(0);
+ QPainter tp(&img);
+ tp.fillPath(path.translated(0, 0), p->brush());
+ tp.end();
+
+ QImage shadowImage = makeShadowImage(QPixmap::fromImage(img));
+ qreal dx = r.left() + (state.shadowOffsetX < 0? state.shadowOffsetX:0);
+ qreal dy = r.top() + (state.shadowOffsetY < 0? state.shadowOffsetY:0);
+
+ p->drawImage(dx, dy, shadowImage);
+ p->fillPath(path, p->brush());
+}
+
+void QSGContext2DPrivate::strokeShadowPath(QPainter* p, const QPainterPath& path)
+{
+ QRectF r = path.boundingRect();
+ QImage img(r.size().width() + r.left() + 1,
+ r.size().height() + r.top() + 1,
+ QImage::Format_ARGB32);
+ img.fill(0);
+ QPainter tp(&img);
+ tp.strokePath(path, p->pen());
+ tp.end();
+
+ QImage shadowImage = makeShadowImage(QPixmap::fromImage(img));
+ qreal dx = r.left() + (state.shadowOffsetX < 0? state.shadowOffsetX:0);
+ qreal dy = r.top() + (state.shadowOffsetY < 0? state.shadowOffsetY:0);
+ p->drawImage(dx, dy, shadowImage);
+ p->strokePath(path, p->pen());
+}
+
+void QSGContext2DPrivate::clear()
+{
+ clearRect(0, 0, size.width(), size.height());
+}
+
+void QSGContext2DPrivate::reset()
+{
+ stateStack.clear();
+ state.matrix = QMatrix();
+ state.clipPath = QPainterPath();
+ state.strokeStyle = Qt::black;
+ state.fillStyle = Qt::black;
+ state.globalAlpha = 1.0;
+ state.lineWidth = 1;
+ state.lineCap = Qt::FlatCap;
+ state.lineJoin = Qt::MiterJoin;
+ state.miterLimit = 10;
+ state.shadowOffsetX = 0;
+ state.shadowOffsetY = 0;
+ state.shadowBlur = 0;
+ state.shadowColor = qRgba(0, 0, 0, 0);
+ state.globalCompositeOperation = QPainter::CompositionMode_SourceOver;
+ state.font = QFont();
+ state.textAlign = QSGContext2D::Start;
+ state.textBaseline = QSGContext2D::Alphabetic;
+ clear();
+}
+
+
+void QSGContext2DPrivate::updateMatrix(const QMatrix& m)
+{
+ commands.push_back(QSGContext2D::UpdateMatrix);
+ matrixes.push_back(m);
+}
+
+
+
+
+void QSGContext2DPrivate::save()
+{
+ stateStack.push(state);
+}
+
+void QSGContext2DPrivate::restore()
+{
+ if (!stateStack.isEmpty()) {
+ bool update = false;
+ QSGContext2D::State s = stateStack.pop();
+ if (state.matrix != s.matrix) {
+ updateMatrix(s.matrix);
+ update = true;
+ }
+
+ if (s.pen != state.pen) {
+ commands.push_back(QSGContext2D::UpdatePen);
+ pens.push_back(s.pen);
+ update = true;
+ }
+
+ if (s.globalAlpha != state.globalAlpha) {
+ commands.push_back(QSGContext2D::GlobalAlpha);
+ reals.push_back(s.globalAlpha);
+ update = true;
+ }
+
+ if (s.globalCompositeOperation != state.globalCompositeOperation) {
+ commands.push_back(QSGContext2D::GlobalCompositeOperation);
+ ints.push_back(s.globalCompositeOperation);
+ update = true;
+ }
+
+ if (s.font != state.font) {
+ commands.push_back(QSGContext2D::Font);
+ fonts.push_back(s.font);
+ update = true;
+ }
+
+ if (s.fillStyle != state.fillStyle) {
+ commands.push_back(QSGContext2D::FillStyle);
+ brushes.push_back(s.fillStyle);
+ update = true;
+ }
+
+ if (s.clipPath != state.clipPath) {
+ //commands.push_back(QSGContext2D::ClipPath);
+ update = true;
+ }
+
+ if (s.textAlign != state.textAlign) {
+ commands.push_back(QSGContext2D::TextAlign);
+ update = true;
+ }
+
+ if (s.textBaseline != state.textBaseline) {
+ commands.push_back(QSGContext2D::TextBaseline);
+ update = true;
+ }
+
+ if (s.shadowBlur != state.shadowBlur
+ || s.shadowColor != state.shadowColor
+ || s.shadowOffsetX != state.shadowOffsetX
+ || s.shadowOffsetY != state.shadowOffsetY) {
+ update = true;
+ }
+
+ if (update)
+ state = s;
+ }
+}
+
+void QSGContext2DPrivate::scale(qreal x, qreal y)
+{
+ state.matrix.scale(x, y);
+ updateMatrix(state.matrix);
+}
+
+void QSGContext2DPrivate::rotate(qreal angle)
+{
+ state.matrix.rotate(DEGREES(angle));
+ updateMatrix(state.matrix);
+}
+
+
+void QSGContext2DPrivate::translate(qreal x, qreal y)
+{
+ state.matrix.translate(x, y);
+ updateMatrix(state.matrix);
+}
+
+void QSGContext2DPrivate::transform(
+ qreal m11, qreal m12,
+ qreal m21, qreal m22,
+ qreal dx, qreal dy)
+{
+ QMatrix matrix(m11, m12, m21, m22, dx, dy);
+ state.matrix *= matrix;
+ updateMatrix(state.matrix);
+}
+
+void QSGContext2DPrivate::setTransform(
+ qreal m11, qreal m12,
+ qreal m21, qreal m22,
+ qreal dx, qreal dy)
+{
+ QMatrix matrix(m11, m12, m21, m22, dx, dy);
+ state.matrix = matrix;
+ updateMatrix(state.matrix);
+}
+
+void QSGContext2DPrivate::clearRect(qreal x, qreal y,
+ qreal w, qreal h)
+{
+ commands.push_back(QSGContext2D::ClearRect);
+ reals.push_back(x);
+ reals.push_back(y);
+ reals.push_back(w);
+ reals.push_back(h);
+}
+
+void QSGContext2DPrivate::fillRect(qreal x, qreal y,
+ qreal w, qreal h)
+{
+ commands.push_back(QSGContext2D::FillRect);
+ reals.push_back(x);
+ reals.push_back(y);
+ reals.push_back(w);
+ reals.push_back(h);
+}
+
+void QSGContext2DPrivate::strokeRect(qreal x, qreal y,
+ qreal w, qreal h)
+{
+ QPainterPath path;
+ path.addRect(x, y, w, h);
+ commands.push_back(QSGContext2D::Stroke);
+ pathes.push_back(path);
+}
+
+void QSGContext2DPrivate::beginPath()
+{
+ path = QPainterPath();
+}
+
+void QSGContext2DPrivate::closePath()
+{
+ path.closeSubpath();
+}
+
+void QSGContext2DPrivate::moveTo( qreal x, qreal y)
+{
+ path.moveTo(state.matrix.map(QPointF(x, y)));
+}
+
+void QSGContext2DPrivate::lineTo( qreal x, qreal y)
+{
+ path.lineTo(state.matrix.map(QPointF(x, y)));
+}
+
+void QSGContext2DPrivate::quadraticCurveTo(qreal cpx, qreal cpy,
+ qreal x, qreal y)
+{
+ path.quadTo(state.matrix.map(QPointF(cpx, cpy)),
+ state.matrix.map(QPointF(x, y)));
+}
+
+void QSGContext2DPrivate::bezierCurveTo(qreal cp1x, qreal cp1y,
+ qreal cp2x, qreal cp2y,
+ qreal x, qreal y)
+{
+ path.cubicTo(state.matrix.map(QPointF(cp1x, cp1y)),
+ state.matrix.map(QPointF(cp2x, cp2y)),
+ state.matrix.map(QPointF(x, y)));
+}
+
+void QSGContext2DPrivate::arcTo(qreal x1, qreal y1,
+ qreal x2, qreal y2,
+ qreal radius)
+{
+ QPointF st = state.matrix.map(QPoint(x1, y1));
+ QPointF end = state.matrix.map(QPoint(x2, y2));
+
+ path.arcTo(st.x(), st.y(),
+ end.x()-st.x(), end.y()-st.y(),
+ radius, 90);
+}
+
+void QSGContext2DPrivate::rect(qreal x, qreal y,
+ qreal w, qreal h)
+{
+ QPainterPath path;
+ path.addRect(QRectF(x, y, w, h));
+ path.addPath(state.matrix.map(path));
+}
+
+void QSGContext2DPrivate::arc(qreal xc,
+ qreal yc,
+ qreal radius,
+ qreal sar,
+ qreal ear,
+ bool antiClockWise)
+{
+ QPainterPath path;
+
+ //### HACK
+
+ // In Qt we don't switch the coordinate system for degrees
+ // and still use the 0,0 as bottom left for degrees so we need
+ // to switch
+ sar = -sar;
+ ear = -ear;
+ antiClockWise = !antiClockWise;
+ //end hack
+
+ float sa = DEGREES(sar);
+ float ea = DEGREES(ear);
+
+ double span = 0;
+
+ double xs = xc - radius;
+ double ys = yc - radius;
+ double width = radius*2;
+ double height = radius*2;
+
+ if (!antiClockWise && (ea < sa)) {
+ span += 360;
+ } else if (antiClockWise && (sa < ea)) {
+ span -= 360;
+ }
+
+ //### this is also due to switched coordinate system
+ // we would end up with a 0 span instead of 360
+ if (!(qFuzzyCompare(span + (ea - sa) + 1, 1) &&
+ qFuzzyCompare(qAbs(span), 360))) {
+ span += ea - sa;
+ }
+
+ path.moveTo(QPointF(xc + radius * qCos(sar),
+ yc - radius * qSin(sar)));
+
+ path.arcTo(xs, ys, width, height, sa, span);
+
+ path.addPath(state.matrix.map(path));
+}
+
+void QSGContext2DPrivate::fill()
+{
+ commands.push_back(QSGContext2D::Fill);
+ pathes.push_back(path);
+}
+
+void QSGContext2DPrivate::stroke()
+{
+ commands.push_back(QSGContext2D::Stroke);
+ pathes.push_back(path);
+// painter->setMatrix(state.matrix, false);
+// QPainterPath tmp = state.matrix.inverted().map(path); //why?
+// painter->strokePath(tmp, painter->pen());
+}
+
+void QSGContext2DPrivate::clip()
+{
+ state.clipPath = path;
+ pathes.push_back(state.clipPath);
+ commands.push_back(QSGContext2D::Clip);
+}
+
+void QSGContext2DPrivate::setGlobalAlpha( qreal alpha)
+{
+ state.globalAlpha = alpha;
+ commands.push_back(QSGContext2D::GlobalAlpha);
+ reals.push_back(state.globalAlpha);
+}
+
+void QSGContext2DPrivate::setGlobalCompositeOperation( const QString &op)
+{
+ state.globalCompositeOperation = compositeOperatorFromString(op);
+ commands.push_back(QSGContext2D::GlobalCompositeOperation);
+ ints.push_back(state.globalCompositeOperation);
+}
+
+void QSGContext2DPrivate::setStrokeStyle( const QVariant &style)
+{
+ QSGCanvasGradient *gradient= qobject_cast<QSGCanvasGradient*>(style.value<QObject*>());
+ QBrush b;
+ if (gradient) {
+ b = gradient->value();
+ } else {
+ b = colorFromString(style.toString());
+ }
+
+ if (state.strokeStyle != b) {
+ state.strokeStyle = b;
+ state.pen.setBrush(state.strokeStyle);
+ commands.push_back(QSGContext2D::UpdatePen);
+ pens.push_back(state.pen);
+ }
+}
+void QSGContext2DPrivate::setStrokeColor(const QColor& color)
+{
+ if (state.strokeStyle != color) {
+ state.strokeStyle = color;
+ commands.push_back(QSGContext2D::UpdatePen);
+ QPen pen;
+ pen.setBrush(state.strokeStyle);
+ pens.push_back(pen);
+ }
+}
+
+void QSGContext2DPrivate::setFillColor(const QColor& color)
+{
+ if (state.fillStyle != color) {
+ state.fillStyle = color;
+ commands.push_back(QSGContext2D::UpdateBrush);
+ brushes.push_back(state.fillStyle);
+ }
+}
+
+void QSGContext2DPrivate::setFillStyle( const QVariant &style)
+{
+ QSGCanvasGradient *gradient= qobject_cast<QSGCanvasGradient*>(style.value<QObject*>());
+ QBrush b;
+ if (gradient) {
+ b = gradient->value();
+ } else {
+ b = colorFromString(style.toString());
+ }
+
+ if (state.fillStyle != b) {
+ state.fillStyle = b;
+ commands.push_back(QSGContext2D::UpdateBrush);
+ brushes.push_back(b);
+ }
+}
+
+
+void QSGContext2DPrivate::setLineWidth( qreal w)
+{
+ if (state.lineWidth != w) {
+ state.pen.setWidthF(w);
+ state.lineWidth = w;
+ commands.push_back(QSGContext2D::UpdatePen);
+ pens.push_back(state.pen);
+ }
+}
+
+void QSGContext2DPrivate::setLineCap( const QString& cap)
+{
+ Qt::PenCapStyle style;
+ if (cap == QLatin1String("round"))
+ style = Qt::RoundCap;
+ else if (cap == QLatin1String("square"))
+ style = Qt::SquareCap;
+ else //if (capString == "butt")
+ style = Qt::FlatCap;
+
+
+ if (state.lineCap != style) {
+ state.pen.setCapStyle(style);
+ state.lineCap = style;
+ commands.push_back(QSGContext2D::UpdatePen);
+ pens.push_back(state.pen);
+ }
+}
+
+void QSGContext2DPrivate::setLineJoin( const QString& join)
+{
+ Qt::PenJoinStyle style;
+ if (join == QLatin1String("round"))
+ style = Qt::RoundJoin;
+ else if (join == QLatin1String("bevel"))
+ style = Qt::BevelJoin;
+ else //if (joinString == "miter")
+ style = Qt::MiterJoin;
+ if (state.lineJoin != style) {
+ state.lineJoin = style;
+ state.pen.setJoinStyle(style);
+ commands.push_back(QSGContext2D::UpdatePen);
+ pens.push_back(state.pen);
+ }
+}
+
+void QSGContext2DPrivate::setMiterLimit( qreal limit)
+{
+ if (state.miterLimit != limit) {
+ state.pen.setMiterLimit(limit);
+ state.miterLimit = limit;
+ commands.push_back(QSGContext2D::UpdatePen);
+ pens.push_back(state.pen);
+ }
+}
+
+void QSGContext2DPrivate::setShadowOffsetX( qreal x)
+{
+ if (state.shadowOffsetX != x) {
+ state.shadowOffsetX = x;
+ commands.push_back(QSGContext2D::ShadowOffsetX);
+ reals.push_back(x);
+ }
+}
+
+void QSGContext2DPrivate::setShadowOffsetY( qreal y)
+{
+ if (state.shadowOffsetY != y) {
+ state.shadowOffsetY = y;
+ commands.push_back(QSGContext2D::ShadowOffsetY);
+ reals.push_back(y);
+ }
+}
+
+void QSGContext2DPrivate::setShadowBlur( qreal b)
+{
+ if (state.shadowBlur != b) {
+ state.shadowBlur = b;
+ commands.push_back(QSGContext2D::ShadowBlur);
+ reals.push_back(b);
+ }
+}
+
+void QSGContext2DPrivate::setShadowColor( const QString& color)
+{
+ QColor c = colorFromString(color);
+ if (state.shadowColor != c) {
+ state.shadowColor = c;
+ commands.push_back(QSGContext2D::ShadowColor);
+ colors.push_back(c);
+ }
+}
+
+void QSGContext2DPrivate::setFont( const QString& fontString)
+{
+ QFont font;
+ // ### this is simplified and incomplete
+ // ### TODO:get code from Qt webkit
+ QStringList tokens = fontString.split(QLatin1String(" "));
+ foreach (const QString &token, tokens) {
+ if (token == QLatin1String("italic"))
+ font.setItalic(true);
+ else if (token == QLatin1String("bold"))
+ font.setBold(true);
+ else if (token.endsWith(QLatin1String("px"))) {
+ QString number = token;
+ number.remove(QLatin1String("px"));
+ font.setPointSizeF(number.trimmed().toFloat());
+ } else
+ font.setFamily(token);
+ }
+
+ if (state.font != font) {
+ state.font = font;
+ commands.push_back(QSGContext2D::Font);
+ fonts.push_back(font);
+ }
+}
+
+void QSGContext2DPrivate::setTextBaseline( const QString& baseline)
+{
+ QSGContext2D::TextBaseLineType tbl;
+ if (baseline==QLatin1String("alphabetic"))
+ tbl = QSGContext2D::Alphabetic;
+ else if (baseline == QLatin1String("hanging"))
+ tbl = QSGContext2D::Hanging;
+ else if (baseline == QLatin1String("top"))
+ tbl = QSGContext2D::Top;
+ else if (baseline == QLatin1String("bottom"))
+ tbl = QSGContext2D::Bottom;
+ else if (baseline == QLatin1String("middle"))
+ tbl = QSGContext2D::Middle;
+ else {
+ tbl = QSGContext2D::Alphabetic;
+ Q_Q(QSGContext2D);
+ qmlInfo(q) << "QSGContext2D: invalid baseline:" << baseline;
+ }
+ if (state.textBaseline != tbl) {
+ state.textBaseline = tbl;
+ commands.push_back(QSGContext2D::TextBaseline);
+ ints.push_back(tbl);
+ }
+}
+
+void QSGContext2DPrivate::setTextAlign(const QString& align)
+{
+ QSGContext2D::TextAlignType ta;
+ if (align==QLatin1String("start"))
+ ta = QSGContext2D::Start;
+ else if (align == QLatin1String("end"))
+ ta = QSGContext2D::End;
+ else if (align == QLatin1String("left"))
+ ta = QSGContext2D::Left;
+ else if (align == QLatin1String("right"))
+ ta = QSGContext2D::Right;
+ else if (align == QLatin1String("center"))
+ ta = QSGContext2D::Center;
+ else {
+ ta = QSGContext2D::Start;
+ Q_Q(QSGContext2D);
+ qmlInfo(q) << "QSGContext2D: invalid text align:" << align;
+ }
+ if (state.textAlign != ta) {
+ state.textAlign = ta;
+ commands.push_back(QSGContext2D::TextAlign);
+ ints.push_back(ta);
+ }
+}
+
+void QSGContext2DPrivate::fillText(const QString& text, qreal x, qreal y)
+{
+ commands.push_back(QSGContext2D::FillText);
+ strings.push_back(text);
+ reals.push_back(x);
+ reals.push_back(y);
+ ints.push_back(state.textAlign);
+ ints.push_back(state.textBaseline);
+}
+
+
+void QSGContext2DPrivate::strokeText( const QString& text, qreal x, qreal y)
+{
+ commands.push_back(QSGContext2D::StrokeText);
+ strings.push_back(text);
+ reals.push_back(x);
+ reals.push_back(y);
+ ints.push_back(state.textAlign);
+ ints.push_back(state.textBaseline);
+}
+
+void QSGContext2DPrivate::drawImage(const QString& url, qreal dx, qreal dy)
+{
+ commands.push_back(QSGContext2D::DrawImage1);
+ strings.push_back(url);
+ reals.push_back(dx);
+ reals.push_back(dy);
+}
+
+void QSGContext2DPrivate::drawImage(const QString& url, qreal dx, qreal dy, qreal dw, qreal dh)
+{
+ commands.push_back(QSGContext2D::DrawImage2);
+ strings.push_back(url);
+ reals.push_back(dx);
+ reals.push_back(dy);
+ reals.push_back(dw);
+ reals.push_back(dh);
+}
+
+void QSGContext2DPrivate::drawImage(const QString& url, qreal sx, qreal sy, qreal sw, qreal sh, qreal dx, qreal dy, qreal dw, qreal dh)
+{
+ commands.push_back(QSGContext2D::DrawImage3);
+ strings.push_back(url);
+ reals.push_back(sx);
+ reals.push_back(sy);
+ reals.push_back(sw);
+ reals.push_back(sh);
+ reals.push_back(dx);
+ reals.push_back(dy);
+ reals.push_back(dw);
+ reals.push_back(dh);
+}
+
+QList<int> QSGContext2DPrivate::getImageData(qreal sx, qreal sy, qreal sw, qreal sh)
+{
+ Q_Q(QSGContext2D);
+ waitingForPainting = true;
+ commands.push_back(QSGContext2D::GetImageData);
+ reals.push_back(sx);
+ reals.push_back(sy);
+ reals.push_back(sw);
+ reals.push_back(sh);
+ q->sync();
+ return imageData;
+}
+
+void QSGContext2DPrivate::putImageData(const QVariantList& imageData, qreal dx, qreal dy, qreal w, qreal h)
+{
+ QImage image = cachedImage.copy(dx, dy, w, h);
+ uchar* data = image.bits();
+ int i = 0;
+ while(i< imageData.size() && i < image.byteCount()) {
+ //the stored order in QImage:BGRA
+ //the stored order in Canvas:RGBA
+ *(data+i) = imageData[i+2].toInt();//B
+ *(data+i+1) = imageData[i+1].toInt();//G
+ *(data+i+2) = imageData[i].toInt();//R
+ *(data+i+3) = imageData[i+3].toInt();//A
+ i+=4;
+ }
+ commands.push_back(QSGContext2D::PutImageData);
+ images.push_back(image);
+ reals.push_back(dx);
+ reals.push_back(dy);
+}
+
+void QSGContext2D::save()
+{
+ Q_D(QSGContext2D);
+ d->save();
+}
+
+
+void QSGContext2D::restore()
+{
+ Q_D(QSGContext2D);
+ d->restore();
+}
+
+
+void QSGContext2D::scale(qreal x, qreal y)
+{
+ Q_D(QSGContext2D);
+ d->scale(x, y);
+}
+
+
+void QSGContext2D::rotate(qreal angle)
+{
+ Q_D(QSGContext2D);
+ d->rotate(angle);
+}
+
+
+void QSGContext2D::translate(qreal x, qreal y)
+{
+ Q_D(QSGContext2D);
+ d->translate(x, y);
+}
+
+void QSGContext2D::transform(qreal m11, qreal m12, qreal m21, qreal m22,
+ qreal dx, qreal dy)
+{
+ Q_D(QSGContext2D);
+ d->transform(m11, m12, m21, m22, dx, dy);
+}
+
+
+void QSGContext2D::setTransform(qreal m11, qreal m12, qreal m21, qreal m22,
+ qreal dx, qreal dy)
+{
+ Q_D(QSGContext2D);
+ d->setTransform(m11, m12, m21, m22, dx, dy);
+}
+
+QString QSGContext2D::globalCompositeOperation() const
+{
+ Q_D(const QSGContext2D);
+ return compositeOperatorToString(d->state.globalCompositeOperation);
+}
+
+void QSGContext2D::setGlobalCompositeOperation(const QString &op)
+{
+ Q_D(QSGContext2D);
+ d->setGlobalCompositeOperation(op);
+}
+
+QVariant QSGContext2D::strokeStyle() const
+{
+ Q_D(const QSGContext2D);
+ return d->state.strokeStyle;
+}
+
+void QSGContext2D::setStrokeStyle(const QVariant &style)
+{
+ Q_D(QSGContext2D);
+ d->setStrokeStyle(style);
+}
+
+QVariant QSGContext2D::fillStyle() const
+{
+ Q_D(const QSGContext2D);
+ return d->state.fillStyle;
+}
+
+QColor QSGContext2D::strokeColor() const
+{
+ Q_D(const QSGContext2D);
+ return d->state.strokeStyle.color();
+}
+
+QColor QSGContext2D::fillColor() const
+{
+ Q_D(const QSGContext2D);
+ return d->state.fillStyle.color();
+}
+
+void QSGContext2D::setFillStyle(const QVariant &style)
+{
+ Q_D(QSGContext2D);
+ d->setFillStyle(style);
+}
+void QSGContext2D::setStrokeColor(const QColor& color)
+{
+ Q_D(QSGContext2D);
+ d->setStrokeColor(color);
+}
+
+void QSGContext2D::setFillColor(const QColor& color)
+{
+ Q_D(QSGContext2D);
+ d->setFillColor(color);
+}
+
+qreal QSGContext2D::globalAlpha() const
+{
+ Q_D(const QSGContext2D);
+ return d->state.globalAlpha;
+}
+
+void QSGContext2D::setGlobalAlpha(qreal alpha)
+{
+ Q_D(QSGContext2D);
+ d->setGlobalAlpha(alpha);
+}
+
+QSGImage *QSGContext2D::createImage(const QString &url)
+{
+ Q_D(QSGContext2D);
+//### cache image
+ QSGImage* img = new QSGImage(d->canvas);
+ img->setSource(QUrl(url));
+ return img;
+}
+
+QSGCanvasGradient *QSGContext2D::createLinearGradient(qreal x0, qreal y0,
+ qreal x1, qreal y1)
+{
+ QLinearGradient g(x0, y0, x1, y1);
+ return new QSGCanvasGradient(g);
+}
+
+
+QSGCanvasGradient *QSGContext2D::createRadialGradient(qreal x0, qreal y0,
+ qreal r0, qreal x1,
+ qreal y1, qreal r1)
+{
+ QRadialGradient g(QPointF(x1, y1), r0+r1, QPointF(x0, y0));
+ return new QSGCanvasGradient(g);
+}
+
+qreal QSGContext2D::lineWidth() const
+{
+ Q_D(const QSGContext2D);
+ return d->state.lineWidth;
+}
+
+void QSGContext2D::setLineWidth(qreal w)
+{
+ Q_D(QSGContext2D);
+ d->setLineWidth(w);
+}
+
+QString QSGContext2D::lineCap() const
+{
+ Q_D(const QSGContext2D);
+ switch(d->state.lineCap) {
+ case Qt::RoundCap:
+ return QLatin1String("round");
+ case Qt::FlatCap:
+ return QLatin1String("butt");
+ case Qt::SquareCap:
+ return QLatin1String("square");
+ default:
+ break;
+ }
+ return QLatin1String("");
+}
+
+void QSGContext2D::setLineCap(const QString &capString)
+{
+ Q_D(QSGContext2D);
+ d->setLineCap(capString);
+}
+
+QString QSGContext2D::lineJoin() const
+{
+ Q_D(const QSGContext2D);
+ switch (d->state.lineJoin) {
+ case Qt::RoundJoin:
+ return QLatin1String("round");
+ case Qt::BevelJoin:
+ return QLatin1String("bevel");
+ case Qt::MiterJoin:
+ return QLatin1String("miter");
+ default:
+ break;
+ }
+ return QLatin1String("");
+}
+
+void QSGContext2D::setLineJoin(const QString &joinString)
+{
+ Q_D(QSGContext2D);
+ d->setLineJoin(joinString);
+}
+
+qreal QSGContext2D::miterLimit() const
+{
+ Q_D(const QSGContext2D);
+ return d->state.miterLimit;
+}
+
+void QSGContext2D::setMiterLimit(qreal m)
+{
+ Q_D(QSGContext2D);
+ d->setMiterLimit(m);
+}
+
+void QSGContext2D::setShadowOffsetX(qreal x)
+{
+ Q_D(QSGContext2D);
+ d->setShadowOffsetX(x);
+}
+
+void QSGContext2D::setShadowOffsetY(qreal y)
+{
+ Q_D(QSGContext2D);
+ d->setShadowOffsetY(y);
+}
+
+void QSGContext2D::setShadowBlur(qreal b)
+{
+ Q_D(QSGContext2D);
+ d->setShadowBlur(b);
+}
+
+void QSGContext2D::setShadowColor(const QString &str)
+{
+ Q_D(QSGContext2D);
+ d->setShadowColor(str);
+}
+
+QString QSGContext2D::textBaseline() const
+{
+ Q_D(const QSGContext2D);
+ switch(d->state.textBaseline) {
+ case QSGContext2D::Alphabetic:
+ return QLatin1String("alphabetic");
+ case QSGContext2D::Hanging:
+ return QLatin1String("hanging");
+ case QSGContext2D::Top:
+ return QLatin1String("top");
+ case QSGContext2D::Bottom:
+ return QLatin1String("bottom");
+ case QSGContext2D::Middle:
+ return QLatin1String("middle");
+ default:
+ break;
+ }
+ return QLatin1String("alphabetic");
+}
+
+void QSGContext2D::setTextBaseline(const QString &baseline)
+{
+ Q_D(QSGContext2D);
+ d->setTextBaseline(baseline);
+}
+
+QString QSGContext2D::textAlign() const
+{
+ Q_D(const QSGContext2D);
+ switch(d->state.textAlign) {
+ case QSGContext2D::Start:
+ return QLatin1String("start");
+ case QSGContext2D::End:
+ return QLatin1String("end");
+ case QSGContext2D::Left:
+ return QLatin1String("left");
+ case QSGContext2D::Right:
+ return QLatin1String("right");
+ case QSGContext2D::Center:
+ return QLatin1String("center");
+ default:
+ break;
+ }
+ return QLatin1String("start");
+}
+
+void QSGContext2D::setTextAlign(const QString &align)
+{
+ Q_D(QSGContext2D);
+ d->setTextAlign(align);
+
+ d->commands.push_back(QSGContext2D::TextAlign);
+ d->ints.push_back(d->state.textAlign);
+}
+
+void QSGContext2D::setFont(const QString &fontString)
+{
+ Q_D(QSGContext2D);
+ d->setFont(fontString);
+}
+
+QString QSGContext2D::font() const
+{
+ //### TODO
+ Q_D(const QSGContext2D);
+ return d->state.font.toString();
+}
+
+qreal QSGContext2D::shadowOffsetX() const
+{
+ Q_D(const QSGContext2D);
+ return d->state.shadowOffsetX;
+}
+
+qreal QSGContext2D::shadowOffsetY() const
+{
+ Q_D(const QSGContext2D);
+ return d->state.shadowOffsetY;
+}
+
+
+qreal QSGContext2D::shadowBlur() const
+{
+ Q_D(const QSGContext2D);
+ return d->state.shadowBlur;
+}
+
+
+QString QSGContext2D::shadowColor() const
+{
+ Q_D(const QSGContext2D);
+ return d->state.shadowColor.name();
+}
+
+
+void QSGContext2D::clearRect(qreal x, qreal y, qreal w, qreal h)
+{
+ Q_D(QSGContext2D);
+ d->clearRect(x, y, w, h);
+}
+
+void QSGContext2D::fillRect(qreal x, qreal y, qreal w, qreal h)
+{
+ Q_D(QSGContext2D);
+ d->fillRect(x, y, w, h);
+}
+
+int QSGContext2DPrivate::baseLineOffset(QSGContext2D::TextBaseLineType value, const QFontMetrics &metrics)
+{
+ int offset = 0;
+ switch (value) {
+ case QSGContext2D::Top:
+ break;
+ case QSGContext2D::Alphabetic:
+ case QSGContext2D::Middle:
+ case QSGContext2D::Hanging:
+ offset = metrics.ascent();
+ break;
+ case QSGContext2D::Bottom:
+ offset = metrics.height();
+ break;
+ }
+ return offset;
+}
+
+int QSGContext2DPrivate::textAlignOffset(QSGContext2D::TextAlignType value, const QFontMetrics &metrics, const QString &text)
+{
+ int offset = 0;
+ if (value == QSGContext2D::Start)
+ value = qApp->layoutDirection() == Qt::LeftToRight ? QSGContext2D::Left : QSGContext2D::Right;
+ else if (value == QSGContext2D::End)
+ value = qApp->layoutDirection() == Qt::LeftToRight ? QSGContext2D::Right: QSGContext2D::Left;
+ switch (value) {
+ case QSGContext2D::Center:
+ offset = metrics.width(text)/2;
+ break;
+ case QSGContext2D::Right:
+ offset = metrics.width(text);
+ case QSGContext2D::Left:
+ default:
+ break;
+ }
+ return offset;
+}
+
+void QSGContext2D::fillText(const QString &text, qreal x, qreal y)
+{
+ Q_D(QSGContext2D);
+ d->fillText(text, x, y);
+}
+
+void QSGContext2D::strokeText(const QString &text, qreal x, qreal y)
+{
+ Q_D(QSGContext2D);
+ d->strokeText(text, x, y);
+}
+
+void QSGContext2D::strokeRect(qreal x, qreal y, qreal w, qreal h)
+{
+ Q_D(QSGContext2D);
+ d->strokeRect(x, y, w, h);
+}
+
+void QSGContext2D::beginPath()
+{
+ Q_D(QSGContext2D);
+ d->beginPath();
+}
+
+
+void QSGContext2D::closePath()
+{
+ Q_D(QSGContext2D);
+ d->closePath();
+}
+
+
+void QSGContext2D::moveTo(qreal x, qreal y)
+{
+ Q_D(QSGContext2D);
+ d->moveTo(x, y);
+}
+
+
+void QSGContext2D::lineTo(qreal x, qreal y)
+{
+ Q_D(QSGContext2D);
+ d->lineTo(x, y);
+}
+
+
+void QSGContext2D::quadraticCurveTo(qreal cpx, qreal cpy, qreal x, qreal y)
+{
+ Q_D(QSGContext2D);
+ d->quadraticCurveTo(cpx, cpy, x, y);
+}
+
+
+void QSGContext2D::bezierCurveTo(qreal cp1x, qreal cp1y,
+ qreal cp2x, qreal cp2y, qreal x, qreal y)
+{
+ Q_D(QSGContext2D);
+ d->bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y);
+}
+
+
+void QSGContext2D::arcTo(qreal x1, qreal y1, qreal x2, qreal y2, qreal radius)
+{
+ Q_D(QSGContext2D);
+ d->arcTo(x1, y1, x2, y2, radius);
+}
+
+
+void QSGContext2D::rect(qreal x, qreal y, qreal w, qreal h)
+{
+ Q_D(QSGContext2D);
+ d->rect(x, y, w, h);
+}
+
+void QSGContext2D::arc(qreal xc, qreal yc, qreal radius,
+ qreal sar, qreal ear,
+ bool anticlockwise)
+{
+ Q_D(QSGContext2D);
+ d->arc(xc, yc, radius, sar, ear, anticlockwise);
+}
+
+
+void QSGContext2D::fill()
+{
+ Q_D(QSGContext2D);
+ d->fill();
+}
+
+
+void QSGContext2D::stroke()
+{
+ Q_D(QSGContext2D);
+ d->stroke();
+}
+
+
+void QSGContext2D::clip()
+{
+ Q_D(QSGContext2D);
+ d->clip();
+}
+
+
+bool QSGContext2D::isPointInPath(qreal x, qreal y) const
+{
+ Q_D(const QSGContext2D);
+ return d->path.contains(QPointF(x, y));
+}
+
+
+QList<int> QSGContext2D::getImageData(qreal sx, qreal sy, qreal sw, qreal sh)
+{
+ Q_D(QSGContext2D);
+ return d->getImageData(sx, sy, sw, sh);
+}
+
+void QSGContext2D::putImageData(const QVariant& imageData, qreal x, qreal y, qreal w, qreal h)
+{
+ Q_D(QSGContext2D);
+ return d->putImageData(imageData.toList(), x, y, w, h);
+}
+
+QSGContext2D::QSGContext2D(QObject *parent)
+ : QObject(*(new QSGContext2DPrivate()), parent)
+{
+ Q_D(QSGContext2D);
+ d->canvas = qobject_cast<QSGCanvasItem*>(parent);
+}
+
+QSGContext2D::QSGContext2D(QSGContext2D *orig, QSGContext2DWorkerAgent* agentData)
+ : QObject(*(new QSGContext2DPrivate()), 0)
+{
+ Q_D(QSGContext2D);
+ d->agent = 0;
+ d->agentData = agentData;
+ if (d->agentData) {
+ d->agentData->orig = orig;
+ }
+ d->canvas = qobject_cast<QSGCanvasItem*>(orig);
+}
+
+QSGContext2D::~QSGContext2D()
+{
+ Q_D(QSGContext2D);
+ if (d->agent) {
+ d->agentData->syncDone.wakeAll();
+ d->agent->release();
+ }
+}
+
+bool QSGContext2D::isDirty() const
+{
+ Q_D(const QSGContext2D);
+ return !d->commands.isEmpty();
+}
+
+QScriptValue QSGContext2D::scriptValue() const
+{
+ Q_D(const QSGContext2D);
+ return d->scriptValue;
+}
+
+void QSGContext2D::setScriptEngine(QScriptEngine *eng)
+{
+ Q_D(QSGContext2D);
+ if (d->scriptEngine != eng) {
+ d->scriptEngine = eng;
+// QScriptValue agent = d->scriptEngine->globalObject().property(QLatin1String("Context2DAgent"));
+// if (!agent.isValid()) {
+// d->scriptEngine->evaluate(QLatin1String(
+// "(function CanvasImageData(w, h, d) {"
+// " this.widht = w;"
+// " this.height = h;"
+// " this.data = d;"
+// " })"));
+// d->scriptEngine->evaluate(agentScript());
+// agent = d->scriptEngine->globalObject().property(QLatin1String("Context2DAgent"));
+// if (!agent.isValid()) {
+// qWarning() << "QSGContext2D:error when evaluating context2d script value!";
+// d->scriptValue = QScriptValue();
+// return;
+// }
+// }
+// QScriptValue o = d->scriptEngine->newQObject(this);
+// d->scriptValue = agent.construct(QScriptValueList() << o);
+ }
+}
+
+QScriptEngine *QSGContext2D::scriptEngine() const
+{
+ Q_D(const QSGContext2D);
+ return d->scriptEngine;
+}
+
+void QSGContext2D::addref()
+{
+ Q_D(QSGContext2D);
+ Q_ASSERT(d->agentData);
+ d->agentData->ref.ref();
+}
+
+void QSGContext2D::release()
+{
+ Q_D(QSGContext2D);
+ Q_ASSERT(d->agentData);
+ if (!d->agentData->ref.deref()) {
+ deleteLater();
+ }
+}
+
+
+bool QSGContext2D::inWorkerThread() const
+{
+ Q_D(const QSGContext2D);
+ return d->agentData != 0;
+}
+const QString& QSGContext2D::agentScript() const
+{
+ static QString script;
+ if (script.isEmpty()) {
+ script = QString::fromLatin1(
+ "function CanvasImageData(w, h, d) {"
+ " this.width = w;"
+ " this.height = h;"
+ " this.data = d;"
+ "}"
+ "function Context2DAgent(_ctx2d) {"
+ " this._ctx = _ctx2d;"
+ " this._fillColor = '#000000';"
+ " this._fillStyle = '#000000';"
+ " this._strokeColor = '#000000';"
+ " this._strokeStyle = '#000000';"
+ " this._globalCompositeOperation = \"source-over\";"
+ " this._commands = [];"
+ " this.createImageData = function() {"
+ " var d = null;"
+ " if (arguments.length == 1 && arguments[0] instanceof CanvasImageData) {"
+ " d = new CanvasImageData(arguments[0].width,"
+ " arguments[0].height,"
+ " new Array(arguments[0].width * arguments[0].height * 4));"
+ " } else if (arguments.length == 2) {"
+ " d = new CanvasImageData(arguments[0], arguments[1], new Array(arguments[0] * arguments[1] * 4));"
+ " }"
+ " if (d)"
+ " for (var i=0; i<d.data.length; i++)"
+ " d.data[i] = 255;"
+ " return d;"
+ " };"
+ " this.getImageData = function(sx, sy, sw, sh) {"
+ " var imageData = new CanvasImageData(sw, sh, this._ctx.getImageData(sx, sy, sw, sh));"
+ " return imageData;"
+ " };"
+ " this.sync = function() {"
+ " this._ctx.processCommands(this._commands);"
+ " this._commands.length = 0;"
+ " };");
+
+ script.append(QString::fromLatin1(
+ "this.save = function() {"
+ " this._commands.push([%1]);"
+ "};").arg(Save));
+
+ script.append(QString::fromLatin1(
+ "this.restore = function() {"
+ " this._commands.push([%1]);"
+ "};").arg(Restore));
+
+ script.append(QString::fromLatin1(
+ "this.scale = function(x, y) {"
+ " this._commands.push([%1, x, y]);"
+ "};").arg(Scale));
+
+ script.append(QString::fromLatin1(
+ "this.createImage = function(url) {"
+ " return this._ctx.createImage(url);"
+ "};"));
+
+ script.append(QString::fromLatin1(
+ "this.rotate = function(x) {"
+ " this._commands.push([%1, x]);"
+ "};").arg(Rotate));
+
+ script.append(QString::fromLatin1(
+ "this.translate = function(x, y) {"
+ " this._commands.push([%1, x, y]);"
+ "};").arg(Translate));
+
+ script.append(QString::fromLatin1(
+ "this.transform = function(a1, a2, a3, a4, a5, a6) {"
+ " this._commands.push([%1, a1, a2, a3, a4, a5, a6]);"
+ "};").arg(Transform));
+
+ script.append(QString::fromLatin1(
+ "this.setTransform = function(a1, a2, a3, a4, a5, a6) {"
+ " this._commands.push([%1, a1, a2, a3, a4, a5, a6]);"
+ "};").arg(SetTransform));
+
+ script.append(QString::fromLatin1(
+ "this.clearRect = function(x, y, w, h) {"
+ " this._commands.push([%1, x, y, w, h]);"
+ "};").arg(ClearRect));
+
+ script.append(QString::fromLatin1(
+ "this.fillRect = function(x, y, w, h) {"
+ " this._commands.push([%1, x, y, w, h]);"
+ "};").arg(FillRect));
+
+ script.append(QString::fromLatin1(
+ "this.strokeRect = function(x, y, w, h) {"
+ " this._commands.push([%1, x, y, w, h]);"
+ "};").arg(StrokeRect));
+
+ script.append(QString::fromLatin1(
+ "this.beginPath = function() {"
+ " this._commands.push([%1]);"
+ "};").arg(BeginPath));
+
+ script.append(QString::fromLatin1(
+ "this.closePath = function() {"
+ " this._commands.push([%1]);"
+ "};").arg(ClosePath));
+
+ script.append(QString::fromLatin1(
+ "this.moveTo = function(x, y) {"
+ " this._commands.push([%1, x, y]);"
+ "};").arg(MoveTo));
+
+ script.append(QString::fromLatin1(
+ "this.lineTo = function(x, y) {"
+ " this._commands.push([%1, x, y]);"
+ "};").arg(LineTo));
+
+ script.append(QString::fromLatin1(
+ "this.quadraticCurveTo = function(a1, a2, a3, a4) {"
+ " this._commands.push([%1, a1, a2, a3, a4]);"
+ "};").arg(QuadraticCurveTo));
+
+ script.append(QString::fromLatin1(
+ "this.bezierCurveTo = function(a1, a2, a3, a4, a5, a6) {"
+ " this._commands.push([%1, a1, a2, a3, a4, a5, a6]);"
+ "};").arg(BezierCurveTo));
+
+ script.append(QString::fromLatin1(
+ "this.arcTo = function(x1, y1, x2, y2, radius) {"
+ " this._commands.push([%1, x1, y1, x2, y2, radius]);"
+ "};").arg(ArcTo));
+
+ script.append(QString::fromLatin1(
+ "this.rect = function(x, y, w, h) {"
+ " this._commands.push([%1, x, y, w, h]);"
+ "};").arg(Rect));
+
+ script.append(QString::fromLatin1(
+ "this.rect = function(x, y, radius, startAngle, endAngle, anticlockwise) {"
+ " this._commands.push([%1, x, y, radius, startAngle, endAngle, anticlockwise]);"
+ "};").arg(Arc));
+
+ script.append(QString::fromLatin1(
+ "this.fill = function() {"
+ " this._commands.push([%1]);"
+ "};").arg(Fill));
+
+ script.append(QString::fromLatin1(
+ "this.stroke = function() {"
+ " this._commands.push([%1]);"
+ "};").arg(Stroke));
+
+ script.append(QString::fromLatin1(
+ "this.clip = function() {"
+ " this._commands.push([%1]);"
+ "};").arg(Clip));
+
+ script.append(QString::fromLatin1(
+ " this.__defineGetter__(\"globalAlpha\", function() {"
+ " return this._globalAlpha;"
+ " });"
+ " this.__defineSetter__(\"globalAlpha\", function(v) {"
+ " this._globalAlpha = v;"
+ " this._commands.push([%1, v]);"
+ " });").arg(GlobalAlpha));
+
+ script.append(QString::fromLatin1(
+ " this.__defineGetter__(\"globalCompositeOperation\", function() {"
+ " return this._globalCompositeOperation;"
+ " });"
+ " this.__defineSetter__(\"globalCompositeOperation\", function(v) {"
+ " this._globalCompositeOperation = v;"
+ " this._commands.push([%1, v]);"
+ " });").arg(GlobalCompositeOperation));
+
+ script.append(QString::fromLatin1(
+ " this.__defineGetter__(\"strokeStyle\", function() {return this._strokeStyle; });"
+ " this.__defineSetter__(\"strokeStyle\", function(v) {"
+ " this._commands.push([%1, v]);"
+ " this._strokeStyle = v;"
+ " });").arg(StrokeStyle));
+
+ script.append(QString::fromLatin1(
+ " this.__defineGetter__(\"fillStyle\", function() {return this._fillStyle; });"
+ " this.__defineSetter__(\"fillStyle\", function(v) {"
+ " this._commands.push([%1, v]);"
+ " this._fillStyle = v;"
+ " });").arg(FillStyle));
+
+ script.append(QString::fromLatin1(
+ " this.__defineGetter__(\"strokeColor\", function() {return this._strokeColor; });"
+ " this.__defineSetter__(\"strokeColor\", function(v) {"
+ " this._commands.push([%1, v]);"
+ " this._strokeColor = v;"
+ " });").arg(StrokeColor));
+
+ script.append(QString::fromLatin1(
+ " this.__defineGetter__(\"fillColor\", function() {return this._fillColor; });"
+ " this.__defineSetter__(\"fillColor\", function(v) {"
+ " this._commands.push([%1, v]);"
+ " this._fillColor = v;"
+ " });").arg(FillColor));
+
+ script.append(QString::fromLatin1(
+ " this.__defineGetter__(\"lineWidth\", function() {return this._lineWidth; });"
+ " this.__defineSetter__(\"lineWidth\", function(v) {"
+ " this._commands.push([%1, v]);"
+ " this._lineWidth = v;"
+ " });").arg(LineWidth));
+
+ script.append(QString::fromLatin1(
+ " this.__defineGetter__(\"lineCap\", function() {return this._lineCap; });"
+ " this.__defineSetter__(\"lineCap\", function(v) {"
+ " this._commands.push([%1, v]);"
+ " this._lineCap = v;"
+ " });").arg(LineCap));
+
+
+ script.append(QString::fromLatin1(
+ " this.__defineGetter__(\"lineJoin\", function() {return this._lineJoin; });"
+ " this.__defineSetter__(\"lineJoin\", function(v) {"
+ " this._commands.push([%1, v]);"
+ " this._lineJoin = v;"
+ " });").arg(LineJoin));
+
+ script.append(QString::fromLatin1(
+ " this.__defineGetter__(\"miterLimit\", function() {return this._miterLimit; });"
+ " this.__defineSetter__(\"miterLimit\", function(v) {"
+ " this._commands.push([%1, v]);"
+ " this._miterLimit = v;"
+ " });").arg(MiterLimit));
+
+
+ script.append(QString::fromLatin1(
+ " this.__defineGetter__(\"shadowOffsetX\", function() {return this._shadowOffsetX; });"
+ " this.__defineSetter__(\"shadowOffsetX\", function(v) {"
+ " this._commands.push([%1, v]);"
+ " this._shadowOffsetX = v;"
+ " });").arg(ShadowOffsetX));
+
+ script.append(QString::fromLatin1(
+ " this.__defineGetter__(\"shadowOffsetY\", function() {return this._shadowOffsetY; });"
+ " this.__defineSetter__(\"shadowOffsetY\", function(v) {"
+ " this._commands.push([%1, v]);"
+ " this._shadowOffsetY = v;"
+ " });").arg(ShadowOffsetY));
+
+ script.append(QString::fromLatin1(
+ " this.__defineGetter__(\"shadowBlur\", function() {return this._shadowBlur; });"
+ " this.__defineSetter__(\"shadowBlur\", function(v) {"
+ " this._commands.push([%1, v]);"
+ " this._shadowBlur = v;"
+ " });").arg(ShadowBlur));
+
+ script.append(QString::fromLatin1(
+ " this.__defineGetter__(\"shadowColor\", function() {return this._shadowColor; });"
+ " this.__defineSetter__(\"shadowColor\", function(v) {"
+ " this._commands.push([%1, v]);"
+ " this._shadowColor = v;"
+ " });").arg(ShadowColor));
+
+ script.append(QString::fromLatin1(
+ " this.__defineGetter__(\"font\", function() {return this._font; });"
+ " this.__defineSetter__(\"font\", function(v) {"
+ " this._commands.push([%1, v]);"
+ " this._font = v;"
+ " });").arg(Font));
+
+ script.append(QString::fromLatin1(
+ " this.__defineGetter__(\"textBaseline\", function() {return this._textBaseline; });"
+ " this.__defineSetter__(\"textBaseline\", function(v) {"
+ " this._commands.push([%1, v]);"
+ " this._textBaseline = v;"
+ " });").arg(TextBaseline));
+
+ script.append(QString::fromLatin1(
+ " this.__defineGetter__(\"textAlign\", function() {return this._textAlign; });"
+ " this.__defineSetter__(\"textAlign\", function(v) {"
+ " this._commands.push([%1, v]);"
+ " this._textAlign = v;"
+ " });").arg(TextAlign));
+
+ script.append(QString::fromLatin1(
+ "this.fillText = function(text, x, y) {"
+ " this._commands.push([%1, text, x, y]);"
+ "};").arg(FillText));
+
+ script.append(QString::fromLatin1(
+ "this.strokeText = function(text, x, y) {"
+ " this._commands.push([%1, text, x, y]);"
+ "};").arg(StrokeText));
+
+ script.append(QString::fromLatin1(
+ "this.drawImage = function() {"
+ " if (arguments.length == 3) {"
+ " this._commands.push([%1, arguments[0], arguments[1], arguments[2]]);"
+ " } else if (arguments.length == 5) {"
+ " this._commands.push([%2, arguments[0], arguments[1], arguments[2], arguments[3], arguments[4]]);"
+ " } else if (arguments.length == 9) {"
+ " this._commands.push([%3, arguments[0], arguments[1], arguments[2], arguments[3], arguments[4], arguments[5], arguments[6], arguments[7], arguments[8]]);}"
+ "};").arg(DrawImage1).arg(DrawImage2).arg(DrawImage3));
+
+ script.append(QString::fromLatin1(
+ "this.putImageData = function() {"
+ " var dx = arguments[1];"
+ " var dy = arguments[2];"
+ " if (arguments.length == 3) {"
+ " this._commands.push([%1, arguments[0].data, dx, dy, arguments[0].width, arguments[0].height]);"
+ " } else if (arguments.length == 7) {"
+ " var dirtyX = arguments[3];"
+ " var dirtyY = arguments[4];"
+ " var dirtyWidth = arguments[5];"
+ " var dirtyHeight = arguments[6];"
+ " var width = arguments[0].width;"
+ " var height = arguments[0].heigh;"
+ " var filteredData = arguments[0].data.filter(function(element, index, array){"
+ " var x=index/width;"
+ " var y=index%width-1;"
+ " return x >= dirtyX && x < dirtyX+dirtyWidth"
+ " && y >= dirtyY && y < dirtyY+dirtyHeight;"
+ " });"
+ " this._commands.push([%2, filteredData, dx, dy, dirtyWidth, dirtyHeight]);"
+ " }"
+ "};").arg(PutImageData).arg(PutImageData));
+ script.append(QString::fromLatin1("}"));
+ }
+ return script;
+}
+
+QSGContext2D *QSGContext2D::agent()
+{
+ Q_D(QSGContext2D);
+
+ if (d->agent)
+ return d->agent;
+
+ d->agent = new QSGContext2D(this, new QSGContext2DWorkerAgent);
+ connect(this, SIGNAL(painted()), d->agent, SIGNAL(painted()));
+ d->agent->setSize(size());
+ return d->agent;
+
+}
+void QSGContext2D::processCommands(const QScriptValue& commands)
+{
+#ifdef QSGCANVASITEM_DEBUG
+ QElapsedTimer t;
+ t.start();
+#endif
+ int ii = 0;
+ if (commands.isArray()) {
+ QScriptValue cmd = commands.property(ii);
+ while(cmd.isValid()) {
+ processCommand(cmd);
+ ii++;
+ cmd = commands.property(ii);
+ }
+ }
+
+#ifdef QSGCANVASITEM_DEBUG
+ qDebug() << "processed" << ii << "commands in " << t.nsecsElapsed() << "nsecs";
+#endif
+ sync();
+}
+
+void QSGContext2D::sync()
+{
+ Q_D(QSGContext2D);
+
+#ifdef QSGCANVASITEM_DEBUG
+ QElapsedTimer t;
+ t.start();
+#endif
+ if (d->agentData) {
+ if (d->agentData->ref == 1) return;
+
+ Sync *s = new Sync;
+ s->data = d->agentData;
+
+ d->agentData->mutex.lock();
+ QCoreApplication::postEvent(this, s);
+ d->agentData->syncDone.wait(&d->agentData->mutex);
+ d->agentData->mutex.unlock();
+ } else {
+ //qmlInfo(this) << "Context2D sync() can only be called from a WorkerScript;";
+ emit changed();
+ }
+
+#ifdef QSGCANVASITEM_DEBUG
+ qDebug() << "syncing time:" << t.nsecsElapsed();
+#endif
+}
+
+
+bool QSGContext2D::event(QEvent *e)
+{
+ Q_D(QSGContext2D);
+ if (e->type() == QEvent::User && d->agentData) {
+ QMutexLocker locker(&d->agentData->mutex);
+ Sync *s = static_cast<Sync *>(e);
+
+ QSGContext2DPrivate* origin_d = static_cast<QSGContext2DPrivate*>(s->data->orig->d_func());
+
+ //quick copy
+ memcpy_vector<PaintCommand>(&origin_d->commands, d->commands);
+ memcpy_vector<int>(&origin_d->ints, d->ints);
+ memcpy_vector<qreal>(&origin_d->reals, d->reals);
+ memcpy_vector<QColor>(&origin_d->colors, d->colors);
+ memcpy_vector<QMatrix>(&origin_d->matrixes, d->matrixes);
+ memcpy_vector<QSize>(&origin_d->sizes, d->sizes);
+
+ //slow copy
+ copy_vector<QString>(&origin_d->strings, d->strings);
+ copy_vector<QVariant>(&origin_d->variants, d->variants);
+ copy_vector<QPen>(&origin_d->pens, d->pens);
+ copy_vector<QBrush>(&origin_d->brushes, d->brushes);
+ copy_vector<QPainterPath>(&origin_d->pathes, d->pathes);
+ copy_vector<QFont>(&origin_d->fonts, d->fonts);
+ copy_vector<QImage>(&origin_d->images, d->images);
+ origin_d->state = d->state;
+ d->clearCommands();
+
+ if (d->waitingForPainting) {
+ d->imageData.clear();
+ origin_d->imageData.clear();
+ emit s->data->orig->changed();
+ while(origin_d->imageData.isEmpty()) {
+ QCoreApplication::processEvents();
+ }
+ d->imageData = origin_d->imageData;
+ d->waitingForPainting = false;
+ qDebug() << "imageData size:" << d->imageData.size();
+ } else {
+ emit s->data->orig->changed();
+ }
+
+ d->agentData->syncDone.wakeAll();
+ return true;
+ }
+ return QObject::event(e);
+}
+
+void QSGContext2D::processCommand(const QScriptValue& cmd)
+{
+ int action = cmd.property(0).toInt32();
+ switch (action) {
+ case QSGContext2D::Save:
+ save();
+ break;
+ case QSGContext2D::Restore:
+ restore();
+ break;
+ case QSGContext2D::Scale:
+ scale(cmd.property(1).toNumber(), cmd.property(2).toNumber());
+ break;
+ case QSGContext2D::Rotate:
+ rotate(cmd.property(1).toNumber());
+ break;
+ case QSGContext2D::Translate:
+ translate(cmd.property(1).toNumber(), cmd.property(2).toNumber());
+ break;
+ case QSGContext2D::Transform:
+ transform(cmd.property(1).toNumber(),
+ cmd.property(2).toNumber(),
+ cmd.property(3).toNumber(),
+ cmd.property(4).toNumber(),
+ cmd.property(5).toNumber(),
+ cmd.property(6).toNumber());
+ break;
+ case QSGContext2D::SetTransform:
+ setTransform(cmd.property(1).toNumber(),
+ cmd.property(2).toNumber(),
+ cmd.property(3).toNumber(),
+ cmd.property(4).toNumber(),
+ cmd.property(5).toNumber(),
+ cmd.property(6).toNumber());
+ break;
+ case QSGContext2D::ClearRect:
+ clearRect(cmd.property(1).toNumber(),
+ cmd.property(2).toNumber(),
+ cmd.property(3).toNumber(),
+ cmd.property(4).toNumber());
+ break;
+ case QSGContext2D::FillRect:
+ fillRect(cmd.property(1).toNumber(),
+ cmd.property(2).toNumber(),
+ cmd.property(3).toNumber(),
+ cmd.property(4).toNumber());
+ break;
+ case QSGContext2D::StrokeRect:
+ strokeRect(cmd.property(1).toNumber(),
+ cmd.property(2).toNumber(),
+ cmd.property(3).toNumber(),
+ cmd.property(4).toNumber());
+ break;
+ case QSGContext2D::BeginPath:
+ beginPath();
+ break;
+ case QSGContext2D::ClosePath:
+ closePath();
+ break;
+ case QSGContext2D::MoveTo:
+ moveTo(cmd.property(1).toNumber(),
+ cmd.property(2).toNumber());
+ break;
+ case QSGContext2D::LineTo:
+ lineTo(cmd.property(1).toNumber(),
+ cmd.property(2).toNumber());
+ break;
+ case QSGContext2D::QuadraticCurveTo:
+ quadraticCurveTo(cmd.property(1).toNumber(),
+ cmd.property(2).toNumber(),
+ cmd.property(3).toNumber(),
+ cmd.property(4).toNumber());
+ break;
+ case QSGContext2D::BezierCurveTo:
+ bezierCurveTo(cmd.property(1).toNumber(),
+ cmd.property(2).toNumber(),
+ cmd.property(3).toNumber(),
+ cmd.property(4).toNumber(),
+ cmd.property(5).toNumber(),
+ cmd.property(6).toNumber());
+ break;
+ case QSGContext2D::ArcTo:
+ arcTo(cmd.property(1).toNumber(),
+ cmd.property(2).toNumber(),
+ cmd.property(3).toNumber(),
+ cmd.property(4).toNumber(),
+ cmd.property(5).toNumber());
+ break;
+ case QSGContext2D::Rect:
+ rect(cmd.property(1).toNumber(),
+ cmd.property(2).toNumber(),
+ cmd.property(3).toNumber(),
+ cmd.property(4).toNumber());
+ break;
+ case QSGContext2D::Arc:
+ arc(cmd.property(1).toNumber(),
+ cmd.property(2).toNumber(),
+ cmd.property(3).toNumber(),
+ cmd.property(4).toNumber(),
+ cmd.property(5).toNumber(),
+ cmd.property(6).toBool());
+ break;
+ case QSGContext2D::Fill:
+ fill();
+ break;
+ case QSGContext2D::Stroke:
+ stroke();
+ break;
+ case QSGContext2D::Clip:
+ clip();
+ break;
+ case QSGContext2D::GlobalAlpha:
+ setGlobalAlpha(cmd.property(1).toNumber());
+ break;
+ case QSGContext2D::GlobalCompositeOperation:
+ setGlobalCompositeOperation(cmd.property(1).toString());
+ break;
+ case QSGContext2D::StrokeStyle:
+ setStrokeStyle(cmd.property(1).toVariant());
+ break;
+ case QSGContext2D::FillStyle:
+ setFillStyle(cmd.property(1).toVariant());
+ break;
+ case QSGContext2D::FillColor:
+ setFillColor(cmd.property(1).toVariant().value<QColor>());
+ break;
+ case QSGContext2D::StrokeColor:
+ setStrokeColor(cmd.property(1).toVariant().value<QColor>());
+ break;
+ case QSGContext2D::LineWidth:
+ setLineWidth(cmd.property(1).toNumber());
+ break;
+ case QSGContext2D::LineCap:
+ setLineCap(cmd.property(1).toString());
+ break;
+ case QSGContext2D::LineJoin:
+ setLineJoin(cmd.property(1).toString());
+ break;
+ case QSGContext2D::MiterLimit:
+ setMiterLimit(cmd.property(1).toNumber());
+ break;
+ case QSGContext2D::ShadowOffsetX:
+ setShadowOffsetX(cmd.property(1).toNumber());
+ break;
+ case QSGContext2D::ShadowOffsetY:
+ setShadowOffsetY(cmd.property(1).toNumber());
+ break;
+ case QSGContext2D::ShadowBlur:
+ setShadowBlur(cmd.property(1).toNumber());
+ break;
+ case QSGContext2D::ShadowColor:
+ setShadowColor(cmd.property(1).toString());
+ break;
+ case QSGContext2D::Font:
+ setFont(cmd.property(1).toString());
+ break;
+ case QSGContext2D::TextBaseline:
+ setTextBaseline(cmd.property(1).toString());
+ break;
+ case QSGContext2D::TextAlign:
+ setTextAlign(cmd.property(1).toString());
+ break;
+ case QSGContext2D::FillText:
+ fillText(cmd.property(1).toString(), cmd.property(2).toNumber(), cmd.property(3).toNumber());
+ break;
+ case QSGContext2D::StrokeText:
+ strokeText(cmd.property(1).toString(), cmd.property(2).toNumber(), cmd.property(3).toNumber());
+ break;
+ case QSGContext2D::DrawImage1:
+ {
+ drawImage(cmd.property(1).toString(),
+ cmd.property(2).toNumber(),
+ cmd.property(3).toNumber());
+ break;
+ }
+ case QSGContext2D::DrawImage2:
+ drawImage(cmd.property(1).toString(),
+ cmd.property(2).toNumber(),
+ cmd.property(3).toNumber(),
+ cmd.property(4).toNumber(),
+ cmd.property(5).toNumber());
+ break;
+ case QSGContext2D::DrawImage3:
+ drawImage(cmd.property(1).toString(),
+ cmd.property(2).toNumber(),
+ cmd.property(3).toNumber(),
+ cmd.property(4).toNumber(),
+ cmd.property(5).toNumber(),
+ cmd.property(6).toNumber(),
+ cmd.property(7).toNumber(),
+ cmd.property(8).toNumber(),
+ cmd.property(9).toNumber());
+ break;
+ case QSGContext2D::PutImageData:
+ putImageData(cmd.property(1).toVariant(),
+ cmd.property(2).toNumber(),
+ cmd.property(3).toNumber(),
+ cmd.property(4).toNumber(),
+ cmd.property(5).toNumber());
+ break;
+ default:
+ break;
+ }
+}
+
+void QSGContext2D::paint(QPainter* p)
+{
+ Q_D(QSGContext2D);
+
+ QTransform transform = p->worldTransform();
+ if (!d->commands.isEmpty()) {
+ int matrix_idx, real_idx, int_idx, variant_idx, string_idx,color_idx,cmd_idx,
+ pen_idx, brush_idx, font_idx, path_idx, image_idx, size_idx;
+
+ matrix_idx = real_idx = int_idx = variant_idx = string_idx =color_idx = cmd_idx
+ = pen_idx = brush_idx = font_idx = path_idx = image_idx = size_idx = 0;
+
+ foreach(PaintCommand cmd, d->commands) {
+ switch (cmd) {
+ case UpdateMatrix:
+ {
+// qDebug() << "update matrix from " << d->state.matrix << " to " << d->matrixes[matrix_idx];
+ //p->setWorldTransform(transform * QTransform(d->matrixes[matrix_idx++]), false);
+ //p->setMatrix(d->matrixes[matrix_idx++]);
+ d->state.matrix = d->matrixes[matrix_idx++];
+ break;
+ }
+ case ClearRect:
+ {
+ qreal x = d->reals[real_idx++];
+ qreal y = d->reals[real_idx++];
+ qreal w = d->reals[real_idx++];
+ qreal h = d->reals[real_idx++];
+ p->eraseRect(QRectF(x, y, w, h));
+ break;
+ }
+ case FillRect:
+ {
+ qreal x = d->reals[real_idx++];
+ qreal y = d->reals[real_idx++];
+ qreal w = d->reals[real_idx++];
+ qreal h = d->reals[real_idx++];
+ if (d->hasShadow())
+ d->fillRectShadow(p, QRectF(x, y, w, h));
+ else
+ p->fillRect(QRectF(x, y, w, h), p->brush());
+ break;
+ }
+ case ShadowColor:
+ {
+ QColor c = d->colors[color_idx++];
+ d->state.shadowColor = c;
+ break;
+ }
+ case ShadowBlur:
+ {
+ qreal blur = d->reals[real_idx++];
+ d->state.shadowBlur = blur;
+ break;
+ }
+ case ShadowOffsetX:
+ {
+ qreal x = d->reals[real_idx++];
+ d->state.shadowOffsetX = x;
+ break;
+ }
+ case ShadowOffsetY:
+ {
+ qreal y = d->reals[real_idx++];
+ d->state.shadowOffsetY = y;
+ break;
+ }
+ case Fill:
+ {
+ QPainterPath path = d->pathes[path_idx++];
+ if (d->hasShadow())
+ d->fillShadowPath(p,path);
+ else
+ p->fillPath(path, p->brush());
+ break;
+ }
+ case Stroke:
+ {
+ p->setMatrix(d->state.matrix);
+ QPainterPath path = d->state.matrix.inverted().map(d->pathes[path_idx++]);
+ if (d->hasShadow())
+ d->strokeShadowPath(p,path);
+ else
+ p->strokePath(path, p->pen());
+ break;
+ }
+ case Clip:
+ {
+ QPainterPath clipPath = d->pathes[path_idx++];
+ p->setClipPath(clipPath);
+ p->setClipping(true);
+ break;
+ }
+ case UpdateBrush:
+ {
+ p->setBrush(d->brushes[brush_idx++]);
+ break;
+ }
+ case UpdatePen:
+ {
+ p->setPen(d->pens[pen_idx++]);
+ break;
+ }
+ case GlobalAlpha:
+ {
+ p->setOpacity(d->reals[real_idx++]);
+ break;
+ }
+ case GlobalCompositeOperation:
+ {
+ p->setCompositionMode(static_cast<QPainter::CompositionMode>(d->ints[int_idx++]));
+ break;
+ }
+ case Font:
+ {
+ p->setFont(d->fonts[font_idx++]);
+ break;
+ }
+ case StrokeText:
+ {
+ QString text = d->strings[string_idx++];
+ qreal x = d->reals[real_idx++];
+ qreal y = d->reals[real_idx++];
+ int align = d->ints[int_idx++];
+ int baseline = d->ints[int_idx++];
+
+ QPen oldPen = p->pen();
+ p->setPen(QPen(p->brush(),0));
+ //p->setMatrix(state.matrix, false); // always set?
+
+ QPainterPath textPath;
+ QFont oldFont = p->font();
+ QFont font = p->font();
+ font.setStyleStrategy(QFont::ForceOutline);
+ p->setFont(font);
+ const QFontMetrics &metrics = p->fontMetrics();
+ int yoffset = d->baseLineOffset(static_cast<QSGContext2D::TextBaseLineType>(baseline), metrics);
+ int xoffset = d->textAlignOffset(static_cast<QSGContext2D::TextAlignType>(align), metrics, text);
+ textPath.addText(x - xoffset, y - yoffset+metrics.ascent(), font, text);
+ if (d->hasShadow())
+ d->strokeShadowPath(p,textPath);
+
+ p->strokePath(textPath, QPen(p->brush(), p->pen().widthF()));
+
+ //reset old font
+ p->setFont(oldFont);
+ p->setPen(oldPen);
+ break;
+ }
+ case FillText:
+ {
+ QString text = d->strings[string_idx++];
+ qreal x = d->reals[real_idx++];
+ qreal y = d->reals[real_idx++];
+ int align = d->ints[int_idx++];
+ int baseline = d->ints[int_idx++];
+
+ QFont oldFont = p->font();
+ QPen oldPen = p->pen();
+ p->setPen(QPen(p->brush(), p->pen().widthF()));
+ //p->setMatrix(state.matrix, false);
+ //QFont font = p->font();
+ QFont font = d->state.font;
+ font.setBold(true);
+
+ p->setFont(font);
+ int yoffset = d->baseLineOffset(static_cast<QSGContext2D::TextBaseLineType>(baseline), p->fontMetrics());
+ int xoffset = d->textAlignOffset(static_cast<QSGContext2D::TextAlignType>(align), p->fontMetrics(), text);
+ QTextOption opt; // Adjust baseLine etc
+ if (d->hasShadow()) {
+ const QFontMetrics &metrics = p->fontMetrics();
+ QPainterPath textPath;
+ textPath.addText(x - xoffset, y - yoffset+metrics.ascent(), font, text);
+ d->fillShadowPath(p,textPath);
+ }
+ //p->drawText(QRectF(x - xoffset, y - yoffset, QWIDGETSIZE_MAX, p->fontMetrics().height()), text, opt);
+ p->setFont(oldFont);
+ p->setPen(oldPen);
+ break;
+ }
+ case DrawImage1:
+ {
+ QUrl url(d->strings[string_idx++]);
+ qreal x = d->reals[real_idx++];
+ qreal y = d->reals[real_idx++];
+ QDeclarativePixmap px(qmlEngine(d->canvas), url);
+ qDebug() << "draw image:" << url << px.pixmap().size();
+ if (px.isReady()) {
+ QPixmap pixmap = px.pixmap();
+ if (d->hasShadow()) {
+ QImage shadow = d->makeShadowImage(pixmap);
+ qreal dx = x + (d->state.shadowOffsetX < 0? d->state.shadowOffsetX:0);
+ qreal dy = y + (d->state.shadowOffsetY < 0? d->state.shadowOffsetY:0);
+ p->drawImage(QPointF(dx, dy), shadow);
+ }
+ p->drawPixmap(QPointF(x, y), pixmap);
+ }
+ break;
+ }
+ case DrawImage2:
+ {
+ qreal dx = d->reals[real_idx++];
+ qreal dy = d->reals[real_idx++];
+ qreal dw = d->reals[real_idx++];
+ qreal dh = d->reals[real_idx++];
+ QUrl url(d->strings[string_idx++]);
+ QDeclarativePixmap px(qmlEngine(d->canvas), url);
+ if (px.isReady()) {
+ QPixmap pixmap = px.pixmap().scaled(dw, dh);
+ if (d->hasShadow()) {
+ QImage shadow = d->makeShadowImage(pixmap);
+ qreal shadow_dx = dx + (d->state.shadowOffsetX < 0? d->state.shadowOffsetX:0);
+ qreal shadow_dy = dy + (d->state.shadowOffsetY < 0? d->state.shadowOffsetY:0);
+ p->drawImage(QPointF(shadow_dx, shadow_dy), shadow);
+ }
+ p->drawPixmap(QPointF(dx, dy), pixmap);
+ }
+ break;
+ }
+ case DrawImage3:
+ {
+ qreal sx = d->reals[real_idx++];
+ qreal sy = d->reals[real_idx++];
+ qreal sw = d->reals[real_idx++];
+ qreal sh = d->reals[real_idx++];
+ qreal dx = d->reals[real_idx++];
+ qreal dy = d->reals[real_idx++];
+ qreal dw = d->reals[real_idx++];
+ qreal dh = d->reals[real_idx++];
+ QUrl url(d->strings[string_idx++]);
+ QDeclarativePixmap px(qmlEngine(d->canvas), url);
+ if (px.isReady()) {
+ QPixmap pixmap = px.pixmap().copy(sx, sy, sw, sh).scaled(dw, dh);
+ if (d->hasShadow()) {
+ QImage shadow = d->makeShadowImage(pixmap);
+ qreal shadow_dx = dx + (d->state.shadowOffsetX < 0? d->state.shadowOffsetX:0);
+ qreal shadow_dy = dy + (d->state.shadowOffsetY < 0? d->state.shadowOffsetY:0);
+ p->drawImage(QPointF(shadow_dx, shadow_dy), shadow);
+ }
+ p->drawPixmap(QPointF(dx, dy), pixmap);
+ }
+ break;
+ }
+ case GetImageData:
+ {
+ qreal sx = d->reals[real_idx++];
+ qreal sy = d->reals[real_idx++];
+ qreal sw = d->reals[real_idx++];
+ qreal sh = d->reals[real_idx++];
+ QImage img = toImage().copy(sx, sy, sw, sh);
+ const uchar* data = img.constBits();
+ int i = 0;
+
+ while(i< img.byteCount()) {
+ //the stored order in QImage:BGRA
+ d->imageData << *(data+i+2);//R
+ d->imageData << *(data+i+1);//G
+ d->imageData << *(data+i);//B
+ d->imageData << *(data+i+3);//A
+ i+=4;
+ }
+ break;
+ }
+ case PutImageData:
+ {
+ QImage image = d->images[image_idx++];
+ qreal x = d->reals[real_idx++];
+ qreal y = d->reals[real_idx++];
+ p->drawImage(QPointF(x, y), image);
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ d->clearCommands();
+ }
+}
+
+QPaintDevice* QSGContext2D::paintDevice()
+{
+ Q_D(QSGContext2D);
+ return &d->cachedImage;
+}
+const QImage& QSGContext2D::toImage() const
+{
+ Q_D(const QSGContext2D);
+ return d->cachedImage;
+}
+bool QSGContext2D::requireCachedImage() const
+{
+ Q_D(const QSGContext2D);
+ return d->waitingForPainting;
+}
+void QSGContext2D::setCachedImage(const QImage& image)
+{
+ Q_D(QSGContext2D);
+#ifndef QSGCANVASITEM_PAINTING_ON_IMAGE
+ if (d->waitingForPainting) {
+ d->cachedImage = image;
+ d->waitingForPainting = false;
+ }
+#endif
+ if (inWorkerThread()) {
+ d->agent->setCachedImage(image);
+ }
+}
+
+void QSGContext2D::clear()
+{
+ Q_D(QSGContext2D);
+ d->clear();
+}
+
+void QSGContext2D::reset()
+{
+ Q_D(QSGContext2D);
+ d->reset();
+}
+
+void QSGContext2D::drawImage(const QString& imgUrl, qreal dx, qreal dy)
+{
+ Q_D(QSGContext2D);
+ if (!imgUrl.isEmpty())
+ d->drawImage(imgUrl, dx, dy);
+}
+
+void QSGContext2D::drawImage(const QString& imgUrl, qreal sx, qreal sy, qreal sw, qreal sh, qreal dx, qreal dy, qreal dw, qreal dh)
+{
+ Q_D(QSGContext2D);
+ if (!imgUrl.isEmpty())
+ d->drawImage(imgUrl, sx, sy, sw, sh, dx, dy, dw, dh);
+}
+
+void QSGContext2D::drawImage(const QString& imgUrl, qreal dx, qreal dy,
+ qreal dw, qreal dh)
+{
+ Q_D(QSGContext2D);
+ if (!imgUrl.isEmpty())
+ d->drawImage(imgUrl, dx, dy, dw, dh);
+}
+
+void QSGContext2D::setSize(int width, int height)
+{
+ QSize size(width, height);
+ setSize(size);
+}
+
+void QSGContext2D::setSize(const QSize &size)
+{
+ Q_D(QSGContext2D);
+
+ if (d->size == size)
+ return;
+ d->setSize(size);
+ emit changed();
+}
+
+QSize QSGContext2D::size() const
+{
+ Q_D(const QSGContext2D);
+ return d->size;
+}
+
+QMatrix QSGContext2D::worldMatrix() const
+{
+ Q_D(const QSGContext2D);
+ return d->state.matrix;
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/items/qsgcontext2d_p.h b/src/declarative/items/qsgcontext2d_p.h
new file mode 100644
index 0000000000..1a900100de
--- /dev/null
+++ b/src/declarative/items/qsgcontext2d_p.h
@@ -0,0 +1,409 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGCONTEXT2D_P_H
+#define QSGCONTEXT2D_P_H
+
+#include <QtDeclarative/qdeclarative.h>
+#include <QtDeclarative/qdeclarativecomponent.h>
+
+#include "qsgtexturematerial.h"
+
+#include <QtGui/qpainter.h>
+#include <QtGui/qpainterpath.h>
+#include <QtGui/qpixmap.h>
+#include <QtCore/qstring.h>
+#include <QtCore/qstack.h>
+#include <QtCore/qmetatype.h>
+#include <QtCore/qcoreevent.h>
+#include <QtCore/qvariant.h>
+#include <QtScript/qscriptvalue.h>
+#include <QMutex>
+#include <QWaitCondition>
+#include "qsgimage_p.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+QColor colorFromString(const QString &name);
+
+class QSGCanvasGradient : public QObject
+{
+ Q_OBJECT
+public:
+ QSGCanvasGradient(const QGradient &gradient) : m_gradient(gradient) {}
+
+public slots:
+ QGradient value() { return m_gradient; }
+ void addColorStop(float pos, const QString &color) { m_gradient.setColorAt(pos, colorFromString(color));}
+
+public:
+ QGradient m_gradient;
+};
+
+Q_DECLARE_METATYPE(QSGCanvasGradient*)
+
+
+//class QSGCanvasImage: public QObject
+//{
+// Q_OBJECT
+// Q_PROPERTY(QString src READ src WRITE setSrc NOTIFY sourceChanged)
+//public:
+// QSGCanvasImage() {}
+// QSGCanvasImage(const QString &url) : m_image(url), m_src(url) {
+// }
+// QSGCanvasImage(const QImage &img) {m_image = img;}
+
+//public slots:
+// QImage &value() { return m_image; }
+// const QImage &value() const{ return m_image; }
+// QString src() { return m_src; }
+// void setSrc(const QString &src) { m_src = src; m_image.load(src); emit sourceChanged();}
+//signals:
+// void sourceChanged();
+
+//private:
+// QSGImage* img;
+// QString src;
+//};
+
+//Q_DECLARE_METATYPE(QSGCanvasImage*)
+
+
+/*
+
+ */
+
+class QSGContext2DWorkerAgent;
+class QSGContext2DPrivate;
+class QSGContext2D : public QObject
+{
+ Q_OBJECT
+ // compositing
+ Q_PROPERTY(qreal globalAlpha READ globalAlpha WRITE setGlobalAlpha)
+ Q_PROPERTY(QString globalCompositeOperation READ globalCompositeOperation WRITE setGlobalCompositeOperation)
+ Q_PROPERTY(QVariant strokeStyle READ strokeStyle WRITE setStrokeStyle)
+ Q_PROPERTY(QVariant fillStyle READ fillStyle WRITE setFillStyle)
+ Q_PROPERTY(QColor strokeColor READ strokeColor WRITE setStrokeColor)
+ Q_PROPERTY(QColor fillColor READ fillColor WRITE setFillColor)
+ // line caps/joins
+ Q_PROPERTY(qreal lineWidth READ lineWidth WRITE setLineWidth)
+ Q_PROPERTY(QString lineCap READ lineCap WRITE setLineCap)
+ Q_PROPERTY(QString lineJoin READ lineJoin WRITE setLineJoin)
+ Q_PROPERTY(qreal miterLimit READ miterLimit WRITE setMiterLimit)
+ // shadows
+ Q_PROPERTY(qreal shadowOffsetX READ shadowOffsetX WRITE setShadowOffsetX)
+ Q_PROPERTY(qreal shadowOffsetY READ shadowOffsetY WRITE setShadowOffsetY)
+ Q_PROPERTY(qreal shadowBlur READ shadowBlur WRITE setShadowBlur)
+ Q_PROPERTY(QString shadowColor READ shadowColor WRITE setShadowColor)
+ // fonts
+ Q_PROPERTY(QString font READ font WRITE setFont)
+ Q_PROPERTY(QString textBaseline READ textBaseline WRITE setTextBaseline)
+ Q_PROPERTY(QString textAlign READ textAlign WRITE setTextAlign)
+ Q_ENUMS(PaintCommand)
+public:
+ enum TextBaseLineType { Alphabetic=0, Top, Middle, Bottom, Hanging};
+ enum TextAlignType { Start=0, End, Left, Right, Center};
+ enum PaintCommand {
+ Invalid = 0,
+ Save,
+ Restore,
+ //matrix operations
+ UpdateMatrix,
+ Scale,
+ Rotate,
+ Translate,
+ Transform,
+ SetTransform,
+
+ ClearRect,
+ FillRect,
+
+ //path operations
+ UpdatePath,
+ BeginPath,
+ ClosePath,
+ MoveTo,
+ LineTo,
+ QuadraticCurveTo,
+ BezierCurveTo,
+ ArcTo,
+ Rect,
+ Arc,
+ Fill,
+ Stroke,
+ Clip,
+ StrokeRect,
+
+ //brushes and pens
+ UpdateBrush,
+ UpdatePen,
+ GlobalAlpha,
+ GlobalCompositeOperation,
+ StrokeStyle,
+ FillStyle,
+ StrokeColor,
+ FillColor,
+ LineWidth,
+ LineCap,
+ LineJoin,
+ MiterLimit,
+
+ //shadows
+ UpdateShadow,
+ ShadowOffsetX,
+ ShadowOffsetY,
+ ShadowBlur,
+ ShadowColor,
+
+ //font&text
+ Font,
+ TextBaseline,
+ TextAlign,
+ FillText,
+ StrokeText,
+
+ //image
+ DrawImage1,
+ DrawImage2,
+ DrawImage3,
+ GetImageData,
+ PutImageData
+ };
+
+ QSGContext2D(QObject *parent = 0);
+ QSGContext2D(QSGContext2D *ctx2d, QSGContext2DWorkerAgent* agentData);
+ ~QSGContext2D();
+ void setSize(int width, int height);
+ void setSize(const QSize &size);
+ QSize size() const;
+
+ void clear();
+ void reset();
+ QPaintDevice* paintDevice();
+ const QImage& toImage() const;
+ bool requireCachedImage() const;
+ void setCachedImage(const QImage& image);
+ // compositing
+ qreal globalAlpha() const; // (default 1.0)
+ QString globalCompositeOperation() const; // (default over)
+ QVariant strokeStyle() const; // (default black)
+ QVariant fillStyle() const; // (default black)
+ QColor strokeColor() const; // (default black)
+ QColor fillColor() const; // (default black)
+
+ void setGlobalAlpha(qreal alpha);
+ void setGlobalCompositeOperation(const QString &op);
+ void setStrokeStyle(const QVariant &style);
+ void setFillStyle(const QVariant &style);
+ void setStrokeColor(const QColor& color);
+ void setFillColor(const QColor& color);
+
+ // line caps/joins
+ qreal lineWidth() const; // (default 1)
+ QString lineCap() const; // "butt", "round", "square" (default "butt")
+ QString lineJoin() const; // "round", "bevel", "miter" (default "miter")
+ qreal miterLimit() const; // (default 10)
+
+ void setLineWidth(qreal w);
+ void setLineCap(const QString &s);
+ void setLineJoin(const QString &s);
+ void setMiterLimit(qreal m);
+
+ void setFont(const QString &font);
+ QString font() const;
+ void setTextBaseline(const QString &font);
+ QString textBaseline() const;
+ void setTextAlign(const QString &font);
+ QString textAlign() const;
+
+
+ // shadows
+ qreal shadowOffsetX() const; // (default 0)
+ qreal shadowOffsetY() const; // (default 0)
+ qreal shadowBlur() const; // (default 0)
+ QString shadowColor() const; // (default black)
+
+ void setShadowOffsetX(qreal x);
+ void setShadowOffsetY(qreal y);
+ void setShadowBlur(qreal b);
+ void setShadowColor(const QString &str);
+
+public slots:
+ void save(); // push state on state stack
+ void restore(); // pop state stack and restore state
+
+ // QTextMetrics measureText(const QString& text);
+
+ void fillText(const QString &text, qreal x, qreal y);
+ void strokeText(const QString &text, qreal x, qreal y);
+
+ void scale(qreal x, qreal y);
+ void rotate(qreal angle);
+ void translate(qreal x, qreal y);
+ void transform(qreal m11, qreal m12, qreal m21, qreal m22,
+ qreal dx, qreal dy);
+ void setTransform(qreal m11, qreal m12, qreal m21, qreal m22,
+ qreal dx, qreal dy);
+
+ QSGCanvasGradient *createLinearGradient(qreal x0, qreal y0,
+ qreal x1, qreal y1);
+ QSGCanvasGradient *createRadialGradient(qreal x0, qreal y0,
+ qreal r0, qreal x1,
+ qreal y1, qreal r1);
+
+ // rects
+ void clearRect(qreal x, qreal y, qreal w, qreal h);
+ void fillRect(qreal x, qreal y, qreal w, qreal h);
+ void strokeRect(qreal x, qreal y, qreal w, qreal h);
+
+ // path API
+ void beginPath();
+ void closePath();
+ void moveTo(qreal x, qreal y);
+ void lineTo(qreal x, qreal y);
+ void quadraticCurveTo(qreal cpx, qreal cpy, qreal x, qreal y);
+ void bezierCurveTo(qreal cp1x, qreal cp1y,
+ qreal cp2x, qreal cp2y, qreal x, qreal y);
+ void arcTo(qreal x1, qreal y1, qreal x2, qreal y2, qreal radius);
+ void rect(qreal x, qreal y, qreal w, qreal h);
+ void arc(qreal x, qreal y, qreal radius,
+ qreal startAngle, qreal endAngle,
+ bool anticlockwise);
+ void fill();
+ void stroke();
+ void clip();
+ bool isPointInPath(qreal x, qreal y) const;
+
+
+ QSGImage *createImage(const QString &url);
+
+ void drawImage(const QString& imgUrl, qreal dx, qreal dy);
+ void drawImage(const QString& imgUrl, qreal dx, qreal dy, qreal dw, qreal dh);
+ void drawImage(const QString& imgUrl, qreal sx, qreal sy, qreal sw, qreal sh, qreal dx, qreal dy, qreal dw, qreal dh);
+
+ // pixel manipulation
+ QList<int> getImageData(qreal sx, qreal sy, qreal sw, qreal sh);
+ void putImageData(const QVariant& imageData, qreal x, qreal y, qreal w, qreal h);
+
+ void paint(QPainter* painter);
+ void sync();
+ void processCommands(const QScriptValue& commands);
+signals:
+ void changed();
+ void painted();
+public:
+ bool isDirty() const;
+ QScriptValue scriptValue() const;
+ void setScriptEngine(QScriptEngine *eng);
+ QScriptEngine *scriptEngine() const;
+
+ void addref();
+ void release();
+
+ struct VariantRef
+ {
+ VariantRef() : a(0) {}
+ VariantRef(const VariantRef &r) : a(r.a) { if (a) a->addref(); }
+ VariantRef(QSGContext2D *_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;
+ }
+
+ QSGContext2D *a;
+ };
+ struct Sync : public QEvent {
+ Sync() : QEvent(QEvent::User) {}
+ QSGContext2DWorkerAgent *data;
+ };
+ inline bool inWorkerThread() const;
+ QSGContext2D *agent();
+ const QString& agentScript() const;
+
+
+ struct State {
+ QMatrix matrix;
+ QPainterPath clipPath;
+ QBrush strokeStyle;
+ QBrush fillStyle;
+ qreal globalAlpha;
+ qreal lineWidth;
+ Qt::PenCapStyle lineCap;
+ Qt::PenJoinStyle lineJoin;
+ qreal miterLimit;
+ qreal shadowOffsetX;
+ qreal shadowOffsetY;
+ qreal shadowBlur;
+ QColor shadowColor;
+ QPainter::CompositionMode globalCompositeOperation;
+ QFont font;
+ QSGContext2D::TextAlignType textAlign;
+ QSGContext2D::TextBaseLineType textBaseline;
+ QPen pen;
+ };
+
+ QMatrix worldMatrix() const;
+
+protected:
+ virtual bool event(QEvent *);
+
+private:
+ void processCommand(const QScriptValue& command);
+
+ Q_DECLARE_PRIVATE(QSGContext2D)
+};
+
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(QSGContext2D::VariantRef)
+QML_DECLARE_TYPE(QSGContext2D)
+
+QT_END_HEADER
+
+#endif // QSGCONTEXT2D_P_H
diff --git a/src/declarative/items/qsgcontext2d_p_p.h b/src/declarative/items/qsgcontext2d_p_p.h
new file mode 100644
index 0000000000..36f26c99df
--- /dev/null
+++ b/src/declarative/items/qsgcontext2d_p_p.h
@@ -0,0 +1,227 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGCONTEXT2D_P_P_H
+#define QSGCONTEXT2D_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 "qsgcontext2d_p.h"
+#include <private/qobject_p.h>
+
+QT_BEGIN_NAMESPACE
+class QSGCanvasItem;
+struct QSGContext2DWorkerAgent {
+ QSGContext2DWorkerAgent()
+ :ref(1)
+ , orig(0)
+ {}
+
+ QAtomicInt ref;
+ QSGContext2D *orig;
+ QMutex mutex;
+ QWaitCondition syncDone;
+};
+
+class QSGContext2DPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QSGContext2D)
+
+public:
+ QSGContext2DPrivate()
+ : agent(0)
+ , agentData(0)
+ , scriptEngine(0)
+ , cachedImage(1,1, QImage::Format_ARGB32)
+ , canvas(0)
+ , waitingForPainting(false)
+ {
+ }
+ void updateMatrix(const QMatrix& m);
+
+ void setSize(const QSize &s)
+ {
+ size = s;
+ cachedImage = QImage(s, QImage::Format_ARGB32);
+ }
+ void clear();
+ void reset();
+
+ // compositing
+ void setGlobalAlpha(qreal alpha);
+ void setGlobalCompositeOperation(const QString &op);
+ void setStrokeStyle(const QVariant &style);
+ void setFillStyle(const QVariant &style);
+ void setStrokeColor(const QColor& color);
+ void setFillColor(const QColor& color);
+
+ // line caps/joins
+ void setLineWidth(qreal w);
+ void setLineCap(const QString &s);
+ void setLineJoin(const QString &s);
+ void setMiterLimit(qreal m);
+
+ void setFont(const QString &font);
+ void setTextBaseline(const QString &font);
+ void setTextAlign(const QString &font);
+
+
+ // shadows
+ void setShadowOffsetX(qreal x);
+ void setShadowOffsetY(qreal y);
+ void setShadowBlur(qreal b);
+ void setShadowColor(const QString &str);
+
+ bool hasShadow() const;
+ void clearShadow();
+ QImage makeShadowImage(const QPixmap& pix);
+ void fillRectShadow(QPainter* p, QRectF shadowRect);
+ void fillShadowPath(QPainter* p, const QPainterPath& path);
+ void strokeShadowPath(QPainter* p, const QPainterPath& path);
+ void save();
+ void restore();
+
+ // QTextMetrics measureText(const QString& text);
+
+ void fillText(const QString &text, qreal x, qreal y);
+ void strokeText(const QString &text, qreal x, qreal y);
+
+ void scale(qreal x, qreal y);
+ void rotate(qreal angle);
+ void translate(qreal x, qreal y);
+ void transform(qreal m11, qreal m12, qreal m21, qreal m22,
+ qreal dx, qreal dy);
+ void setTransform(qreal m11, qreal m12, qreal m21, qreal m22,
+ qreal dx, qreal dy);
+
+ // rects
+ void clearRect(qreal x, qreal y, qreal w, qreal h);
+ void fillRect(qreal x, qreal y, qreal w, qreal h);
+ void strokeRect(qreal x, qreal y, qreal w, qreal h);
+
+ // path API
+ void beginPath();
+ void closePath();
+ void moveTo(qreal x, qreal y);
+ void lineTo(qreal x, qreal y);
+ void quadraticCurveTo(qreal cpx, qreal cpy, qreal x, qreal y);
+ void bezierCurveTo(qreal cp1x, qreal cp1y,
+ qreal cp2x, qreal cp2y, qreal x, qreal y);
+ void arcTo(qreal x1, qreal y1, qreal x2, qreal y2, qreal radius);
+ void rect(qreal x, qreal y, qreal w, qreal h);
+ void arc(qreal x, qreal y, qreal radius,
+ qreal startAngle, qreal endAngle,
+ bool anticlockwise);
+ void fill();
+ void stroke();
+ void clip();
+
+ void drawImage(const QString& url, qreal dx, qreal dy);
+ void drawImage(const QString& url, qreal dx, qreal dy, qreal dw, qreal dh);
+ void drawImage(const QString& url, qreal sx, qreal sy, qreal sw, qreal sh, qreal dx, qreal dy, qreal dw, qreal dh);
+
+ QList<int> getImageData(qreal sx, qreal sy, qreal sw, qreal sh);
+ void putImageData(const QVariantList& imageData, qreal x, qreal y, qreal w, qreal h);
+
+ int baseLineOffset(QSGContext2D::TextBaseLineType value, const QFontMetrics &metrics);
+ int textAlignOffset(QSGContext2D::TextAlignType value, const QFontMetrics &metrics, const QString &string);
+
+ void clearCommands()
+ {
+ commands.remove(0, commands.size());
+ variants.remove(0, variants.size());
+ pens.remove(0, pens.size());
+ ints.remove(0, ints.size());
+ reals.remove(0, reals.size());
+ strings.remove(0, strings.size());
+ colors.remove(0, colors.size());
+ matrixes.remove(0, matrixes.size());
+ brushes.remove(0, brushes.size());
+ pathes.remove(0, pathes.size());
+ fonts.remove(0, fonts.size());
+ images.remove(0, images.size());
+ sizes.remove(0, sizes.size());
+ }
+
+ //current context2d variables
+ QPainterPath path;
+ QSize size;
+ QSGContext2D::State state;
+ QStack<QSGContext2D::State> stateStack;
+
+ //variables for actual painting
+ QVector<QSGContext2D::PaintCommand> commands;
+ QVector<QVariant> variants;
+ QVector<int> ints;
+ QVector<qreal> reals;
+ QVector<QString> strings;
+ QVector<QColor> colors;
+ QVector<QMatrix> matrixes;
+ QVector<QPen> pens;
+ QVector<QBrush> brushes;
+ QVector<QPainterPath> pathes;
+ QVector<QFont> fonts;
+ QVector<QImage> images;
+ QVector<QSize> sizes;
+ QList<int> imageData;
+
+ //workerscript agent
+ QSGContext2D* agent;
+ QSGContext2DWorkerAgent* agentData;
+ QScriptEngine* scriptEngine;
+ QScriptValue scriptValue;
+ QImage cachedImage;
+ QSGCanvasItem* canvas;
+ bool waitingForPainting;
+};
+
+QT_END_NAMESPACE
+
+#endif // QSGCONTEXT2D_P_P_H
diff --git a/src/declarative/items/qsgevents.cpp b/src/declarative/items/qsgevents.cpp
new file mode 100644
index 0000000000..44ef38b037
--- /dev/null
+++ b/src/declarative/items/qsgevents.cpp
@@ -0,0 +1,47 @@
+// Commit: ac5c099cc3c5b8c7eec7a49fdeb8a21037230350
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgevents_p_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QT_END_NAMESPACE
diff --git a/src/declarative/items/qsgevents_p_p.h b/src/declarative/items/qsgevents_p_p.h
new file mode 100644
index 0000000000..f0d434db32
--- /dev/null
+++ b/src/declarative/items/qsgevents_p_p.h
@@ -0,0 +1,142 @@
+// Commit: ac5c099cc3c5b8c7eec7a49fdeb8a21037230350
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGEVENTS_P_P_H
+#define QSGEVENTS_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 <qdeclarative.h>
+
+#include <QtCore/qobject.h>
+#include <QtGui/qevent.h>
+
+QT_BEGIN_NAMESPACE
+
+class QSGKeyEvent : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(int key READ key)
+ Q_PROPERTY(QString text READ text)
+ Q_PROPERTY(int modifiers READ modifiers)
+ Q_PROPERTY(bool isAutoRepeat READ isAutoRepeat)
+ Q_PROPERTY(int count READ count)
+ Q_PROPERTY(bool accepted READ isAccepted WRITE setAccepted)
+
+public:
+ QSGKeyEvent(QEvent::Type type, int key, Qt::KeyboardModifiers modifiers, const QString &text=QString(), bool autorep=false, ushort count=1)
+ : event(type, key, modifiers, text, autorep, count) { event.setAccepted(false); }
+ QSGKeyEvent(const QKeyEvent &ke)
+ : event(ke) { event.setAccepted(false); }
+
+ int key() const { return event.key(); }
+ QString text() const { return event.text(); }
+ int modifiers() const { return event.modifiers(); }
+ bool isAutoRepeat() const { return event.isAutoRepeat(); }
+ int count() const { return event.count(); }
+
+ bool isAccepted() { return event.isAccepted(); }
+ void setAccepted(bool accepted) { event.setAccepted(accepted); }
+
+private:
+ QKeyEvent event;
+};
+
+class QSGMouseEvent : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(int x READ x)
+ Q_PROPERTY(int y READ y)
+ Q_PROPERTY(int button READ button)
+ Q_PROPERTY(int buttons READ buttons)
+ Q_PROPERTY(int modifiers READ modifiers)
+ Q_PROPERTY(bool wasHeld READ wasHeld)
+ Q_PROPERTY(bool isClick READ isClick)
+ Q_PROPERTY(bool accepted READ isAccepted WRITE setAccepted)
+
+public:
+ QSGMouseEvent(int x, int y, Qt::MouseButton button, Qt::MouseButtons buttons, Qt::KeyboardModifiers modifiers
+ , bool isClick=false, bool wasHeld=false)
+ : _x(x), _y(y), _button(button), _buttons(buttons), _modifiers(modifiers)
+ , _wasHeld(wasHeld), _isClick(isClick), _accepted(true) {}
+
+ int x() const { return _x; }
+ int y() const { return _y; }
+ int button() const { return _button; }
+ int buttons() const { return _buttons; }
+ int modifiers() const { return _modifiers; }
+ bool wasHeld() const { return _wasHeld; }
+ bool isClick() const { return _isClick; }
+
+ // only for internal usage
+ void setX(int x) { _x = x; }
+ void setY(int y) { _y = y; }
+
+ bool isAccepted() { return _accepted; }
+ void setAccepted(bool accepted) { _accepted = accepted; }
+
+private:
+ int _x;
+ int _y;
+ Qt::MouseButton _button;
+ Qt::MouseButtons _buttons;
+ Qt::KeyboardModifiers _modifiers;
+ bool _wasHeld;
+ bool _isClick;
+ bool _accepted;
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QSGKeyEvent)
+QML_DECLARE_TYPE(QSGMouseEvent)
+
+#endif // QSGEVENTS_P_P_H
diff --git a/src/declarative/items/qsgflickable.cpp b/src/declarative/items/qsgflickable.cpp
new file mode 100644
index 0000000000..be0ac13bbf
--- /dev/null
+++ b/src/declarative/items/qsgflickable.cpp
@@ -0,0 +1,1495 @@
+// Commit: d4fa1878ff1e7628d3e984d54f8a93810353c71b
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgflickable_p.h"
+#include "qsgflickable_p_p.h"
+#include "qsgcanvas.h"
+#include "qsgcanvas_p.h"
+
+#include <QtDeclarative/qdeclarativeinfo.h>
+#include <QtGui/qgraphicssceneevent.h>
+#include <QtGui/qapplication.h>
+#include "qplatformdefs.h"
+
+QT_BEGIN_NAMESPACE
+
+// The maximum number of pixels a flick can overshoot
+#ifndef QML_FLICK_OVERSHOOT
+#define QML_FLICK_OVERSHOOT 200
+#endif
+
+// The number of samples to use in calculating the velocity of a flick
+#ifndef QML_FLICK_SAMPLEBUFFER
+#define QML_FLICK_SAMPLEBUFFER 3
+#endif
+
+// The number of samples to discard when calculating the flick velocity.
+// Touch panels often produce inaccurate results as the finger is lifted.
+#ifndef QML_FLICK_DISCARDSAMPLES
+#define QML_FLICK_DISCARDSAMPLES 1
+#endif
+
+// The default maximum velocity of a flick.
+#ifndef QML_FLICK_DEFAULTMAXVELOCITY
+#define QML_FLICK_DEFAULTMAXVELOCITY 2500
+#endif
+
+// The default deceleration of a flick.
+#ifndef QML_FLICK_DEFAULTDECELERATION
+#define QML_FLICK_DEFAULTDECELERATION 1500
+#endif
+
+// How much faster to decelerate when overshooting
+#ifndef QML_FLICK_OVERSHOOTFRICTION
+#define QML_FLICK_OVERSHOOTFRICTION 8
+#endif
+
+// FlickThreshold determines how far the "mouse" must have moved
+// before we perform a flick.
+static const int FlickThreshold = 20;
+
+// RetainGrabVelocity is the maxmimum instantaneous velocity that
+// will ensure the Flickable retains the grab on consecutive flicks.
+static const int RetainGrabVelocity = 15;
+
+QSGFlickableVisibleArea::QSGFlickableVisibleArea(QSGFlickable *parent)
+ : QObject(parent), flickable(parent), m_xPosition(0.), m_widthRatio(0.)
+ , m_yPosition(0.), m_heightRatio(0.)
+{
+}
+
+qreal QSGFlickableVisibleArea::widthRatio() const
+{
+ return m_widthRatio;
+}
+
+qreal QSGFlickableVisibleArea::xPosition() const
+{
+ return m_xPosition;
+}
+
+qreal QSGFlickableVisibleArea::heightRatio() const
+{
+ return m_heightRatio;
+}
+
+qreal QSGFlickableVisibleArea::yPosition() const
+{
+ return m_yPosition;
+}
+
+void QSGFlickableVisibleArea::updateVisible()
+{
+ QSGFlickablePrivate *p = QSGFlickablePrivate::get(flickable);
+
+ bool changeX = false;
+ bool changeY = false;
+ bool changeWidth = false;
+ bool changeHeight = false;
+
+ // Vertical
+ const qreal viewheight = flickable->height();
+ const qreal maxyextent = -flickable->maxYExtent() + flickable->minYExtent();
+ qreal pagePos = (-p->vData.move.value() + flickable->minYExtent()) / (maxyextent + viewheight);
+ qreal pageSize = viewheight / (maxyextent + viewheight);
+
+ if (pageSize != m_heightRatio) {
+ m_heightRatio = pageSize;
+ changeHeight = true;
+ }
+ if (pagePos != m_yPosition) {
+ m_yPosition = pagePos;
+ changeY = true;
+ }
+
+ // Horizontal
+ const qreal viewwidth = flickable->width();
+ const qreal maxxextent = -flickable->maxXExtent() + flickable->minXExtent();
+ pagePos = (-p->hData.move.value() + flickable->minXExtent()) / (maxxextent + viewwidth);
+ pageSize = viewwidth / (maxxextent + viewwidth);
+
+ if (pageSize != m_widthRatio) {
+ m_widthRatio = pageSize;
+ changeWidth = true;
+ }
+ if (pagePos != m_xPosition) {
+ m_xPosition = pagePos;
+ changeX = true;
+ }
+
+ if (changeX)
+ emit xPositionChanged(m_xPosition);
+ if (changeY)
+ emit yPositionChanged(m_yPosition);
+ if (changeWidth)
+ emit widthRatioChanged(m_widthRatio);
+ if (changeHeight)
+ emit heightRatioChanged(m_heightRatio);
+}
+
+
+QSGFlickablePrivate::QSGFlickablePrivate()
+ : contentItem(new QSGItem)
+ , hData(this, &QSGFlickablePrivate::setViewportX)
+ , vData(this, &QSGFlickablePrivate::setViewportY)
+ , flickingHorizontally(false), flickingVertically(false)
+ , hMoved(false), vMoved(false)
+ , movingHorizontally(false), movingVertically(false)
+ , stealMouse(false), pressed(false), interactive(true), calcVelocity(false)
+ , deceleration(QML_FLICK_DEFAULTDECELERATION)
+ , maxVelocity(QML_FLICK_DEFAULTMAXVELOCITY), reportedVelocitySmoothing(100)
+ , delayedPressEvent(0), delayedPressTarget(0), pressDelay(0), fixupDuration(400)
+ , fixupMode(Normal), vTime(0), visibleArea(0)
+ , flickableDirection(QSGFlickable::AutoFlickDirection)
+ , boundsBehavior(QSGFlickable::DragAndOvershootBounds)
+{
+}
+
+void QSGFlickablePrivate::init()
+{
+ Q_Q(QSGFlickable);
+ QDeclarative_setParent_noEvent(contentItem, q);
+ contentItem->setParentItem(q);
+ static int timelineUpdatedIdx = -1;
+ static int timelineCompletedIdx = -1;
+ static int flickableTickedIdx = -1;
+ static int flickableMovementEndingIdx = -1;
+ if (timelineUpdatedIdx == -1) {
+ timelineUpdatedIdx = QDeclarativeTimeLine::staticMetaObject.indexOfSignal("updated()");
+ timelineCompletedIdx = QDeclarativeTimeLine::staticMetaObject.indexOfSignal("completed()");
+ flickableTickedIdx = QSGFlickable::staticMetaObject.indexOfSlot("ticked()");
+ flickableMovementEndingIdx = QSGFlickable::staticMetaObject.indexOfSlot("movementEnding()");
+ }
+ QMetaObject::connect(&timeline, timelineUpdatedIdx,
+ q, flickableTickedIdx, Qt::DirectConnection);
+ QMetaObject::connect(&timeline, timelineCompletedIdx,
+ q, flickableMovementEndingIdx, Qt::DirectConnection);
+ q->setAcceptedMouseButtons(Qt::LeftButton);
+ q->setFiltersChildMouseEvents(true);
+ QSGItemPrivate *viewportPrivate = QSGItemPrivate::get(contentItem);
+ viewportPrivate->addItemChangeListener(this, QSGItemPrivate::Geometry);
+ lastPosTime.invalidate();
+}
+
+/*
+ Returns the amount to overshoot by given a velocity.
+ Will be roughly in range 0 - size/4
+*/
+qreal QSGFlickablePrivate::overShootDistance(qreal size)
+{
+ if (maxVelocity <= 0)
+ return 0.0;
+
+ return qMin(qreal(QML_FLICK_OVERSHOOT), size/3);
+}
+
+void QSGFlickablePrivate::AxisData::addVelocitySample(qreal v, qreal maxVelocity)
+{
+ if (v > maxVelocity)
+ v = maxVelocity;
+ else if (v < -maxVelocity)
+ v = -maxVelocity;
+ velocityBuffer.append(v);
+ if (velocityBuffer.count() > QML_FLICK_SAMPLEBUFFER)
+ velocityBuffer.remove(0);
+}
+
+void QSGFlickablePrivate::AxisData::updateVelocity()
+{
+ if (velocityBuffer.count() > QML_FLICK_DISCARDSAMPLES) {
+ velocity = 0;
+ int count = velocityBuffer.count()-QML_FLICK_DISCARDSAMPLES;
+ for (int i = 0; i < count; ++i) {
+ qreal v = velocityBuffer.at(i);
+ velocity += v;
+ }
+ velocity /= count;
+ }
+}
+
+void QSGFlickablePrivate::itemGeometryChanged(QSGItem *item, const QRectF &newGeom, const QRectF &oldGeom)
+{
+ Q_Q(QSGFlickable);
+ if (item == contentItem) {
+ if (newGeom.x() != oldGeom.x())
+ emit q->contentXChanged();
+ if (newGeom.y() != oldGeom.y())
+ emit q->contentYChanged();
+ }
+}
+
+void QSGFlickablePrivate::flickX(qreal velocity)
+{
+ Q_Q(QSGFlickable);
+ flick(hData, q->minXExtent(), q->maxXExtent(), q->width(), fixupX_callback, velocity);
+}
+
+void QSGFlickablePrivate::flickY(qreal velocity)
+{
+ Q_Q(QSGFlickable);
+ flick(vData, q->minYExtent(), q->maxYExtent(), q->height(), fixupY_callback, velocity);
+}
+
+void QSGFlickablePrivate::flick(AxisData &data, qreal minExtent, qreal maxExtent, qreal,
+ QDeclarativeTimeLineCallback::Callback fixupCallback, qreal velocity)
+{
+ Q_Q(QSGFlickable);
+ qreal maxDistance = -1;
+ data.fixingUp = false;
+ // -ve velocity means list is moving up
+ if (velocity > 0) {
+ maxDistance = qAbs(minExtent - data.move.value());
+ data.flickTarget = minExtent;
+ } else {
+ maxDistance = qAbs(maxExtent - data.move.value());
+ data.flickTarget = maxExtent;
+ }
+ if (maxDistance > 0) {
+ qreal v = velocity;
+ if (maxVelocity != -1 && maxVelocity < qAbs(v)) {
+ if (v < 0)
+ v = -maxVelocity;
+ else
+ v = maxVelocity;
+ }
+ timeline.reset(data.move);
+ if (boundsBehavior == QSGFlickable::DragAndOvershootBounds)
+ timeline.accel(data.move, v, deceleration);
+ else
+ timeline.accel(data.move, v, deceleration, maxDistance);
+ timeline.callback(QDeclarativeTimeLineCallback(&data.move, fixupCallback, this));
+ if (!flickingHorizontally && q->xflick()) {
+ flickingHorizontally = true;
+ emit q->flickingChanged();
+ emit q->flickingHorizontallyChanged();
+ if (!flickingVertically)
+ emit q->flickStarted();
+ }
+ if (!flickingVertically && q->yflick()) {
+ flickingVertically = true;
+ emit q->flickingChanged();
+ emit q->flickingVerticallyChanged();
+ if (!flickingHorizontally)
+ emit q->flickStarted();
+ }
+ } else {
+ timeline.reset(data.move);
+ fixup(data, minExtent, maxExtent);
+ }
+}
+
+void QSGFlickablePrivate::fixupY_callback(void *data)
+{
+ ((QSGFlickablePrivate *)data)->fixupY();
+}
+
+void QSGFlickablePrivate::fixupX_callback(void *data)
+{
+ ((QSGFlickablePrivate *)data)->fixupX();
+}
+
+void QSGFlickablePrivate::fixupX()
+{
+ Q_Q(QSGFlickable);
+ fixup(hData, q->minXExtent(), q->maxXExtent());
+}
+
+void QSGFlickablePrivate::fixupY()
+{
+ Q_Q(QSGFlickable);
+ fixup(vData, q->minYExtent(), q->maxYExtent());
+}
+
+void QSGFlickablePrivate::fixup(AxisData &data, qreal minExtent, qreal maxExtent)
+{
+ if (data.move.value() > minExtent || maxExtent > minExtent) {
+ timeline.reset(data.move);
+ if (data.move.value() != minExtent) {
+ switch (fixupMode) {
+ case Immediate:
+ timeline.set(data.move, minExtent);
+ break;
+ case ExtentChanged:
+ // The target has changed. Don't start from the beginning; just complete the
+ // second half of the animation using the new extent.
+ timeline.move(data.move, minExtent, QEasingCurve(QEasingCurve::OutExpo), 3*fixupDuration/4);
+ data.fixingUp = true;
+ break;
+ default: {
+ qreal dist = minExtent - data.move;
+ timeline.move(data.move, minExtent - dist/2, QEasingCurve(QEasingCurve::InQuad), fixupDuration/4);
+ timeline.move(data.move, minExtent, QEasingCurve(QEasingCurve::OutExpo), 3*fixupDuration/4);
+ data.fixingUp = true;
+ }
+ }
+ }
+ } else if (data.move.value() < maxExtent) {
+ timeline.reset(data.move);
+ switch (fixupMode) {
+ case Immediate:
+ timeline.set(data.move, maxExtent);
+ break;
+ case ExtentChanged:
+ // The target has changed. Don't start from the beginning; just complete the
+ // second half of the animation using the new extent.
+ timeline.move(data.move, maxExtent, QEasingCurve(QEasingCurve::OutExpo), 3*fixupDuration/4);
+ data.fixingUp = true;
+ break;
+ default: {
+ qreal dist = maxExtent - data.move;
+ timeline.move(data.move, maxExtent - dist/2, QEasingCurve(QEasingCurve::InQuad), fixupDuration/4);
+ timeline.move(data.move, maxExtent, QEasingCurve(QEasingCurve::OutExpo), 3*fixupDuration/4);
+ data.fixingUp = true;
+ }
+ }
+ }
+ data.inOvershoot = false;
+ fixupMode = Normal;
+ vTime = timeline.time();
+}
+
+void QSGFlickablePrivate::updateBeginningEnd()
+{
+ Q_Q(QSGFlickable);
+ bool atBoundaryChange = false;
+
+ // Vertical
+ const int maxyextent = int(-q->maxYExtent());
+ const qreal ypos = -vData.move.value();
+ bool atBeginning = (ypos <= -q->minYExtent());
+ bool atEnd = (maxyextent <= ypos);
+
+ if (atBeginning != vData.atBeginning) {
+ vData.atBeginning = atBeginning;
+ atBoundaryChange = true;
+ }
+ if (atEnd != vData.atEnd) {
+ vData.atEnd = atEnd;
+ atBoundaryChange = true;
+ }
+
+ // Horizontal
+ const int maxxextent = int(-q->maxXExtent());
+ const qreal xpos = -hData.move.value();
+ atBeginning = (xpos <= -q->minXExtent());
+ atEnd = (maxxextent <= xpos);
+
+ if (atBeginning != hData.atBeginning) {
+ hData.atBeginning = atBeginning;
+ atBoundaryChange = true;
+ }
+ if (atEnd != hData.atEnd) {
+ hData.atEnd = atEnd;
+ atBoundaryChange = true;
+ }
+
+ if (atBoundaryChange)
+ emit q->isAtBoundaryChanged();
+
+ if (visibleArea)
+ visibleArea->updateVisible();
+}
+
+QSGFlickable::QSGFlickable(QSGItem *parent)
+ : QSGItem(*(new QSGFlickablePrivate), parent)
+{
+ Q_D(QSGFlickable);
+ d->init();
+}
+
+QSGFlickable::QSGFlickable(QSGFlickablePrivate &dd, QSGItem *parent)
+ : QSGItem(dd, parent)
+{
+ Q_D(QSGFlickable);
+ d->init();
+}
+
+QSGFlickable::~QSGFlickable()
+{
+}
+
+qreal QSGFlickable::contentX() const
+{
+ Q_D(const QSGFlickable);
+ return -d->contentItem->x();
+}
+
+void QSGFlickable::setContentX(qreal pos)
+{
+ Q_D(QSGFlickable);
+ d->timeline.reset(d->hData.move);
+ d->vTime = d->timeline.time();
+ movementXEnding();
+ if (-pos != d->hData.move.value()) {
+ d->hData.move.setValue(-pos);
+ viewportMoved();
+ }
+}
+
+qreal QSGFlickable::contentY() const
+{
+ Q_D(const QSGFlickable);
+ return -d->contentItem->y();
+}
+
+void QSGFlickable::setContentY(qreal pos)
+{
+ Q_D(QSGFlickable);
+ d->timeline.reset(d->vData.move);
+ d->vTime = d->timeline.time();
+ movementYEnding();
+ if (-pos != d->vData.move.value()) {
+ d->vData.move.setValue(-pos);
+ viewportMoved();
+ }
+}
+
+bool QSGFlickable::isInteractive() const
+{
+ Q_D(const QSGFlickable);
+ return d->interactive;
+}
+
+void QSGFlickable::setInteractive(bool interactive)
+{
+ Q_D(QSGFlickable);
+ if (interactive != d->interactive) {
+ d->interactive = interactive;
+ if (!interactive && (d->flickingHorizontally || d->flickingVertically)) {
+ d->timeline.clear();
+ d->vTime = d->timeline.time();
+ d->flickingHorizontally = false;
+ d->flickingVertically = false;
+ emit flickingChanged();
+ emit flickingHorizontallyChanged();
+ emit flickingVerticallyChanged();
+ emit flickEnded();
+ }
+ emit interactiveChanged();
+ }
+}
+
+qreal QSGFlickable::horizontalVelocity() const
+{
+ Q_D(const QSGFlickable);
+ return d->hData.smoothVelocity.value();
+}
+
+qreal QSGFlickable::verticalVelocity() const
+{
+ Q_D(const QSGFlickable);
+ return d->vData.smoothVelocity.value();
+}
+
+bool QSGFlickable::isAtXEnd() const
+{
+ Q_D(const QSGFlickable);
+ return d->hData.atEnd;
+}
+
+bool QSGFlickable::isAtXBeginning() const
+{
+ Q_D(const QSGFlickable);
+ return d->hData.atBeginning;
+}
+
+bool QSGFlickable::isAtYEnd() const
+{
+ Q_D(const QSGFlickable);
+ return d->vData.atEnd;
+}
+
+bool QSGFlickable::isAtYBeginning() const
+{
+ Q_D(const QSGFlickable);
+ return d->vData.atBeginning;
+}
+
+void QSGFlickable::ticked()
+{
+ viewportMoved();
+}
+
+QSGItem *QSGFlickable::contentItem()
+{
+ Q_D(QSGFlickable);
+ return d->contentItem;
+}
+
+QSGFlickableVisibleArea *QSGFlickable::visibleArea()
+{
+ Q_D(QSGFlickable);
+ if (!d->visibleArea)
+ d->visibleArea = new QSGFlickableVisibleArea(this);
+ return d->visibleArea;
+}
+
+QSGFlickable::FlickableDirection QSGFlickable::flickableDirection() const
+{
+ Q_D(const QSGFlickable);
+ return d->flickableDirection;
+}
+
+void QSGFlickable::setFlickableDirection(FlickableDirection direction)
+{
+ Q_D(QSGFlickable);
+ if (direction != d->flickableDirection) {
+ d->flickableDirection = direction;
+ emit flickableDirectionChanged();
+ }
+}
+
+void QSGFlickablePrivate::handleMousePressEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_Q(QSGFlickable);
+ if (interactive && timeline.isActive()
+ && (qAbs(hData.smoothVelocity.value()) > RetainGrabVelocity
+ || qAbs(vData.smoothVelocity.value()) > RetainGrabVelocity)) {
+ stealMouse = true; // If we've been flicked then steal the click.
+ } else {
+ stealMouse = false;
+ }
+ q->setKeepMouseGrab(stealMouse);
+ pressed = true;
+ timeline.clear();
+ hData.reset();
+ vData.reset();
+ hData.dragMinBound = q->minXExtent();
+ vData.dragMinBound = q->minYExtent();
+ hData.dragMaxBound = q->maxXExtent();
+ vData.dragMaxBound = q->maxYExtent();
+ fixupMode = Normal;
+ lastPos = QPoint();
+ QSGItemPrivate::start(lastPosTime);
+ pressPos = event->pos();
+ hData.pressPos = hData.move.value();
+ vData.pressPos = vData.move.value();
+ flickingHorizontally = false;
+ flickingVertically = false;
+ QSGItemPrivate::start(pressTime);
+ QSGItemPrivate::start(velocityTime);
+}
+
+void QSGFlickablePrivate::handleMouseMoveEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_Q(QSGFlickable);
+ if (!interactive || !lastPosTime.isValid())
+ return;
+ bool rejectY = false;
+ bool rejectX = false;
+
+ bool stealY = stealMouse;
+ bool stealX = stealMouse;
+
+ if (q->yflick()) {
+ int dy = int(event->pos().y() - pressPos.y());
+ if (qAbs(dy) > QApplication::startDragDistance() || QSGItemPrivate::elapsed(pressTime) > 200) {
+ if (!vMoved)
+ vData.dragStartOffset = dy;
+ qreal newY = dy + vData.pressPos - vData.dragStartOffset;
+ const qreal minY = vData.dragMinBound;
+ const qreal maxY = vData.dragMaxBound;
+ if (newY > minY)
+ newY = minY + (newY - minY) / 2;
+ if (newY < maxY && maxY - minY <= 0)
+ newY = maxY + (newY - maxY) / 2;
+ if (boundsBehavior == QSGFlickable::StopAtBounds && (newY > minY || newY < maxY)) {
+ rejectY = true;
+ if (newY < maxY) {
+ newY = maxY;
+ rejectY = false;
+ }
+ if (newY > minY) {
+ newY = minY;
+ rejectY = false;
+ }
+ }
+ if (!rejectY && stealMouse) {
+ vData.move.setValue(qRound(newY));
+ vMoved = true;
+ }
+ if (qAbs(dy) > QApplication::startDragDistance())
+ stealY = true;
+ }
+ }
+
+ if (q->xflick()) {
+ int dx = int(event->pos().x() - pressPos.x());
+ if (qAbs(dx) > QApplication::startDragDistance() || QSGItemPrivate::elapsed(pressTime) > 200) {
+ if (!hMoved)
+ hData.dragStartOffset = dx;
+ qreal newX = dx + hData.pressPos - hData.dragStartOffset;
+ const qreal minX = hData.dragMinBound;
+ const qreal maxX = hData.dragMaxBound;
+ if (newX > minX)
+ newX = minX + (newX - minX) / 2;
+ if (newX < maxX && maxX - minX <= 0)
+ newX = maxX + (newX - maxX) / 2;
+ if (boundsBehavior == QSGFlickable::StopAtBounds && (newX > minX || newX < maxX)) {
+ rejectX = true;
+ if (newX < maxX) {
+ newX = maxX;
+ rejectX = false;
+ }
+ if (newX > minX) {
+ newX = minX;
+ rejectX = false;
+ }
+ }
+ if (!rejectX && stealMouse) {
+ hData.move.setValue(qRound(newX));
+ hMoved = true;
+ }
+
+ if (qAbs(dx) > QApplication::startDragDistance())
+ stealX = true;
+ }
+ }
+
+ stealMouse = stealX || stealY;
+ if (stealMouse)
+ q->setKeepMouseGrab(true);
+
+ if (rejectY) {
+ vData.velocityBuffer.clear();
+ vData.velocity = 0;
+ }
+ if (rejectX) {
+ hData.velocityBuffer.clear();
+ hData.velocity = 0;
+ }
+
+ if (hMoved || vMoved) {
+ q->movementStarting();
+ q->viewportMoved();
+ }
+
+ if (!lastPos.isNull()) {
+ qreal elapsed = qreal(QSGItemPrivate::elapsed(lastPosTime)) / 1000.;
+ if (elapsed <= 0)
+ return;
+ QSGItemPrivate::restart(lastPosTime);
+ qreal dy = event->pos().y()-lastPos.y();
+ if (q->yflick() && !rejectY)
+ vData.addVelocitySample(dy/elapsed, maxVelocity);
+ qreal dx = event->pos().x()-lastPos.x();
+ if (q->xflick() && !rejectX)
+ hData.addVelocitySample(dx/elapsed, maxVelocity);
+ }
+
+ lastPos = event->pos();
+}
+
+void QSGFlickablePrivate::handleMouseReleaseEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_Q(QSGFlickable);
+ stealMouse = false;
+ q->setKeepMouseGrab(false);
+ pressed = false;
+ if (!lastPosTime.isValid())
+ return;
+
+ // if we drag then pause before release we should not cause a flick.
+ if (QSGItemPrivate::elapsed(lastPosTime) < 100) {
+ vData.updateVelocity();
+ hData.updateVelocity();
+ } else {
+ hData.velocity = 0.0;
+ vData.velocity = 0.0;
+ }
+
+ vTime = timeline.time();
+
+ qreal velocity = vData.velocity;
+ if (vData.atBeginning || vData.atEnd)
+ velocity /= 2;
+ if (qAbs(velocity) > MinimumFlickVelocity && qAbs(event->pos().y() - pressPos.y()) > FlickThreshold)
+ flickY(velocity);
+ else
+ fixupY();
+
+ velocity = hData.velocity;
+ if (hData.atBeginning || hData.atEnd)
+ velocity /= 2;
+ if (qAbs(velocity) > MinimumFlickVelocity && qAbs(event->pos().x() - pressPos.x()) > FlickThreshold)
+ flickX(velocity);
+ else
+ fixupX();
+
+ if (!timeline.isActive())
+ q->movementEnding();
+}
+
+void QSGFlickable::mousePressEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(QSGFlickable);
+ if (d->interactive) {
+ if (!d->pressed)
+ d->handleMousePressEvent(event);
+ event->accept();
+ } else {
+ QSGItem::mousePressEvent(event);
+ }
+}
+
+void QSGFlickable::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(QSGFlickable);
+ if (d->interactive) {
+ d->handleMouseMoveEvent(event);
+ event->accept();
+ } else {
+ QSGItem::mouseMoveEvent(event);
+ }
+}
+
+void QSGFlickable::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(QSGFlickable);
+ if (d->interactive) {
+ d->clearDelayedPress();
+ d->handleMouseReleaseEvent(event);
+ event->accept();
+ ungrabMouse();
+ } else {
+ QSGItem::mouseReleaseEvent(event);
+ }
+}
+
+void QSGFlickable::wheelEvent(QGraphicsSceneWheelEvent *event)
+{
+ Q_D(QSGFlickable);
+ if (!d->interactive) {
+ QSGItem::wheelEvent(event);
+ } else if (yflick() && event->orientation() == Qt::Vertical) {
+ bool valid = false;
+ if (event->delta() > 0 && contentY() > -minYExtent()) {
+ d->vData.velocity = qMax(event->delta()*2 - d->vData.smoothVelocity.value(), qreal(d->maxVelocity/4));
+ valid = true;
+ } else if (event->delta() < 0 && contentY() < -maxYExtent()) {
+ d->vData.velocity = qMin(event->delta()*2 - d->vData.smoothVelocity.value(), qreal(-d->maxVelocity/4));
+ valid = true;
+ }
+ if (valid) {
+ d->flickingVertically = false;
+ d->flickY(d->vData.velocity);
+ if (d->flickingVertically) {
+ d->vMoved = true;
+ movementStarting();
+ }
+ event->accept();
+ }
+ } else if (xflick() && event->orientation() == Qt::Horizontal) {
+ bool valid = false;
+ if (event->delta() > 0 && contentX() > -minXExtent()) {
+ d->hData.velocity = qMax(event->delta()*2 - d->hData.smoothVelocity.value(), qreal(d->maxVelocity/4));
+ valid = true;
+ } else if (event->delta() < 0 && contentX() < -maxXExtent()) {
+ d->hData.velocity = qMin(event->delta()*2 - d->hData.smoothVelocity.value(), qreal(-d->maxVelocity/4));
+ valid = true;
+ }
+ if (valid) {
+ d->flickingHorizontally = false;
+ d->flickX(d->hData.velocity);
+ if (d->flickingHorizontally) {
+ d->hMoved = true;
+ movementStarting();
+ }
+ event->accept();
+ }
+ } else {
+ QSGItem::wheelEvent(event);
+ }
+}
+
+bool QSGFlickablePrivate::isOutermostPressDelay() const
+{
+ Q_Q(const QSGFlickable);
+ QSGItem *item = q->parentItem();
+ while (item) {
+ QSGFlickable *flick = qobject_cast<QSGFlickable*>(item);
+ if (flick && flick->pressDelay() > 0 && flick->isInteractive())
+ return false;
+ item = item->parentItem();
+ }
+
+ return true;
+}
+
+void QSGFlickablePrivate::captureDelayedPress(QGraphicsSceneMouseEvent *event)
+{
+ Q_Q(QSGFlickable);
+ if (!q->canvas() || pressDelay <= 0)
+ return;
+ if (!isOutermostPressDelay())
+ return;
+ delayedPressTarget = q->canvas()->mouseGrabberItem();
+ delayedPressEvent = new QGraphicsSceneMouseEvent(event->type());
+ delayedPressEvent->setAccepted(false);
+ for (int i = 0x1; i <= 0x10; i <<= 1) {
+ if (event->buttons() & i) {
+ Qt::MouseButton button = Qt::MouseButton(i);
+ delayedPressEvent->setButtonDownPos(button, event->buttonDownPos(button));
+ delayedPressEvent->setButtonDownScenePos(button, event->buttonDownScenePos(button));
+ delayedPressEvent->setButtonDownScreenPos(button, event->buttonDownScreenPos(button));
+ }
+ }
+ delayedPressEvent->setButtons(event->buttons());
+ delayedPressEvent->setButton(event->button());
+ delayedPressEvent->setPos(event->pos());
+ delayedPressEvent->setScenePos(event->scenePos());
+ delayedPressEvent->setScreenPos(event->screenPos());
+ delayedPressEvent->setLastPos(event->lastPos());
+ delayedPressEvent->setLastScenePos(event->lastScenePos());
+ delayedPressEvent->setLastScreenPos(event->lastScreenPos());
+ delayedPressEvent->setModifiers(event->modifiers());
+ delayedPressTimer.start(pressDelay, q);
+}
+
+void QSGFlickablePrivate::clearDelayedPress()
+{
+ if (delayedPressEvent) {
+ delayedPressTimer.stop();
+ delete delayedPressEvent;
+ delayedPressEvent = 0;
+ }
+}
+
+void QSGFlickablePrivate::setViewportX(qreal x)
+{
+ contentItem->setX(x);
+}
+
+void QSGFlickablePrivate::setViewportY(qreal y)
+{
+ contentItem->setY(y);
+}
+
+void QSGFlickable::timerEvent(QTimerEvent *event)
+{
+ Q_D(QSGFlickable);
+ if (event->timerId() == d->delayedPressTimer.timerId()) {
+ d->delayedPressTimer.stop();
+ if (d->delayedPressEvent) {
+ QSGItem *grabber = canvas() ? canvas()->mouseGrabberItem() : 0;
+ if (!grabber || grabber != this) {
+ // We replay the mouse press but the grabber we had might not be interessted by the event (e.g. overlay)
+ // so we reset the grabber
+ if (canvas()->mouseGrabberItem() == d->delayedPressTarget)
+ d->delayedPressTarget->ungrabMouse();
+ // Use the event handler that will take care of finding the proper item to propagate the event
+ QSGCanvasPrivate::get(canvas())->deliverMouseEvent(d->delayedPressEvent);
+ }
+ delete d->delayedPressEvent;
+ d->delayedPressEvent = 0;
+ }
+ }
+}
+
+qreal QSGFlickable::minYExtent() const
+{
+ return 0.0;
+}
+
+qreal QSGFlickable::minXExtent() const
+{
+ return 0.0;
+}
+
+/* returns -ve */
+qreal QSGFlickable::maxXExtent() const
+{
+ return width() - vWidth();
+}
+/* returns -ve */
+qreal QSGFlickable::maxYExtent() const
+{
+ return height() - vHeight();
+}
+
+void QSGFlickable::viewportMoved()
+{
+ Q_D(QSGFlickable);
+
+ qreal prevX = d->lastFlickablePosition.x();
+ qreal prevY = d->lastFlickablePosition.y();
+ d->velocityTimeline.clear();
+ if (d->pressed || d->calcVelocity) {
+ int elapsed = QSGItemPrivate::restart(d->velocityTime);
+ if (elapsed > 0) {
+ qreal horizontalVelocity = (prevX - d->hData.move.value()) * 1000 / elapsed;
+ qreal verticalVelocity = (prevY - d->vData.move.value()) * 1000 / elapsed;
+ d->velocityTimeline.move(d->hData.smoothVelocity, horizontalVelocity, d->reportedVelocitySmoothing);
+ d->velocityTimeline.move(d->hData.smoothVelocity, 0, d->reportedVelocitySmoothing);
+ d->velocityTimeline.move(d->vData.smoothVelocity, verticalVelocity, d->reportedVelocitySmoothing);
+ d->velocityTimeline.move(d->vData.smoothVelocity, 0, d->reportedVelocitySmoothing);
+ }
+ } else {
+ if (d->timeline.time() > d->vTime) {
+ qreal horizontalVelocity = (prevX - d->hData.move.value()) * 1000 / (d->timeline.time() - d->vTime);
+ qreal verticalVelocity = (prevY - d->vData.move.value()) * 1000 / (d->timeline.time() - d->vTime);
+ d->hData.smoothVelocity.setValue(horizontalVelocity);
+ d->vData.smoothVelocity.setValue(verticalVelocity);
+ }
+ }
+
+ if (!d->vData.inOvershoot && !d->vData.fixingUp && d->flickingVertically
+ && (d->vData.move.value() > minYExtent() || d->vData.move.value() < maxYExtent())
+ && qAbs(d->vData.smoothVelocity.value()) > 100) {
+ // Increase deceleration if we've passed a bound
+ d->vData.inOvershoot = true;
+ qreal maxDistance = d->overShootDistance(height());
+ d->timeline.reset(d->vData.move);
+ d->timeline.accel(d->vData.move, -d->vData.smoothVelocity.value(), d->deceleration*QML_FLICK_OVERSHOOTFRICTION, maxDistance);
+ d->timeline.callback(QDeclarativeTimeLineCallback(&d->vData.move, d->fixupY_callback, d));
+ }
+ if (!d->hData.inOvershoot && !d->hData.fixingUp && d->flickingHorizontally
+ && (d->hData.move.value() > minXExtent() || d->hData.move.value() < maxXExtent())
+ && qAbs(d->hData.smoothVelocity.value()) > 100) {
+ // Increase deceleration if we've passed a bound
+ d->hData.inOvershoot = true;
+ qreal maxDistance = d->overShootDistance(width());
+ d->timeline.reset(d->hData.move);
+ d->timeline.accel(d->hData.move, -d->hData.smoothVelocity.value(), d->deceleration*QML_FLICK_OVERSHOOTFRICTION, maxDistance);
+ d->timeline.callback(QDeclarativeTimeLineCallback(&d->hData.move, d->fixupX_callback, d));
+ }
+
+ d->lastFlickablePosition = QPointF(d->hData.move.value(), d->vData.move.value());
+
+ d->vTime = d->timeline.time();
+ d->updateBeginningEnd();
+}
+
+void QSGFlickable::geometryChanged(const QRectF &newGeometry,
+ const QRectF &oldGeometry)
+{
+ Q_D(QSGFlickable);
+ QSGItem::geometryChanged(newGeometry, oldGeometry);
+
+ bool changed = false;
+ if (newGeometry.width() != oldGeometry.width()) {
+ if (xflick())
+ changed = true;
+ if (d->hData.viewSize < 0) {
+ d->contentItem->setWidth(width());
+ emit contentWidthChanged();
+ }
+ // Make sure that we're entirely in view.
+ if (!d->pressed && !d->movingHorizontally && !d->movingVertically) {
+ d->fixupMode = QSGFlickablePrivate::Immediate;
+ d->fixupX();
+ }
+ }
+ if (newGeometry.height() != oldGeometry.height()) {
+ if (yflick())
+ changed = true;
+ if (d->vData.viewSize < 0) {
+ d->contentItem->setHeight(height());
+ emit contentHeightChanged();
+ }
+ // Make sure that we're entirely in view.
+ if (!d->pressed && !d->movingHorizontally && !d->movingVertically) {
+ d->fixupMode = QSGFlickablePrivate::Immediate;
+ d->fixupY();
+ }
+ }
+
+ if (changed)
+ d->updateBeginningEnd();
+}
+
+void QSGFlickable::cancelFlick()
+{
+ Q_D(QSGFlickable);
+ d->timeline.reset(d->hData.move);
+ d->timeline.reset(d->vData.move);
+ movementEnding();
+}
+
+void QSGFlickablePrivate::data_append(QDeclarativeListProperty<QObject> *prop, QObject *o)
+{
+ QSGItem *i = qobject_cast<QSGItem *>(o);
+ if (i) {
+ i->setParentItem(static_cast<QSGFlickablePrivate*>(prop->data)->contentItem);
+ } else {
+ o->setParent(prop->object); // XXX todo - do we want this?
+ }
+}
+
+int QSGFlickablePrivate::data_count(QDeclarativeListProperty<QObject> *)
+{
+ // XXX todo
+ return 0;
+}
+
+QObject *QSGFlickablePrivate::data_at(QDeclarativeListProperty<QObject> *, int)
+{
+ // XXX todo
+ return 0;
+}
+
+void QSGFlickablePrivate::data_clear(QDeclarativeListProperty<QObject> *)
+{
+ // XXX todo
+}
+
+QDeclarativeListProperty<QObject> QSGFlickable::flickableData()
+{
+ Q_D(QSGFlickable);
+ return QDeclarativeListProperty<QObject>(this, (void *)d, QSGFlickablePrivate::data_append,
+ QSGFlickablePrivate::data_count,
+ QSGFlickablePrivate::data_at,
+ QSGFlickablePrivate::data_clear);
+}
+
+QDeclarativeListProperty<QSGItem> QSGFlickable::flickableChildren()
+{
+ Q_D(QSGFlickable);
+ return QSGItemPrivate::get(d->contentItem)->children();
+}
+
+QSGFlickable::BoundsBehavior QSGFlickable::boundsBehavior() const
+{
+ Q_D(const QSGFlickable);
+ return d->boundsBehavior;
+}
+
+void QSGFlickable::setBoundsBehavior(BoundsBehavior b)
+{
+ Q_D(QSGFlickable);
+ if (b == d->boundsBehavior)
+ return;
+ d->boundsBehavior = b;
+ emit boundsBehaviorChanged();
+}
+
+qreal QSGFlickable::contentWidth() const
+{
+ Q_D(const QSGFlickable);
+ return d->hData.viewSize;
+}
+
+void QSGFlickable::setContentWidth(qreal w)
+{
+ Q_D(QSGFlickable);
+ if (d->hData.viewSize == w)
+ return;
+ d->hData.viewSize = w;
+ if (w < 0)
+ d->contentItem->setWidth(width());
+ else
+ d->contentItem->setWidth(w);
+ // Make sure that we're entirely in view.
+ if (!d->pressed && !d->movingHorizontally && !d->movingVertically) {
+ d->fixupMode = QSGFlickablePrivate::Immediate;
+ d->fixupX();
+ } else if (!d->pressed && d->hData.fixingUp) {
+ d->fixupMode = QSGFlickablePrivate::ExtentChanged;
+ d->fixupX();
+ }
+ emit contentWidthChanged();
+ d->updateBeginningEnd();
+}
+
+qreal QSGFlickable::contentHeight() const
+{
+ Q_D(const QSGFlickable);
+ return d->vData.viewSize;
+}
+
+void QSGFlickable::setContentHeight(qreal h)
+{
+ Q_D(QSGFlickable);
+ if (d->vData.viewSize == h)
+ return;
+ d->vData.viewSize = h;
+ if (h < 0)
+ d->contentItem->setHeight(height());
+ else
+ d->contentItem->setHeight(h);
+ // Make sure that we're entirely in view.
+ if (!d->pressed && !d->movingHorizontally && !d->movingVertically) {
+ d->fixupMode = QSGFlickablePrivate::Immediate;
+ d->fixupY();
+ } else if (!d->pressed && d->vData.fixingUp) {
+ d->fixupMode = QSGFlickablePrivate::ExtentChanged;
+ d->fixupY();
+ }
+ emit contentHeightChanged();
+ d->updateBeginningEnd();
+}
+
+void QSGFlickable::resizeContent(qreal w, qreal h, QPointF center)
+{
+ Q_D(QSGFlickable);
+ if (w != d->hData.viewSize) {
+ qreal oldSize = d->hData.viewSize;
+ d->hData.viewSize = w;
+ d->contentItem->setWidth(w);
+ emit contentWidthChanged();
+ if (center.x() != 0) {
+ qreal pos = center.x() * w / oldSize;
+ setContentX(contentX() + pos - center.x());
+ }
+ }
+ if (h != d->vData.viewSize) {
+ qreal oldSize = d->vData.viewSize;
+ d->vData.viewSize = h;
+ d->contentItem->setHeight(h);
+ emit contentHeightChanged();
+ if (center.y() != 0) {
+ qreal pos = center.y() * h / oldSize;
+ setContentY(contentY() + pos - center.y());
+ }
+ }
+ d->updateBeginningEnd();
+}
+
+void QSGFlickable::returnToBounds()
+{
+ Q_D(QSGFlickable);
+ d->fixupX();
+ d->fixupY();
+}
+
+qreal QSGFlickable::vWidth() const
+{
+ Q_D(const QSGFlickable);
+ if (d->hData.viewSize < 0)
+ return width();
+ else
+ return d->hData.viewSize;
+}
+
+qreal QSGFlickable::vHeight() const
+{
+ Q_D(const QSGFlickable);
+ if (d->vData.viewSize < 0)
+ return height();
+ else
+ return d->vData.viewSize;
+}
+
+bool QSGFlickable::xflick() const
+{
+ Q_D(const QSGFlickable);
+ if (d->flickableDirection == QSGFlickable::AutoFlickDirection)
+ return vWidth() != width();
+ return d->flickableDirection & QSGFlickable::HorizontalFlick;
+}
+
+bool QSGFlickable::yflick() const
+{
+ Q_D(const QSGFlickable);
+ if (d->flickableDirection == QSGFlickable::AutoFlickDirection)
+ return vHeight() != height();
+ return d->flickableDirection & QSGFlickable::VerticalFlick;
+}
+
+void QSGFlickable::mouseUngrabEvent()
+{
+ Q_D(QSGFlickable);
+ if (d->pressed) {
+ // if our mouse grab has been removed (probably by another Flickable),
+ // fix our state
+ d->pressed = false;
+ d->stealMouse = false;
+ setKeepMouseGrab(false);
+ }
+}
+
+bool QSGFlickable::sendMouseEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(QSGFlickable);
+ QGraphicsSceneMouseEvent mouseEvent(event->type());
+ QRectF myRect = mapRectToScene(QRectF(0, 0, width(), height()));
+
+ QSGCanvas *c = canvas();
+ QSGItem *grabber = c ? c->mouseGrabberItem() : 0;
+ bool disabledItem = grabber && !grabber->isEnabled();
+ bool stealThisEvent = d->stealMouse;
+ if ((stealThisEvent || myRect.contains(event->scenePos().toPoint())) && (!grabber || !grabber->keepMouseGrab() || disabledItem)) {
+ mouseEvent.setAccepted(false);
+ for (int i = 0x1; i <= 0x10; i <<= 1) {
+ if (event->buttons() & i) {
+ Qt::MouseButton button = Qt::MouseButton(i);
+ mouseEvent.setButtonDownPos(button, mapFromScene(event->buttonDownPos(button)));
+ }
+ }
+ mouseEvent.setScenePos(event->scenePos());
+ mouseEvent.setLastScenePos(event->lastScenePos());
+ mouseEvent.setPos(mapFromScene(event->scenePos()));
+ mouseEvent.setLastPos(mapFromScene(event->lastScenePos()));
+
+ switch(mouseEvent.type()) {
+ case QEvent::GraphicsSceneMouseMove:
+ d->handleMouseMoveEvent(&mouseEvent);
+ break;
+ case QEvent::GraphicsSceneMousePress:
+ if (d->pressed) // we are already pressed - this is a delayed replay
+ return false;
+
+ d->handleMousePressEvent(&mouseEvent);
+ d->captureDelayedPress(event);
+ stealThisEvent = d->stealMouse; // Update stealThisEvent in case changed by function call above
+ break;
+ case QEvent::GraphicsSceneMouseRelease:
+ if (d->delayedPressEvent) {
+ // We replay the mouse press but the grabber we had might not be interessted by the event (e.g. overlay)
+ // so we reset the grabber
+ if (c->mouseGrabberItem() == d->delayedPressTarget)
+ d->delayedPressTarget->ungrabMouse();
+ //Use the event handler that will take care of finding the proper item to propagate the event
+ QSGCanvasPrivate::get(canvas())->deliverMouseEvent(d->delayedPressEvent);
+ d->clearDelayedPress();
+ // We send the release
+ canvas()->sendEvent(c->mouseGrabberItem(), event);
+ // And the event has been consumed
+ d->stealMouse = false;
+ d->pressed = false;
+ return true;
+ }
+ d->handleMouseReleaseEvent(&mouseEvent);
+ break;
+ default:
+ break;
+ }
+ grabber = qobject_cast<QSGItem*>(c->mouseGrabberItem());
+ if ((grabber && stealThisEvent && !grabber->keepMouseGrab() && grabber != this) || disabledItem) {
+ d->clearDelayedPress();
+ grabMouse();
+ }
+
+ return stealThisEvent || d->delayedPressEvent || disabledItem;
+ } else if (d->lastPosTime.isValid()) {
+ d->lastPosTime.invalidate();
+ }
+ if (mouseEvent.type() == QEvent::GraphicsSceneMouseRelease) {
+ d->clearDelayedPress();
+ d->stealMouse = false;
+ d->pressed = false;
+ }
+ return false;
+}
+
+
+bool QSGFlickable::childMouseEventFilter(QSGItem *i, QEvent *e)
+{
+ Q_D(QSGFlickable);
+ if (!isVisible() || !d->interactive)
+ return QSGItem::childMouseEventFilter(i, e);
+ switch (e->type()) {
+ case QEvent::GraphicsSceneMousePress:
+ case QEvent::GraphicsSceneMouseMove:
+ case QEvent::GraphicsSceneMouseRelease:
+ return sendMouseEvent(static_cast<QGraphicsSceneMouseEvent *>(e));
+ default:
+ break;
+ }
+
+ return QSGItem::childMouseEventFilter(i, e);
+}
+
+qreal QSGFlickable::maximumFlickVelocity() const
+{
+ Q_D(const QSGFlickable);
+ return d->maxVelocity;
+}
+
+void QSGFlickable::setMaximumFlickVelocity(qreal v)
+{
+ Q_D(QSGFlickable);
+ if (v == d->maxVelocity)
+ return;
+ d->maxVelocity = v;
+ emit maximumFlickVelocityChanged();
+}
+
+qreal QSGFlickable::flickDeceleration() const
+{
+ Q_D(const QSGFlickable);
+ return d->deceleration;
+}
+
+void QSGFlickable::setFlickDeceleration(qreal deceleration)
+{
+ Q_D(QSGFlickable);
+ if (deceleration == d->deceleration)
+ return;
+ d->deceleration = deceleration;
+ emit flickDecelerationChanged();
+}
+
+bool QSGFlickable::isFlicking() const
+{
+ Q_D(const QSGFlickable);
+ return d->flickingHorizontally || d->flickingVertically;
+}
+
+bool QSGFlickable::isFlickingHorizontally() const
+{
+ Q_D(const QSGFlickable);
+ return d->flickingHorizontally;
+}
+
+bool QSGFlickable::isFlickingVertically() const
+{
+ Q_D(const QSGFlickable);
+ return d->flickingVertically;
+}
+
+int QSGFlickable::pressDelay() const
+{
+ Q_D(const QSGFlickable);
+ return d->pressDelay;
+}
+
+void QSGFlickable::setPressDelay(int delay)
+{
+ Q_D(QSGFlickable);
+ if (d->pressDelay == delay)
+ return;
+ d->pressDelay = delay;
+ emit pressDelayChanged();
+}
+
+
+bool QSGFlickable::isMoving() const
+{
+ Q_D(const QSGFlickable);
+ return d->movingHorizontally || d->movingVertically;
+}
+
+bool QSGFlickable::isMovingHorizontally() const
+{
+ Q_D(const QSGFlickable);
+ return d->movingHorizontally;
+}
+
+bool QSGFlickable::isMovingVertically() const
+{
+ Q_D(const QSGFlickable);
+ return d->movingVertically;
+}
+
+void QSGFlickable::movementStarting()
+{
+ Q_D(QSGFlickable);
+ if (d->hMoved && !d->movingHorizontally) {
+ d->movingHorizontally = true;
+ emit movingChanged();
+ emit movingHorizontallyChanged();
+ if (!d->movingVertically)
+ emit movementStarted();
+ }
+ else if (d->vMoved && !d->movingVertically) {
+ d->movingVertically = true;
+ emit movingChanged();
+ emit movingVerticallyChanged();
+ if (!d->movingHorizontally)
+ emit movementStarted();
+ }
+}
+
+void QSGFlickable::movementEnding()
+{
+ Q_D(QSGFlickable);
+ movementXEnding();
+ movementYEnding();
+ d->hData.smoothVelocity.setValue(0);
+ d->vData.smoothVelocity.setValue(0);
+}
+
+void QSGFlickable::movementXEnding()
+{
+ Q_D(QSGFlickable);
+ if (d->flickingHorizontally) {
+ d->flickingHorizontally = false;
+ emit flickingChanged();
+ emit flickingHorizontallyChanged();
+ if (!d->flickingVertically)
+ emit flickEnded();
+ }
+ if (!d->pressed && !d->stealMouse) {
+ if (d->movingHorizontally) {
+ d->movingHorizontally = false;
+ d->hMoved = false;
+ emit movingChanged();
+ emit movingHorizontallyChanged();
+ if (!d->movingVertically)
+ emit movementEnded();
+ }
+ }
+ d->hData.fixingUp = false;
+}
+
+void QSGFlickable::movementYEnding()
+{
+ Q_D(QSGFlickable);
+ if (d->flickingVertically) {
+ d->flickingVertically = false;
+ emit flickingChanged();
+ emit flickingVerticallyChanged();
+ if (!d->flickingHorizontally)
+ emit flickEnded();
+ }
+ if (!d->pressed && !d->stealMouse) {
+ if (d->movingVertically) {
+ d->movingVertically = false;
+ d->vMoved = false;
+ emit movingChanged();
+ emit movingVerticallyChanged();
+ if (!d->movingHorizontally)
+ emit movementEnded();
+ }
+ }
+ d->vData.fixingUp = false;
+}
+
+void QSGFlickablePrivate::updateVelocity()
+{
+ Q_Q(QSGFlickable);
+ emit q->horizontalVelocityChanged();
+ emit q->verticalVelocityChanged();
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/items/qsgflickable_p.h b/src/declarative/items/qsgflickable_p.h
new file mode 100644
index 0000000000..c1ed024527
--- /dev/null
+++ b/src/declarative/items/qsgflickable_p.h
@@ -0,0 +1,230 @@
+// Commit: 1bcddaaf318fc37c71c5191913f3487c49444ec6
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGFLICKABLE_P_H
+#define QSGFLICKABLE_P_H
+
+#include "qsgitem.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QSGFlickablePrivate;
+class QSGFlickableVisibleArea;
+class Q_AUTOTEST_EXPORT QSGFlickable : public QSGItem
+{
+ Q_OBJECT
+
+ Q_PROPERTY(qreal contentWidth READ contentWidth WRITE setContentWidth NOTIFY contentWidthChanged)
+ Q_PROPERTY(qreal contentHeight READ contentHeight WRITE setContentHeight NOTIFY contentHeightChanged)
+ Q_PROPERTY(qreal contentX READ contentX WRITE setContentX NOTIFY contentXChanged)
+ Q_PROPERTY(qreal contentY READ contentY WRITE setContentY NOTIFY contentYChanged)
+ Q_PROPERTY(QSGItem *contentItem READ contentItem CONSTANT)
+
+ Q_PROPERTY(qreal horizontalVelocity READ horizontalVelocity NOTIFY horizontalVelocityChanged)
+ Q_PROPERTY(qreal verticalVelocity READ verticalVelocity NOTIFY verticalVelocityChanged)
+
+ Q_PROPERTY(BoundsBehavior boundsBehavior READ boundsBehavior WRITE setBoundsBehavior NOTIFY boundsBehaviorChanged)
+ Q_PROPERTY(qreal maximumFlickVelocity READ maximumFlickVelocity WRITE setMaximumFlickVelocity NOTIFY maximumFlickVelocityChanged)
+ Q_PROPERTY(qreal flickDeceleration READ flickDeceleration WRITE setFlickDeceleration NOTIFY flickDecelerationChanged)
+ Q_PROPERTY(bool moving READ isMoving NOTIFY movingChanged)
+ Q_PROPERTY(bool movingHorizontally READ isMovingHorizontally NOTIFY movingHorizontallyChanged)
+ Q_PROPERTY(bool movingVertically READ isMovingVertically NOTIFY movingVerticallyChanged)
+ Q_PROPERTY(bool flicking READ isFlicking NOTIFY flickingChanged)
+ Q_PROPERTY(bool flickingHorizontally READ isFlickingHorizontally NOTIFY flickingHorizontallyChanged)
+ Q_PROPERTY(bool flickingVertically READ isFlickingVertically NOTIFY flickingVerticallyChanged)
+ Q_PROPERTY(FlickableDirection flickableDirection READ flickableDirection WRITE setFlickableDirection NOTIFY flickableDirectionChanged)
+
+ Q_PROPERTY(bool interactive READ isInteractive WRITE setInteractive NOTIFY interactiveChanged)
+ Q_PROPERTY(int pressDelay READ pressDelay WRITE setPressDelay NOTIFY pressDelayChanged)
+
+ Q_PROPERTY(bool atXEnd READ isAtXEnd NOTIFY isAtBoundaryChanged)
+ Q_PROPERTY(bool atYEnd READ isAtYEnd NOTIFY isAtBoundaryChanged)
+ Q_PROPERTY(bool atXBeginning READ isAtXBeginning NOTIFY isAtBoundaryChanged)
+ Q_PROPERTY(bool atYBeginning READ isAtYBeginning NOTIFY isAtBoundaryChanged)
+
+ Q_PROPERTY(QSGFlickableVisibleArea *visibleArea READ visibleArea CONSTANT)
+
+ Q_PROPERTY(QDeclarativeListProperty<QObject> flickableData READ flickableData)
+ Q_PROPERTY(QDeclarativeListProperty<QSGItem> flickableChildren READ flickableChildren)
+ Q_CLASSINFO("DefaultProperty", "flickableData")
+
+ Q_ENUMS(FlickableDirection)
+ Q_ENUMS(BoundsBehavior)
+
+public:
+ QSGFlickable(QSGItem *parent=0);
+ ~QSGFlickable();
+
+ QDeclarativeListProperty<QObject> flickableData();
+ QDeclarativeListProperty<QSGItem> flickableChildren();
+
+ enum BoundsBehavior { StopAtBounds, DragOverBounds, DragAndOvershootBounds };
+ BoundsBehavior boundsBehavior() const;
+ void setBoundsBehavior(BoundsBehavior);
+
+ qreal contentWidth() const;
+ void setContentWidth(qreal);
+
+ qreal contentHeight() const;
+ void setContentHeight(qreal);
+
+ qreal contentX() const;
+ virtual void setContentX(qreal pos);
+
+ qreal contentY() const;
+ virtual void setContentY(qreal pos);
+
+ bool isMoving() const;
+ bool isMovingHorizontally() const;
+ bool isMovingVertically() const;
+ bool isFlicking() const;
+ bool isFlickingHorizontally() const;
+ bool isFlickingVertically() const;
+
+ int pressDelay() const;
+ void setPressDelay(int delay);
+
+ qreal maximumFlickVelocity() const;
+ void setMaximumFlickVelocity(qreal);
+
+ qreal flickDeceleration() const;
+ void setFlickDeceleration(qreal);
+
+ bool isInteractive() const;
+ void setInteractive(bool);
+
+ qreal horizontalVelocity() const;
+ qreal verticalVelocity() const;
+
+ bool isAtXEnd() const;
+ bool isAtXBeginning() const;
+ bool isAtYEnd() const;
+ bool isAtYBeginning() const;
+
+ QSGItem *contentItem();
+
+ enum FlickableDirection { AutoFlickDirection=0x00, HorizontalFlick=0x01, VerticalFlick=0x02, HorizontalAndVerticalFlick=0x03 };
+ FlickableDirection flickableDirection() const;
+ void setFlickableDirection(FlickableDirection);
+
+ Q_INVOKABLE void resizeContent(qreal w, qreal h, QPointF center);
+ Q_INVOKABLE void returnToBounds();
+
+Q_SIGNALS:
+ void contentWidthChanged();
+ void contentHeightChanged();
+ void contentXChanged();
+ void contentYChanged();
+ void movingChanged();
+ void movingHorizontallyChanged();
+ void movingVerticallyChanged();
+ void flickingChanged();
+ void flickingHorizontallyChanged();
+ void flickingVerticallyChanged();
+ void horizontalVelocityChanged();
+ void verticalVelocityChanged();
+ void isAtBoundaryChanged();
+ void flickableDirectionChanged();
+ void interactiveChanged();
+ void boundsBehaviorChanged();
+ void maximumFlickVelocityChanged();
+ void flickDecelerationChanged();
+ void pressDelayChanged();
+ void movementStarted();
+ void movementEnded();
+ void flickStarted();
+ void flickEnded();
+
+protected:
+ virtual bool childMouseEventFilter(QSGItem *, QEvent *);
+ virtual void mousePressEvent(QGraphicsSceneMouseEvent *event);
+ virtual void mouseMoveEvent(QGraphicsSceneMouseEvent *event);
+ virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *event);
+ virtual void wheelEvent(QGraphicsSceneWheelEvent *event);
+ virtual void timerEvent(QTimerEvent *event);
+
+ QSGFlickableVisibleArea *visibleArea();
+
+protected Q_SLOTS:
+ virtual void ticked();
+ void movementStarting();
+ void movementEnding();
+
+protected:
+ void movementXEnding();
+ void movementYEnding();
+ virtual qreal minXExtent() const;
+ virtual qreal minYExtent() const;
+ virtual qreal maxXExtent() const;
+ virtual qreal maxYExtent() const;
+ qreal vWidth() const;
+ qreal vHeight() const;
+ virtual void viewportMoved();
+ virtual void geometryChanged(const QRectF &newGeometry,
+ const QRectF &oldGeometry);
+ void mouseUngrabEvent();
+ bool sendMouseEvent(QGraphicsSceneMouseEvent *event);
+
+ bool xflick() const;
+ bool yflick() const;
+ void cancelFlick();
+
+protected:
+ QSGFlickable(QSGFlickablePrivate &dd, QSGItem *parent);
+
+private:
+ Q_DISABLE_COPY(QSGFlickable)
+ Q_DECLARE_PRIVATE(QSGFlickable)
+ friend class QSGFlickableVisibleArea;
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QSGFlickable)
+
+QT_END_HEADER
+
+#endif // QSGFLICKABLE_P_H
diff --git a/src/declarative/items/qsgflickable_p_p.h b/src/declarative/items/qsgflickable_p_p.h
new file mode 100644
index 0000000000..114db53668
--- /dev/null
+++ b/src/declarative/items/qsgflickable_p_p.h
@@ -0,0 +1,243 @@
+// Commit: 160f1867868cdea916923652b00484ed11f90aaa
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGFLICKABLE_P_P_H
+#define QSGFLICKABLE_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 "qsgflickable_p.h"
+#include "qsgitem_p.h"
+#include "qsgitemchangelistener_p.h"
+
+#include <QtDeclarative/qdeclarative.h>
+#include <QtCore/qdatetime.h>
+
+#include <private/qdeclarativetimeline_p_p.h>
+#include <private/qdeclarativeanimation_p_p.h>
+
+QT_BEGIN_NAMESPACE
+
+// Really slow flicks can be annoying.
+const qreal MinimumFlickVelocity = 75.0;
+
+class QSGFlickableVisibleArea;
+class QSGFlickablePrivate : public QSGItemPrivate, public QSGItemChangeListener
+{
+ Q_DECLARE_PUBLIC(QSGFlickable)
+
+public:
+ static inline QSGFlickablePrivate *get(QSGFlickable *o) { return o->d_func(); }
+
+ QSGFlickablePrivate();
+ void init();
+
+ struct Velocity : public QDeclarativeTimeLineValue
+ {
+ Velocity(QSGFlickablePrivate *p)
+ : parent(p) {}
+ virtual void setValue(qreal v) {
+ if (v != value()) {
+ QDeclarativeTimeLineValue::setValue(v);
+ parent->updateVelocity();
+ }
+ }
+ QSGFlickablePrivate *parent;
+ };
+
+ struct AxisData {
+ AxisData(QSGFlickablePrivate *fp, void (QSGFlickablePrivate::*func)(qreal))
+ : move(fp, func), viewSize(-1), smoothVelocity(fp), atEnd(false), atBeginning(true)
+ , fixingUp(false), inOvershoot(false)
+ {}
+
+ void reset() {
+ velocityBuffer.clear();
+ dragStartOffset = 0;
+ fixingUp = false;
+ inOvershoot = false;
+ }
+
+ void addVelocitySample(qreal v, qreal maxVelocity);
+ void updateVelocity();
+
+ QDeclarativeTimeLineValueProxy<QSGFlickablePrivate> move;
+ qreal viewSize;
+ qreal pressPos;
+ qreal dragStartOffset;
+ qreal dragMinBound;
+ qreal dragMaxBound;
+ qreal velocity;
+ qreal flickTarget;
+ QSGFlickablePrivate::Velocity smoothVelocity;
+ QPODVector<qreal,10> velocityBuffer;
+ bool atEnd : 1;
+ bool atBeginning : 1;
+ bool fixingUp : 1;
+ bool inOvershoot : 1;
+ };
+
+ void flickX(qreal velocity);
+ void flickY(qreal velocity);
+ virtual void flick(AxisData &data, qreal minExtent, qreal maxExtent, qreal vSize,
+ QDeclarativeTimeLineCallback::Callback fixupCallback, qreal velocity);
+
+ void fixupX();
+ void fixupY();
+ virtual void fixup(AxisData &data, qreal minExtent, qreal maxExtent);
+
+ void updateBeginningEnd();
+
+ bool isOutermostPressDelay() const;
+ void captureDelayedPress(QGraphicsSceneMouseEvent *event);
+ void clearDelayedPress();
+
+ void setViewportX(qreal x);
+ void setViewportY(qreal y);
+
+ qreal overShootDistance(qreal size);
+
+ void itemGeometryChanged(QSGItem *, const QRectF &, const QRectF &);
+
+public:
+ QSGItem *contentItem;
+
+ AxisData hData;
+ AxisData vData;
+
+ QDeclarativeTimeLine timeline;
+ bool flickingHorizontally : 1;
+ bool flickingVertically : 1;
+ bool hMoved : 1;
+ bool vMoved : 1;
+ bool movingHorizontally : 1;
+ bool movingVertically : 1;
+ bool stealMouse : 1;
+ bool pressed : 1;
+ bool interactive : 1;
+ bool calcVelocity : 1;
+ QElapsedTimer lastPosTime;
+ QPointF lastPos;
+ QPointF pressPos;
+ QElapsedTimer pressTime;
+ qreal deceleration;
+ qreal maxVelocity;
+ QElapsedTimer velocityTime;
+ QPointF lastFlickablePosition;
+ qreal reportedVelocitySmoothing;
+ QGraphicsSceneMouseEvent *delayedPressEvent;
+ QSGItem *delayedPressTarget;
+ QBasicTimer delayedPressTimer;
+ int pressDelay;
+ int fixupDuration;
+
+ enum FixupMode { Normal, Immediate, ExtentChanged };
+ FixupMode fixupMode;
+
+ static void fixupY_callback(void *);
+ static void fixupX_callback(void *);
+
+ void updateVelocity();
+ int vTime;
+ QDeclarativeTimeLine velocityTimeline;
+ QSGFlickableVisibleArea *visibleArea;
+ QSGFlickable::FlickableDirection flickableDirection;
+ QSGFlickable::BoundsBehavior boundsBehavior;
+
+ void handleMousePressEvent(QGraphicsSceneMouseEvent *);
+ void handleMouseMoveEvent(QGraphicsSceneMouseEvent *);
+ void handleMouseReleaseEvent(QGraphicsSceneMouseEvent *);
+
+ // flickableData property
+ static void data_append(QDeclarativeListProperty<QObject> *, QObject *);
+ static int data_count(QDeclarativeListProperty<QObject> *);
+ static QObject *data_at(QDeclarativeListProperty<QObject> *, int);
+ static void data_clear(QDeclarativeListProperty<QObject> *);
+};
+
+class QSGFlickableVisibleArea : public QObject
+{
+ Q_OBJECT
+
+ Q_PROPERTY(qreal xPosition READ xPosition NOTIFY xPositionChanged)
+ Q_PROPERTY(qreal yPosition READ yPosition NOTIFY yPositionChanged)
+ Q_PROPERTY(qreal widthRatio READ widthRatio NOTIFY widthRatioChanged)
+ Q_PROPERTY(qreal heightRatio READ heightRatio NOTIFY heightRatioChanged)
+
+public:
+ QSGFlickableVisibleArea(QSGFlickable *parent=0);
+
+ qreal xPosition() const;
+ qreal widthRatio() const;
+ qreal yPosition() const;
+ qreal heightRatio() const;
+
+ void updateVisible();
+
+signals:
+ void xPositionChanged(qreal xPosition);
+ void yPositionChanged(qreal yPosition);
+ void widthRatioChanged(qreal widthRatio);
+ void heightRatioChanged(qreal heightRatio);
+
+private:
+ QSGFlickable *flickable;
+ qreal m_xPosition;
+ qreal m_widthRatio;
+ qreal m_yPosition;
+ qreal m_heightRatio;
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QSGFlickableVisibleArea)
+
+#endif // QSGFLICKABLE_P_P_H
diff --git a/src/declarative/items/qsgflipable.cpp b/src/declarative/items/qsgflipable.cpp
new file mode 100644
index 0000000000..a856d6360b
--- /dev/null
+++ b/src/declarative/items/qsgflipable.cpp
@@ -0,0 +1,255 @@
+// Commit: caee66da925949cf7aef2ff8e1a86c38dd6e6efd
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgflipable_p.h"
+#include "qsgitem_p.h"
+
+#include <private/qdeclarativeguard_p.h>
+
+#include <QtDeclarative/qdeclarativeinfo.h>
+
+QT_BEGIN_NAMESPACE
+
+// XXX todo - i think this needs work and a bit of a re-think
+
+class QSGLocalTransform : public QSGTransform
+{
+ Q_OBJECT
+public:
+ QSGLocalTransform(QObject *parent) : QSGTransform(parent) {}
+
+ void setTransform(const QTransform &t) {
+ transform = t;
+ update();
+ }
+ virtual void applyTo(QMatrix4x4 *matrix) const {
+ *matrix *= transform;
+ }
+private:
+ QTransform transform;
+};
+
+class QSGFlipablePrivate : public QSGItemPrivate
+{
+ Q_DECLARE_PUBLIC(QSGFlipable)
+public:
+ QSGFlipablePrivate() : current(QSGFlipable::Front), front(0), back(0), sideDirty(false) {}
+
+ virtual void transformChanged();
+ void updateSide();
+ void setBackTransform();
+
+ QSGFlipable::Side current;
+ QDeclarativeGuard<QSGLocalTransform> backTransform;
+ QDeclarativeGuard<QSGItem> front;
+ QDeclarativeGuard<QSGItem> back;
+
+ bool sideDirty;
+ bool wantBackXFlipped;
+ bool wantBackYFlipped;
+};
+
+QSGFlipable::QSGFlipable(QSGItem *parent)
+: QSGItem(*(new QSGFlipablePrivate), parent)
+{
+}
+
+QSGFlipable::~QSGFlipable()
+{
+}
+
+QSGItem *QSGFlipable::front()
+{
+ Q_D(const QSGFlipable);
+ return d->front;
+}
+
+void QSGFlipable::setFront(QSGItem *front)
+{
+ Q_D(QSGFlipable);
+ if (d->front) {
+ qmlInfo(this) << tr("front is a write-once property");
+ return;
+ }
+ d->front = front;
+ d->front->setParentItem(this);
+ if (Back == d->current)
+ d->front->setOpacity(0.);
+ emit frontChanged();
+}
+
+QSGItem *QSGFlipable::back()
+{
+ Q_D(const QSGFlipable);
+ return d->back;
+}
+
+void QSGFlipable::setBack(QSGItem *back)
+{
+ Q_D(QSGFlipable);
+ if (d->back) {
+ qmlInfo(this) << tr("back is a write-once property");
+ return;
+ }
+ if (back == 0)
+ return;
+ d->back = back;
+ d->back->setParentItem(this);
+
+ d->backTransform = new QSGLocalTransform(d->back);
+ d->backTransform->prependToItem(d->back);
+
+ if (Front == d->current)
+ d->back->setOpacity(0.);
+ connect(back, SIGNAL(widthChanged()),
+ this, SLOT(retransformBack()));
+ connect(back, SIGNAL(heightChanged()),
+ this, SLOT(retransformBack()));
+ emit backChanged();
+}
+
+void QSGFlipable::retransformBack()
+{
+ Q_D(QSGFlipable);
+ if (d->current == QSGFlipable::Back && d->back)
+ d->setBackTransform();
+}
+
+QSGFlipable::Side QSGFlipable::side() const
+{
+ Q_D(const QSGFlipable);
+
+ const_cast<QSGFlipablePrivate *>(d)->updateSide();
+ return d->current;
+}
+
+void QSGFlipablePrivate::transformChanged()
+{
+ Q_Q(QSGFlipable);
+
+ if (!sideDirty) {
+ sideDirty = true;
+ q->polish();
+ }
+
+ QSGItemPrivate::transformChanged();
+}
+
+void QSGFlipable::updatePolish()
+{
+ Q_D(QSGFlipable);
+ d->updateSide();
+}
+
+// determination on the currently visible side of the flipable
+// has to be done on the complete scene transform to give
+// correct results.
+void QSGFlipablePrivate::updateSide()
+{
+ Q_Q(QSGFlipable);
+
+ if (!sideDirty)
+ return;
+
+ sideDirty = false;
+
+ QTransform sceneTransform;
+ itemToParentTransform(sceneTransform);
+
+ QPointF p1(0, 0);
+ QPointF p2(1, 0);
+ QPointF p3(1, 1);
+
+ QPointF scenep1 = sceneTransform.map(p1);
+ QPointF scenep2 = sceneTransform.map(p2);
+ QPointF scenep3 = sceneTransform.map(p3);
+#if 0
+ p1 = q->mapToParent(p1);
+ p2 = q->mapToParent(p2);
+ p3 = q->mapToParent(p3);
+#endif
+
+ qreal cross = (scenep1.x() - scenep2.x()) * (scenep3.y() - scenep2.y()) -
+ (scenep1.y() - scenep2.y()) * (scenep3.x() - scenep2.x());
+
+ wantBackYFlipped = scenep1.x() >= scenep2.x();
+ wantBackXFlipped = scenep2.y() >= scenep3.y();
+
+ QSGFlipable::Side newSide;
+ if (cross > 0) {
+ newSide = QSGFlipable::Back;
+ } else {
+ newSide = QSGFlipable::Front;
+ }
+
+ if (newSide != current) {
+ current = newSide;
+ if (current == QSGFlipable::Back && back)
+ setBackTransform();
+ if (front)
+ front->setOpacity((current==QSGFlipable::Front)?1.:0.);
+ if (back)
+ back->setOpacity((current==QSGFlipable::Back)?1.:0.);
+ emit q->sideChanged();
+ }
+}
+
+/* Depends on the width/height of the back item, and so needs reevaulating
+ if those change.
+*/
+void QSGFlipablePrivate::setBackTransform()
+{
+ QTransform mat;
+ mat.translate(back->width()/2,back->height()/2);
+ if (back->width() && wantBackYFlipped)
+ mat.rotate(180, Qt::YAxis);
+ if (back->height() && wantBackXFlipped)
+ mat.rotate(180, Qt::XAxis);
+ mat.translate(-back->width()/2,-back->height()/2);
+
+ if (backTransform)
+ backTransform->setTransform(mat);
+}
+
+QT_END_NAMESPACE
+
+#include "qsgflipable.moc"
diff --git a/src/declarative/items/qsgflipable_p.h b/src/declarative/items/qsgflipable_p.h
new file mode 100644
index 0000000000..02178adca8
--- /dev/null
+++ b/src/declarative/items/qsgflipable_p.h
@@ -0,0 +1,104 @@
+// Commit: ebd4bc73c46c2962742a682b6a391fb68c482aec
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGFLIPABLE_P_H
+#define QSGFLIPABLE_P_H
+
+#include "qsgitem.h"
+
+#include <QtGui/qtransform.h>
+#include <QtGui/qvector3d.h>
+#include <QtCore/qobject.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QSGFlipablePrivate;
+class Q_AUTOTEST_EXPORT QSGFlipable : public QSGItem
+{
+ Q_OBJECT
+
+ Q_ENUMS(Side)
+ Q_PROPERTY(QSGItem *front READ front WRITE setFront NOTIFY frontChanged)
+ Q_PROPERTY(QSGItem *back READ back WRITE setBack NOTIFY backChanged)
+ Q_PROPERTY(Side side READ side NOTIFY sideChanged)
+ //### flipAxis
+ //### flipRotation
+public:
+ QSGFlipable(QSGItem *parent=0);
+ ~QSGFlipable();
+
+ QSGItem *front();
+ void setFront(QSGItem *);
+
+ QSGItem *back();
+ void setBack(QSGItem *);
+
+ enum Side { Front, Back };
+ Side side() const;
+
+Q_SIGNALS:
+ void frontChanged();
+ void backChanged();
+ void sideChanged();
+
+protected:
+ virtual void updatePolish();
+
+private Q_SLOTS:
+ void retransformBack();
+
+private:
+ Q_DISABLE_COPY(QSGFlipable)
+ Q_DECLARE_PRIVATE(QSGFlipable)
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QSGFlipable)
+
+QT_END_HEADER
+
+#endif // QSGFLIPABLE_P_H
diff --git a/src/declarative/items/qsgfocusscope.cpp b/src/declarative/items/qsgfocusscope.cpp
new file mode 100644
index 0000000000..84f19b1671
--- /dev/null
+++ b/src/declarative/items/qsgfocusscope.cpp
@@ -0,0 +1,57 @@
+// Commit: ac5c099cc3c5b8c7eec7a49fdeb8a21037230350
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgfocusscope_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QSGFocusScope::QSGFocusScope(QSGItem *parent)
+: QSGItem(parent)
+{
+ setFlag(ItemIsFocusScope);
+}
+
+QSGFocusScope::~QSGFocusScope()
+{
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/items/qsgfocusscope_p.h b/src/declarative/items/qsgfocusscope_p.h
new file mode 100644
index 0000000000..ceffd9f089
--- /dev/null
+++ b/src/declarative/items/qsgfocusscope_p.h
@@ -0,0 +1,68 @@
+// Commit: ac5c099cc3c5b8c7eec7a49fdeb8a21037230350
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGFOCUSSCOPE_P_H
+#define QSGFOCUSSCOPE_P_H
+
+#include "qsgitem.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class Q_AUTOTEST_EXPORT QSGFocusScope : public QSGItem
+{
+ Q_OBJECT
+public:
+ QSGFocusScope(QSGItem *parent=0);
+ virtual ~QSGFocusScope();
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QSGFocusScope)
+
+QT_END_HEADER
+
+#endif // QSGFOCUSSCOPE_P_H
diff --git a/src/declarative/items/qsggridview.cpp b/src/declarative/items/qsggridview.cpp
new file mode 100644
index 0000000000..b65cd39e8e
--- /dev/null
+++ b/src/declarative/items/qsggridview.cpp
@@ -0,0 +1,2661 @@
+// Commit: 806f031efeda71d3f4d7d2f949b437493e79cf52
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsggridview_p.h"
+#include "qsgvisualitemmodel_p.h"
+#include "qsgflickable_p_p.h"
+
+#include <private/qdeclarativesmoothedanimation_p_p.h>
+#include <private/qlistmodelinterface_p.h>
+
+#include <QtGui/qevent.h>
+#include <QtCore/qmath.h>
+#include <QtCore/qcoreapplication.h>
+#include <math.h>
+
+QT_BEGIN_NAMESPACE
+
+//----------------------------------------------------------------------------
+
+class FxGridItemSG
+{
+public:
+ FxGridItemSG(QSGItem *i, QSGGridView *v) : item(i), view(v) {
+ attached = static_cast<QSGGridViewAttached*>(qmlAttachedPropertiesObject<QSGGridView>(item));
+ if (attached)
+ attached->setView(view);
+ }
+ ~FxGridItemSG() {}
+
+ qreal rowPos() const {
+ qreal rowPos = 0;
+ if (view->flow() == QSGGridView::LeftToRight) {
+ rowPos = item->y();
+ } else {
+ if (view->effectiveLayoutDirection() == Qt::RightToLeft)
+ rowPos = -view->cellWidth()-item->x();
+ else
+ rowPos = item->x();
+ }
+ return rowPos;
+ }
+ qreal colPos() const {
+ qreal colPos = 0;
+ if (view->flow() == QSGGridView::LeftToRight) {
+ if (view->effectiveLayoutDirection() == Qt::RightToLeft) {
+ int colSize = view->cellWidth();
+ int columns = view->width()/colSize;
+ colPos = colSize * (columns-1) - item->x();
+ } else {
+ colPos = item->x();
+ }
+ } else {
+ colPos = item->y();
+ }
+
+ return colPos;
+ }
+ qreal endRowPos() const {
+ if (view->flow() == QSGGridView::LeftToRight) {
+ return item->y() + view->cellHeight() - 1;
+ } else {
+ if (view->effectiveLayoutDirection() == Qt::RightToLeft)
+ return -item->x() - 1;
+ else
+ return item->x() + view->cellWidth() - 1;
+ }
+ }
+ void setPosition(qreal col, qreal row) {
+ if (view->effectiveLayoutDirection() == Qt::RightToLeft) {
+ if (view->flow() == QSGGridView::LeftToRight) {
+ int columns = view->width()/view->cellWidth();
+ item->setPos(QPointF((view->cellWidth() * (columns-1) - col), row));
+ } else {
+ item->setPos(QPointF(-view->cellWidth()-row, col));
+ }
+ } else {
+ if (view->flow() == QSGGridView::LeftToRight)
+ item->setPos(QPointF(col, row));
+ else
+ item->setPos(QPointF(row, col));
+ }
+ }
+ bool contains(qreal x, qreal y) const {
+ return (x >= item->x() && x < item->x() + view->cellWidth() &&
+ y >= item->y() && y < item->y() + view->cellHeight());
+ }
+
+ QSGItem *item;
+ QSGGridView *view;
+ QSGGridViewAttached *attached;
+ int index;
+};
+
+//----------------------------------------------------------------------------
+
+class QSGGridViewPrivate : public QSGFlickablePrivate
+{
+ Q_DECLARE_PUBLIC(QSGGridView)
+
+public:
+ QSGGridViewPrivate()
+ : currentItem(0), layoutDirection(Qt::LeftToRight), flow(QSGGridView::LeftToRight)
+ , visibleIndex(0) , currentIndex(-1)
+ , cellWidth(100), cellHeight(100), columns(1), requestedIndex(-1), itemCount(0)
+ , highlightRangeStart(0), highlightRangeEnd(0)
+ , highlightRange(QSGGridView::NoHighlightRange)
+ , highlightComponent(0), highlight(0), trackedItem(0)
+ , moveReason(Other), buffer(0), highlightXAnimator(0), highlightYAnimator(0)
+ , highlightMoveDuration(150)
+ , footerComponent(0), footer(0), headerComponent(0), header(0)
+ , bufferMode(BufferBefore | BufferAfter), snapMode(QSGGridView::NoSnap)
+ , ownModel(false), wrap(false), autoHighlight(true)
+ , fixCurrentVisibility(false), lazyRelease(false), layoutScheduled(false)
+ , deferredRelease(false), haveHighlightRange(false), currentIndexCleared(false)
+ , highlightRangeStartValid(false), highlightRangeEndValid(false) {}
+
+ void init();
+ void clear();
+ FxGridItemSG *createItem(int modelIndex);
+ void releaseItem(FxGridItemSG *item);
+ void refill(qreal from, qreal to, bool doBuffer=false);
+
+ void updateGrid();
+ void scheduleLayout();
+ void layout();
+ void updateUnrequestedIndexes();
+ void updateUnrequestedPositions();
+ void updateTrackedItem();
+ void createHighlight();
+ void updateHighlight();
+ void updateCurrent(int modelIndex);
+ void updateHeader();
+ void updateFooter();
+ void fixupPosition();
+
+ FxGridItemSG *visibleItem(int modelIndex) const {
+ if (modelIndex >= visibleIndex && modelIndex < visibleIndex + visibleItems.count()) {
+ for (int i = modelIndex - visibleIndex; i < visibleItems.count(); ++i) {
+ FxGridItemSG *item = visibleItems.at(i);
+ if (item->index == modelIndex)
+ return item;
+ }
+ }
+ return 0;
+ }
+
+ bool isRightToLeftTopToBottom() const {
+ Q_Q(const QSGGridView);
+ return flow == QSGGridView::TopToBottom && q->effectiveLayoutDirection() == Qt::RightToLeft;
+ }
+
+ void regenerate() {
+ Q_Q(QSGGridView);
+ if (q->isComponentComplete()) {
+ clear();
+ updateGrid();
+ setPosition(0);
+ q->refill();
+ updateCurrent(currentIndex);
+ }
+ }
+
+ void mirrorChange() {
+ Q_Q(QSGGridView);
+ regenerate();
+ emit q->effectiveLayoutDirectionChanged();
+ }
+
+ qreal position() const {
+ Q_Q(const QSGGridView);
+ return flow == QSGGridView::LeftToRight ? q->contentY() : q->contentX();
+ }
+ void setPosition(qreal pos) {
+ Q_Q(QSGGridView);
+ if (flow == QSGGridView::LeftToRight) {
+ q->QSGFlickable::setContentY(pos);
+ q->QSGFlickable::setContentX(0);
+ } else {
+ if (q->effectiveLayoutDirection() == Qt::LeftToRight)
+ q->QSGFlickable::setContentX(pos);
+ else
+ q->QSGFlickable::setContentX(-pos-size());
+ q->QSGFlickable::setContentY(0);
+ }
+ }
+ int size() const {
+ Q_Q(const QSGGridView);
+ return flow == QSGGridView::LeftToRight ? q->height() : q->width();
+ }
+ qreal originPosition() const {
+ qreal pos = 0;
+ if (!visibleItems.isEmpty())
+ pos = visibleItems.first()->rowPos() - visibleIndex / columns * rowSize();
+ return pos;
+ }
+
+ qreal lastPosition() const {
+ qreal pos = 0;
+ if (model && model->count())
+ pos = rowPosAt(model->count() - 1) + rowSize();
+ return pos;
+ }
+
+ qreal startPosition() const {
+ return isRightToLeftTopToBottom() ? -lastPosition()+1 : originPosition();
+ }
+
+ qreal endPosition() const {
+ return isRightToLeftTopToBottom() ? -originPosition()+1 : lastPosition();
+
+ }
+
+ bool isValid() const {
+ return model && model->count() && model->isValid();
+ }
+
+ int rowSize() const {
+ return flow == QSGGridView::LeftToRight ? cellHeight : cellWidth;
+ }
+ int colSize() const {
+ return flow == QSGGridView::LeftToRight ? cellWidth : cellHeight;
+ }
+
+ qreal colPosAt(int modelIndex) const {
+ if (FxGridItemSG *item = visibleItem(modelIndex))
+ return item->colPos();
+ if (!visibleItems.isEmpty()) {
+ if (modelIndex < visibleIndex) {
+ int count = (visibleIndex - modelIndex) % columns;
+ int col = visibleItems.first()->colPos() / colSize();
+ col = (columns - count + col) % columns;
+ return col * colSize();
+ } else {
+ int count = columns - 1 - (modelIndex - visibleItems.last()->index - 1) % columns;
+ return visibleItems.last()->colPos() - count * colSize();
+ }
+ } else {
+ return (modelIndex % columns) * colSize();
+ }
+ return 0;
+ }
+ qreal rowPosAt(int modelIndex) const {
+ if (FxGridItemSG *item = visibleItem(modelIndex))
+ return item->rowPos();
+ if (!visibleItems.isEmpty()) {
+ if (modelIndex < visibleIndex) {
+ int firstCol = visibleItems.first()->colPos() / colSize();
+ int col = visibleIndex - modelIndex + (columns - firstCol - 1);
+ int rows = col / columns;
+ return visibleItems.first()->rowPos() - rows * rowSize();
+ } else {
+ int count = modelIndex - visibleItems.last()->index;
+ int col = visibleItems.last()->colPos() + count * colSize();
+ int rows = col / (columns * colSize());
+ return visibleItems.last()->rowPos() + rows * rowSize();
+ }
+ } else {
+ qreal pos = (modelIndex / columns) * rowSize();
+ if (header)
+ pos += headerSize();
+ return pos;
+ }
+ return 0;
+ }
+
+ FxGridItemSG *firstVisibleItem() const {
+ const qreal pos = isRightToLeftTopToBottom() ? -position()-size() : position();
+ for (int i = 0; i < visibleItems.count(); ++i) {
+ FxGridItemSG *item = visibleItems.at(i);
+ if (item->index != -1 && item->endRowPos() > pos)
+ return item;
+ }
+ return visibleItems.count() ? visibleItems.first() : 0;
+ }
+
+ int lastVisibleIndex() const {
+ for (int i = 0; i < visibleItems.count(); ++i) {
+ FxGridItemSG *item = visibleItems.at(i);
+ if (item->index != -1)
+ return item->index;
+ }
+ return -1;
+ }
+
+ // Map a model index to visibleItems list index.
+ // These may differ if removed items are still present in the visible list,
+ // e.g. doing a removal animation
+ int mapFromModel(int modelIndex) const {
+ if (modelIndex < visibleIndex || modelIndex >= visibleIndex + visibleItems.count())
+ return -1;
+ for (int i = 0; i < visibleItems.count(); ++i) {
+ FxGridItemSG *listItem = visibleItems.at(i);
+ if (listItem->index == modelIndex)
+ return i + visibleIndex;
+ if (listItem->index > modelIndex)
+ return -1;
+ }
+ return -1; // Not in visibleList
+ }
+
+ qreal snapPosAt(qreal pos) const {
+ Q_Q(const QSGGridView);
+ qreal snapPos = 0;
+ if (!visibleItems.isEmpty()) {
+ pos += rowSize()/2;
+ snapPos = visibleItems.first()->rowPos() - visibleIndex / columns * rowSize();
+ snapPos = pos - fmodf(pos - snapPos, qreal(rowSize()));
+ qreal maxExtent;
+ qreal minExtent;
+ if (isRightToLeftTopToBottom()) {
+ maxExtent = q->minXExtent();
+ minExtent = q->maxXExtent();
+ } else {
+ maxExtent = flow == QSGGridView::LeftToRight ? -q->maxYExtent() : -q->maxXExtent();
+ minExtent = flow == QSGGridView::LeftToRight ? -q->minYExtent() : -q->minXExtent();
+ }
+ if (snapPos > maxExtent)
+ snapPos = maxExtent;
+ if (snapPos < minExtent)
+ snapPos = minExtent;
+ }
+ return snapPos;
+ }
+
+ FxGridItemSG *snapItemAt(qreal pos) {
+ for (int i = 0; i < visibleItems.count(); ++i) {
+ FxGridItemSG *item = visibleItems[i];
+ if (item->index == -1)
+ continue;
+ qreal itemTop = item->rowPos();
+ if (itemTop+rowSize()/2 >= pos && itemTop - rowSize()/2 <= pos)
+ return item;
+ }
+ return 0;
+ }
+
+ int snapIndex() {
+ int index = currentIndex;
+ for (int i = 0; i < visibleItems.count(); ++i) {
+ FxGridItemSG *item = visibleItems[i];
+ if (item->index == -1)
+ continue;
+ qreal itemTop = item->rowPos();
+ if (itemTop >= highlight->rowPos()-rowSize()/2 && itemTop < highlight->rowPos()+rowSize()/2) {
+ index = item->index;
+ if (item->colPos() >= highlight->colPos()-colSize()/2 && item->colPos() < highlight->colPos()+colSize()/2)
+ return item->index;
+ }
+ }
+ return index;
+ }
+
+ qreal headerSize() const {
+ if (!header)
+ return 0.0;
+
+ return flow == QSGGridView::LeftToRight
+ ? header->item->height()
+ : header->item->width();
+ }
+
+
+ virtual void itemGeometryChanged(QSGItem *item, const QRectF &newGeometry, const QRectF &oldGeometry) {
+ Q_Q(const QSGGridView);
+ QSGFlickablePrivate::itemGeometryChanged(item, newGeometry, oldGeometry);
+ if (item == q) {
+ if (newGeometry.height() != oldGeometry.height()
+ || newGeometry.width() != oldGeometry.width()) {
+ if (q->isComponentComplete()) {
+ updateGrid();
+ scheduleLayout();
+ }
+ }
+ } else if ((header && header->item == item) || (footer && footer->item == item)) {
+ if (header)
+ updateHeader();
+ if (footer)
+ updateFooter();
+ }
+ }
+
+ void positionViewAtIndex(int index, int mode);
+ virtual void fixup(AxisData &data, qreal minExtent, qreal maxExtent);
+ virtual void flick(AxisData &data, qreal minExtent, qreal maxExtent, qreal vSize,
+ QDeclarativeTimeLineCallback::Callback fixupCallback, qreal velocity);
+
+ // for debugging only
+ void checkVisible() const {
+ int skip = 0;
+ for (int i = 0; i < visibleItems.count(); ++i) {
+ FxGridItemSG *listItem = visibleItems.at(i);
+ if (listItem->index == -1) {
+ ++skip;
+ } else if (listItem->index != visibleIndex + i - skip) {
+ for (int j = 0; j < visibleItems.count(); j++)
+ qDebug() << " index" << j << "item index" << visibleItems.at(j)->index;
+ qFatal("index %d %d %d", visibleIndex, i, listItem->index);
+ }
+ }
+ }
+
+ QDeclarativeGuard<QSGVisualModel> model;
+ QVariant modelVariant;
+ QList<FxGridItemSG*> visibleItems;
+ QHash<QSGItem*,int> unrequestedItems;
+ FxGridItemSG *currentItem;
+ Qt::LayoutDirection layoutDirection;
+ QSGGridView::Flow flow;
+ int visibleIndex;
+ int currentIndex;
+ int cellWidth;
+ int cellHeight;
+ int columns;
+ int requestedIndex;
+ int itemCount;
+ qreal highlightRangeStart;
+ qreal highlightRangeEnd;
+ QSGGridView::HighlightRangeMode highlightRange;
+ QDeclarativeComponent *highlightComponent;
+ FxGridItemSG *highlight;
+ FxGridItemSG *trackedItem;
+ enum MovementReason { Other, SetIndex, Mouse };
+ MovementReason moveReason;
+ int buffer;
+ QSmoothedAnimation *highlightXAnimator;
+ QSmoothedAnimation *highlightYAnimator;
+ int highlightMoveDuration;
+ QDeclarativeComponent *footerComponent;
+ FxGridItemSG *footer;
+ QDeclarativeComponent *headerComponent;
+ FxGridItemSG *header;
+ enum BufferMode { NoBuffer = 0x00, BufferBefore = 0x01, BufferAfter = 0x02 };
+ int bufferMode;
+ QSGGridView::SnapMode snapMode;
+
+ bool ownModel : 1;
+ bool wrap : 1;
+ bool autoHighlight : 1;
+ bool fixCurrentVisibility : 1;
+ bool lazyRelease : 1;
+ bool layoutScheduled : 1;
+ bool deferredRelease : 1;
+ bool haveHighlightRange : 1;
+ bool currentIndexCleared : 1;
+ bool highlightRangeStartValid : 1;
+ bool highlightRangeEndValid : 1;
+};
+
+void QSGGridViewPrivate::init()
+{
+ Q_Q(QSGGridView);
+ QSGItemPrivate::get(contentItem)->childrenDoNotOverlap = true;
+ QObject::connect(q, SIGNAL(movementEnded()), q, SLOT(animStopped()));
+ q->setFlag(QSGItem::ItemIsFocusScope);
+ q->setFlickableDirection(QSGFlickable::VerticalFlick);
+ addItemChangeListener(this, Geometry);
+}
+
+void QSGGridViewPrivate::clear()
+{
+ for (int i = 0; i < visibleItems.count(); ++i)
+ releaseItem(visibleItems.at(i));
+ visibleItems.clear();
+ visibleIndex = 0;
+ releaseItem(currentItem);
+ currentItem = 0;
+ createHighlight();
+ trackedItem = 0;
+ itemCount = 0;
+}
+
+FxGridItemSG *QSGGridViewPrivate::createItem(int modelIndex)
+{
+ Q_Q(QSGGridView);
+ // create object
+ requestedIndex = modelIndex;
+ FxGridItemSG *listItem = 0;
+ if (QSGItem *item = model->item(modelIndex, false)) {
+ listItem = new FxGridItemSG(item, q);
+ listItem->index = modelIndex;
+ if (model->completePending()) {
+ // complete
+ listItem->item->setZ(1);
+ listItem->item->setParentItem(q->contentItem());
+ model->completeItem();
+ } else {
+ listItem->item->setParentItem(q->contentItem());
+ }
+ unrequestedItems.remove(listItem->item);
+ }
+ requestedIndex = -1;
+ return listItem;
+}
+
+
+void QSGGridViewPrivate::releaseItem(FxGridItemSG *item)
+{
+ Q_Q(QSGGridView);
+ if (!item || !model)
+ return;
+ if (trackedItem == item) {
+ QObject::disconnect(trackedItem->item, SIGNAL(yChanged()), q, SLOT(trackedPositionChanged()));
+ QObject::disconnect(trackedItem->item, SIGNAL(xChanged()), q, SLOT(trackedPositionChanged()));
+ trackedItem = 0;
+ }
+ if (model->release(item->item) == 0) {
+ // item was not destroyed, and we no longer reference it.
+ unrequestedItems.insert(item->item, model->indexOf(item->item, q));
+ }
+ delete item;
+}
+
+void QSGGridViewPrivate::refill(qreal from, qreal to, bool doBuffer)
+{
+ Q_Q(QSGGridView);
+ if (!isValid() || !q->isComponentComplete())
+ return;
+ itemCount = model->count();
+ qreal bufferFrom = from - buffer;
+ qreal bufferTo = to + buffer;
+ qreal fillFrom = from;
+ qreal fillTo = to;
+ if (doBuffer && (bufferMode & BufferAfter))
+ fillTo = bufferTo;
+ if (doBuffer && (bufferMode & BufferBefore))
+ fillFrom = bufferFrom;
+
+ bool changed = false;
+
+ int colPos = colPosAt(visibleIndex);
+ int rowPos = rowPosAt(visibleIndex);
+ int modelIndex = visibleIndex;
+ if (visibleItems.count()) {
+ rowPos = visibleItems.last()->rowPos();
+ colPos = visibleItems.last()->colPos() + colSize();
+ if (colPos > colSize() * (columns-1)) {
+ colPos = 0;
+ rowPos += rowSize();
+ }
+ int i = visibleItems.count() - 1;
+ while (i > 0 && visibleItems.at(i)->index == -1)
+ --i;
+ modelIndex = visibleItems.at(i)->index + 1;
+ }
+
+ if (visibleItems.count() && (fillFrom > rowPos + rowSize()*2
+ || fillTo < rowPosAt(visibleIndex) - rowSize())) {
+ // We've jumped more than a page. Estimate which items are now
+ // visible and fill from there.
+ int count = (fillFrom - (rowPos + rowSize())) / (rowSize()) * columns;
+ for (int i = 0; i < visibleItems.count(); ++i)
+ releaseItem(visibleItems.at(i));
+ visibleItems.clear();
+ modelIndex += count;
+ if (modelIndex >= model->count())
+ modelIndex = model->count() - 1;
+ else if (modelIndex < 0)
+ modelIndex = 0;
+ modelIndex = modelIndex / columns * columns;
+ visibleIndex = modelIndex;
+ colPos = colPosAt(visibleIndex);
+ rowPos = rowPosAt(visibleIndex);
+ }
+
+ int colNum = colPos / colSize();
+
+ FxGridItemSG *item = 0;
+
+ // Item creation and release is staggered in order to avoid
+ // creating/releasing multiple items in one frame
+ // while flicking (as much as possible).
+ while (modelIndex < model->count() && rowPos <= fillTo + rowSize()*(columns - colNum)/(columns+1)) {
+// qDebug() << "refill: append item" << modelIndex;
+ if (!(item = createItem(modelIndex)))
+ break;
+ item->setPosition(colPos, rowPos);
+ visibleItems.append(item);
+ colPos += colSize();
+ colNum++;
+ if (colPos > colSize() * (columns-1)) {
+ colPos = 0;
+ colNum = 0;
+ rowPos += rowSize();
+ }
+ ++modelIndex;
+ changed = true;
+ if (doBuffer) // never buffer more than one item per frame
+ break;
+ }
+
+ if (visibleItems.count()) {
+ rowPos = visibleItems.first()->rowPos();
+ colPos = visibleItems.first()->colPos() - colSize();
+ if (colPos < 0) {
+ colPos = colSize() * (columns - 1);
+ rowPos -= rowSize();
+ }
+ }
+ colNum = colPos / colSize();
+ while (visibleIndex > 0 && rowPos + rowSize() - 1 >= fillFrom - rowSize()*(colNum+1)/(columns+1)){
+// qDebug() << "refill: prepend item" << visibleIndex-1 << "top pos" << rowPos << colPos;
+ if (!(item = createItem(visibleIndex-1)))
+ break;
+ --visibleIndex;
+ item->setPosition(colPos, rowPos);
+ visibleItems.prepend(item);
+ colPos -= colSize();
+ colNum--;
+ if (colPos < 0) {
+ colPos = colSize() * (columns - 1);
+ colNum = columns-1;
+ rowPos -= rowSize();
+ }
+ changed = true;
+ if (doBuffer) // never buffer more than one item per frame
+ break;
+ }
+
+ if (!lazyRelease || !changed || deferredRelease) { // avoid destroying items in the same frame that we create
+ while (visibleItems.count() > 1
+ && (item = visibleItems.first())
+ && item->rowPos()+rowSize()-1 < bufferFrom - rowSize()*(item->colPos()/colSize()+1)/(columns+1)) {
+ if (item->attached->delayRemove())
+ break;
+// qDebug() << "refill: remove first" << visibleIndex << "top end pos" << item->endRowPos();
+ if (item->index != -1)
+ visibleIndex++;
+ visibleItems.removeFirst();
+ releaseItem(item);
+ changed = true;
+ }
+ while (visibleItems.count() > 1
+ && (item = visibleItems.last())
+ && item->rowPos() > bufferTo + rowSize()*(columns - item->colPos()/colSize())/(columns+1)) {
+ if (item->attached->delayRemove())
+ break;
+// qDebug() << "refill: remove last" << visibleIndex+visibleItems.count()-1;
+ visibleItems.removeLast();
+ releaseItem(item);
+ changed = true;
+ }
+ deferredRelease = false;
+ } else {
+ deferredRelease = true;
+ }
+ if (changed) {
+ if (header)
+ updateHeader();
+ if (footer)
+ updateFooter();
+ if (flow == QSGGridView::LeftToRight)
+ q->setContentHeight(endPosition() - startPosition());
+ else
+ q->setContentWidth(endPosition() - startPosition());
+ } else if (!doBuffer && buffer && bufferMode != NoBuffer) {
+ refill(from, to, true);
+ }
+ lazyRelease = false;
+}
+
+void QSGGridViewPrivate::updateGrid()
+{
+ Q_Q(QSGGridView);
+ columns = (int)qMax((flow == QSGGridView::LeftToRight ? q->width() : q->height()) / colSize(), qreal(1.));
+ if (isValid()) {
+ if (flow == QSGGridView::LeftToRight)
+ q->setContentHeight(endPosition() - startPosition());
+ else
+ q->setContentWidth(lastPosition() - originPosition());
+ }
+}
+
+void QSGGridViewPrivate::scheduleLayout()
+{
+ Q_Q(QSGGridView);
+ if (!layoutScheduled) {
+ layoutScheduled = true;
+ q->polish();
+ }
+}
+
+void QSGGridViewPrivate::layout()
+{
+ Q_Q(QSGGridView);
+ layoutScheduled = false;
+ if (!isValid() && !visibleItems.count()) {
+ clear();
+ return;
+ }
+ if (visibleItems.count()) {
+ qreal rowPos = visibleItems.first()->rowPos();
+ qreal colPos = visibleItems.first()->colPos();
+ int col = visibleIndex % columns;
+ if (colPos != col * colSize()) {
+ colPos = col * colSize();
+ visibleItems.first()->setPosition(colPos, rowPos);
+ }
+ for (int i = 1; i < visibleItems.count(); ++i) {
+ FxGridItemSG *item = visibleItems.at(i);
+ colPos += colSize();
+ if (colPos > colSize() * (columns-1)) {
+ colPos = 0;
+ rowPos += rowSize();
+ }
+ item->setPosition(colPos, rowPos);
+ }
+ }
+ if (header)
+ updateHeader();
+ if (footer)
+ updateFooter();
+ q->refill();
+ updateHighlight();
+ moveReason = Other;
+ if (flow == QSGGridView::LeftToRight) {
+ q->setContentHeight(endPosition() - startPosition());
+ fixupY();
+ } else {
+ q->setContentWidth(endPosition() - startPosition());
+ fixupX();
+ }
+ updateUnrequestedPositions();
+}
+
+void QSGGridViewPrivate::updateUnrequestedIndexes()
+{
+ Q_Q(QSGGridView);
+ QHash<QSGItem*,int>::iterator it;
+ for (it = unrequestedItems.begin(); it != unrequestedItems.end(); ++it)
+ *it = model->indexOf(it.key(), q);
+}
+
+void QSGGridViewPrivate::updateUnrequestedPositions()
+{
+ QHash<QSGItem*,int>::const_iterator it;
+ for (it = unrequestedItems.begin(); it != unrequestedItems.end(); ++it) {
+ QSGItem *item = it.key();
+ if (flow == QSGGridView::LeftToRight) {
+ item->setPos(QPointF(colPosAt(*it), rowPosAt(*it)));
+ } else {
+ if (isRightToLeftTopToBottom())
+ item->setPos(QPointF(-rowPosAt(*it)-item->width(), colPosAt(*it)));
+ else
+ item->setPos(QPointF(rowPosAt(*it), colPosAt(*it)));
+ }
+ }
+}
+
+void QSGGridViewPrivate::updateTrackedItem()
+{
+ Q_Q(QSGGridView);
+ FxGridItemSG *item = currentItem;
+ if (highlight)
+ item = highlight;
+
+ if (trackedItem && item != trackedItem) {
+ QObject::disconnect(trackedItem->item, SIGNAL(yChanged()), q, SLOT(trackedPositionChanged()));
+ QObject::disconnect(trackedItem->item, SIGNAL(xChanged()), q, SLOT(trackedPositionChanged()));
+ trackedItem = 0;
+ }
+
+ if (!trackedItem && item) {
+ trackedItem = item;
+ QObject::connect(trackedItem->item, SIGNAL(yChanged()), q, SLOT(trackedPositionChanged()));
+ QObject::connect(trackedItem->item, SIGNAL(xChanged()), q, SLOT(trackedPositionChanged()));
+ }
+ if (trackedItem)
+ q->trackedPositionChanged();
+}
+
+void QSGGridViewPrivate::createHighlight()
+{
+ Q_Q(QSGGridView);
+ bool changed = false;
+ if (highlight) {
+ if (trackedItem == highlight)
+ trackedItem = 0;
+ highlight->item->setParentItem(0);
+ highlight->item->deleteLater();
+ delete highlight;
+ highlight = 0;
+ delete highlightXAnimator;
+ delete highlightYAnimator;
+ highlightXAnimator = 0;
+ highlightYAnimator = 0;
+ changed = true;
+ }
+
+ if (currentItem) {
+ QSGItem *item = 0;
+ if (highlightComponent) {
+ QDeclarativeContext *highlightContext = new QDeclarativeContext(qmlContext(q));
+ QObject *nobj = highlightComponent->create(highlightContext);
+ if (nobj) {
+ QDeclarative_setParent_noEvent(highlightContext, nobj);
+ item = qobject_cast<QSGItem *>(nobj);
+ if (!item)
+ delete nobj;
+ } else {
+ delete highlightContext;
+ }
+ } else {
+ item = new QSGItem;
+ QDeclarative_setParent_noEvent(item, q->contentItem());
+ item->setParentItem(q->contentItem());
+ }
+ if (item) {
+ QDeclarative_setParent_noEvent(item, q->contentItem());
+ item->setParentItem(q->contentItem());
+ highlight = new FxGridItemSG(item, q);
+ if (currentItem && autoHighlight)
+ highlight->setPosition(currentItem->colPos(), currentItem->rowPos());
+ highlightXAnimator = new QSmoothedAnimation(q);
+ highlightXAnimator->target = QDeclarativeProperty(highlight->item, QLatin1String("x"));
+ highlightXAnimator->userDuration = highlightMoveDuration;
+ highlightYAnimator = new QSmoothedAnimation(q);
+ highlightYAnimator->target = QDeclarativeProperty(highlight->item, QLatin1String("y"));
+ highlightYAnimator->userDuration = highlightMoveDuration;
+ if (autoHighlight) {
+ highlightXAnimator->restart();
+ highlightYAnimator->restart();
+ }
+ changed = true;
+ }
+ }
+ if (changed)
+ emit q->highlightItemChanged();
+}
+
+void QSGGridViewPrivate::updateHighlight()
+{
+ if ((!currentItem && highlight) || (currentItem && !highlight))
+ createHighlight();
+ if (currentItem && autoHighlight && highlight && !movingHorizontally && !movingVertically) {
+ // auto-update highlight
+ highlightXAnimator->to = currentItem->item->x();
+ highlightYAnimator->to = currentItem->item->y();
+ highlight->item->setWidth(currentItem->item->width());
+ highlight->item->setHeight(currentItem->item->height());
+ highlightXAnimator->restart();
+ highlightYAnimator->restart();
+ }
+ updateTrackedItem();
+}
+
+void QSGGridViewPrivate::updateCurrent(int modelIndex)
+{
+ Q_Q(QSGGridView);
+ if (!q->isComponentComplete() || !isValid() || modelIndex < 0 || modelIndex >= model->count()) {
+ if (currentItem) {
+ currentItem->attached->setIsCurrentItem(false);
+ releaseItem(currentItem);
+ currentItem = 0;
+ currentIndex = modelIndex;
+ emit q->currentIndexChanged();
+ updateHighlight();
+ } else if (currentIndex != modelIndex) {
+ currentIndex = modelIndex;
+ emit q->currentIndexChanged();
+ }
+ return;
+ }
+
+ if (currentItem && currentIndex == modelIndex) {
+ updateHighlight();
+ return;
+ }
+
+ FxGridItemSG *oldCurrentItem = currentItem;
+ currentIndex = modelIndex;
+ currentItem = createItem(modelIndex);
+ fixCurrentVisibility = true;
+ if (oldCurrentItem && (!currentItem || oldCurrentItem->item != currentItem->item))
+ oldCurrentItem->attached->setIsCurrentItem(false);
+ if (currentItem) {
+ currentItem->setPosition(colPosAt(modelIndex), rowPosAt(modelIndex));
+ currentItem->item->setFocus(true);
+ currentItem->attached->setIsCurrentItem(true);
+ }
+ updateHighlight();
+ emit q->currentIndexChanged();
+ releaseItem(oldCurrentItem);
+}
+
+void QSGGridViewPrivate::updateFooter()
+{
+ Q_Q(QSGGridView);
+ if (!footer && footerComponent) {
+ QSGItem *item = 0;
+ QDeclarativeContext *context = new QDeclarativeContext(qmlContext(q));
+ QObject *nobj = footerComponent->create(context);
+ if (nobj) {
+ QDeclarative_setParent_noEvent(context, nobj);
+ item = qobject_cast<QSGItem *>(nobj);
+ if (!item)
+ delete nobj;
+ } else {
+ delete context;
+ }
+ if (item) {
+ QDeclarative_setParent_noEvent(item, q->contentItem());
+ item->setParentItem(q->contentItem());
+ item->setZ(1);
+ QSGItemPrivate *itemPrivate = QSGItemPrivate::get(item);
+ itemPrivate->addItemChangeListener(this, QSGItemPrivate::Geometry);
+ footer = new FxGridItemSG(item, q);
+ }
+ }
+ if (footer) {
+ qreal colOffset = 0;
+ qreal rowOffset;
+ if (isRightToLeftTopToBottom()) {
+ rowOffset = footer->item->width()-cellWidth;
+ } else {
+ rowOffset = 0;
+ if (q->effectiveLayoutDirection() == Qt::RightToLeft)
+ colOffset = footer->item->width()-cellWidth;
+ }
+ if (visibleItems.count()) {
+ qreal endPos = lastPosition();
+ if (lastVisibleIndex() == model->count()-1) {
+ footer->setPosition(colOffset, endPos + rowOffset);
+ } else {
+ qreal visiblePos = isRightToLeftTopToBottom() ? -position() : position() + size();
+ if (endPos <= visiblePos || footer->endRowPos() < endPos + rowOffset)
+ footer->setPosition(colOffset, endPos + rowOffset);
+ }
+ } else {
+ qreal endPos = 0;
+ if (header) {
+ endPos += (flow == QSGGridView::LeftToRight) ? header->item->height() : header->item->width();
+ }
+ footer->setPosition(colOffset, endPos);
+ }
+ }
+}
+
+void QSGGridViewPrivate::updateHeader()
+{
+ Q_Q(QSGGridView);
+ if (!header && headerComponent) {
+ QSGItem *item = 0;
+ QDeclarativeContext *context = new QDeclarativeContext(qmlContext(q));
+ QObject *nobj = headerComponent->create(context);
+ if (nobj) {
+ QDeclarative_setParent_noEvent(context, nobj);
+ item = qobject_cast<QSGItem *>(nobj);
+ if (!item)
+ delete nobj;
+ } else {
+ delete context;
+ }
+ if (item) {
+ QDeclarative_setParent_noEvent(item, q->contentItem());
+ item->setParentItem(q->contentItem());
+ item->setZ(1);
+ QSGItemPrivate *itemPrivate = QSGItemPrivate::get(item);
+ itemPrivate->addItemChangeListener(this, QSGItemPrivate::Geometry);
+ header = new FxGridItemSG(item, q);
+ }
+ }
+ if (header) {
+ qreal colOffset = 0;
+ qreal rowOffset;
+ if (isRightToLeftTopToBottom()) {
+ rowOffset = -cellWidth;
+ } else {
+ rowOffset = -headerSize();
+ if (q->effectiveLayoutDirection() == Qt::RightToLeft)
+ colOffset = header->item->width()-cellWidth;
+ }
+ if (visibleItems.count()) {
+ qreal startPos = originPosition();
+ if (visibleIndex == 0) {
+ header->setPosition(colOffset, startPos + rowOffset);
+ } else {
+ qreal tempPos = isRightToLeftTopToBottom() ? -position()-size() : position();
+ qreal headerPos = isRightToLeftTopToBottom() ? header->rowPos() + cellWidth - headerSize() : header->rowPos();
+ if (tempPos <= startPos || headerPos > startPos + rowOffset)
+ header->setPosition(colOffset, startPos + rowOffset);
+ }
+ } else {
+ header->setPosition(colOffset, 0);
+ }
+ }
+}
+
+void QSGGridViewPrivate::fixupPosition()
+{
+ moveReason = Other;
+ if (flow == QSGGridView::LeftToRight)
+ fixupY();
+ else
+ fixupX();
+}
+
+void QSGGridViewPrivate::fixup(AxisData &data, qreal minExtent, qreal maxExtent)
+{
+ if ((flow == QSGGridView::TopToBottom && &data == &vData)
+ || (flow == QSGGridView::LeftToRight && &data == &hData))
+ return;
+
+ fixupMode = moveReason == Mouse ? fixupMode : Immediate;
+
+ qreal highlightStart;
+ qreal highlightEnd;
+ qreal viewPos;
+ if (isRightToLeftTopToBottom()) {
+ // Handle Right-To-Left exceptions
+ viewPos = -position()-size();
+ highlightStart = highlightRangeStartValid ? size()-highlightRangeEnd : highlightRangeStart;
+ highlightEnd = highlightRangeEndValid ? size()-highlightRangeStart : highlightRangeEnd;
+ } else {
+ viewPos = position();
+ highlightStart = highlightRangeStart;
+ highlightEnd = highlightRangeEnd;
+ }
+
+ if (snapMode != QSGGridView::NoSnap) {
+ qreal tempPosition = isRightToLeftTopToBottom() ? -position()-size() : position();
+ FxGridItemSG *topItem = snapItemAt(tempPosition+highlightStart);
+ FxGridItemSG *bottomItem = snapItemAt(tempPosition+highlightEnd);
+ qreal pos;
+ if (topItem && bottomItem && haveHighlightRange && highlightRange == QSGGridView::StrictlyEnforceRange) {
+ qreal topPos = qMin(topItem->rowPos() - highlightStart, -maxExtent);
+ qreal bottomPos = qMax(bottomItem->rowPos() - highlightEnd, -minExtent);
+ pos = qAbs(data.move + topPos) < qAbs(data.move + bottomPos) ? topPos : bottomPos;
+ } else if (topItem) {
+ qreal headerPos = 0;
+ if (header)
+ headerPos = isRightToLeftTopToBottom() ? header->rowPos() + cellWidth - headerSize() : header->rowPos();
+ if (topItem->index == 0 && header && tempPosition+highlightStart < headerPos+headerSize()/2) {
+ pos = isRightToLeftTopToBottom() ? - headerPos + highlightStart - size() : headerPos - highlightStart;
+ } else {
+ if (isRightToLeftTopToBottom())
+ pos = qMax(qMin(-topItem->rowPos() + highlightStart - size(), -maxExtent), -minExtent);
+ else
+ pos = qMax(qMin(topItem->rowPos() - highlightStart, -maxExtent), -minExtent);
+ }
+ } else if (bottomItem) {
+ if (isRightToLeftTopToBottom())
+ pos = qMax(qMin(-bottomItem->rowPos() + highlightStart - size(), -maxExtent), -minExtent);
+ else
+ pos = qMax(qMin(bottomItem->rowPos() - highlightStart, -maxExtent), -minExtent);
+ } else {
+ QSGFlickablePrivate::fixup(data, minExtent, maxExtent);
+ return;
+ }
+ if (currentItem && haveHighlightRange && highlightRange == QSGGridView::StrictlyEnforceRange) {
+ updateHighlight();
+ qreal currPos = currentItem->rowPos();
+ if (isRightToLeftTopToBottom())
+ pos = -pos-size(); // Transform Pos if required
+ if (pos < currPos + rowSize() - highlightEnd)
+ pos = currPos + rowSize() - highlightEnd;
+ if (pos > currPos - highlightStart)
+ pos = currPos - highlightStart;
+ if (isRightToLeftTopToBottom())
+ pos = -pos-size(); // Untransform
+ }
+
+ qreal dist = qAbs(data.move + pos);
+ if (dist > 0) {
+ timeline.reset(data.move);
+ if (fixupMode != Immediate) {
+ timeline.move(data.move, -pos, QEasingCurve(QEasingCurve::InOutQuad), fixupDuration/2);
+ data.fixingUp = true;
+ } else {
+ timeline.set(data.move, -pos);
+ }
+ vTime = timeline.time();
+ }
+ } else if (haveHighlightRange && highlightRange == QSGGridView::StrictlyEnforceRange) {
+ if (currentItem) {
+ updateHighlight();
+ qreal pos = currentItem->rowPos();
+ if (viewPos < pos + rowSize() - highlightEnd)
+ viewPos = pos + rowSize() - highlightEnd;
+ if (viewPos > pos - highlightStart)
+ viewPos = pos - highlightStart;
+ if (isRightToLeftTopToBottom())
+ viewPos = -viewPos-size();
+ timeline.reset(data.move);
+ if (viewPos != position()) {
+ if (fixupMode != Immediate) {
+ timeline.move(data.move, -viewPos, QEasingCurve(QEasingCurve::InOutQuad), fixupDuration/2);
+ data.fixingUp = true;
+ } else {
+ timeline.set(data.move, -viewPos);
+ }
+ }
+ vTime = timeline.time();
+ }
+ } else {
+ QSGFlickablePrivate::fixup(data, minExtent, maxExtent);
+ }
+ data.inOvershoot = false;
+ fixupMode = Normal;
+}
+
+void QSGGridViewPrivate::flick(AxisData &data, qreal minExtent, qreal maxExtent, qreal vSize,
+ QDeclarativeTimeLineCallback::Callback fixupCallback, qreal velocity)
+{
+ Q_Q(QSGGridView);
+ data.fixingUp = false;
+ moveReason = Mouse;
+ if ((!haveHighlightRange || highlightRange != QSGGridView::StrictlyEnforceRange)
+ && snapMode == QSGGridView::NoSnap) {
+ QSGFlickablePrivate::flick(data, minExtent, maxExtent, vSize, fixupCallback, velocity);
+ return;
+ }
+ qreal maxDistance = 0;
+ qreal dataValue = isRightToLeftTopToBottom() ? -data.move.value()+size() : data.move.value();
+ // -ve velocity means list is moving up/left
+ if (velocity > 0) {
+ if (data.move.value() < minExtent) {
+ if (snapMode == QSGGridView::SnapOneRow) {
+ if (FxGridItemSG *item = firstVisibleItem())
+ maxDistance = qAbs(item->rowPos() + dataValue);
+ } else {
+ maxDistance = qAbs(minExtent - data.move.value());
+ }
+ }
+ if (snapMode == QSGGridView::NoSnap && highlightRange != QSGGridView::StrictlyEnforceRange)
+ data.flickTarget = minExtent;
+ } else {
+ if (data.move.value() > maxExtent) {
+ if (snapMode == QSGGridView::SnapOneRow) {
+ qreal pos = snapPosAt(-dataValue) + (isRightToLeftTopToBottom() ? 0 : rowSize());
+ maxDistance = qAbs(pos + dataValue);
+ } else {
+ maxDistance = qAbs(maxExtent - data.move.value());
+ }
+ }
+ if (snapMode == QSGGridView::NoSnap && highlightRange != QSGGridView::StrictlyEnforceRange)
+ data.flickTarget = maxExtent;
+ }
+ bool overShoot = boundsBehavior == QSGFlickable::DragAndOvershootBounds;
+ qreal highlightStart = isRightToLeftTopToBottom() && highlightRangeStartValid ? size()-highlightRangeEnd : highlightRangeStart;
+ if (maxDistance > 0 || overShoot) {
+ // This mode requires the grid to stop exactly on a row boundary.
+ qreal v = velocity;
+ if (maxVelocity != -1 && maxVelocity < qAbs(v)) {
+ if (v < 0)
+ v = -maxVelocity;
+ else
+ v = maxVelocity;
+ }
+ qreal accel = deceleration;
+ qreal v2 = v * v;
+ qreal overshootDist = 0.0;
+ if ((maxDistance > 0.0 && v2 / (2.0f * maxDistance) < accel) || snapMode == QSGGridView::SnapOneRow) {
+ // + rowSize()/4 to encourage moving at least one item in the flick direction
+ qreal dist = v2 / (accel * 2.0) + rowSize()/4;
+ dist = qMin(dist, maxDistance);
+ if (v > 0)
+ dist = -dist;
+ qreal distTemp = isRightToLeftTopToBottom() ? -dist : dist;
+ data.flickTarget = -snapPosAt(-(dataValue - highlightStart) + distTemp) + highlightStart;
+ data.flickTarget = isRightToLeftTopToBottom() ? -data.flickTarget+size() : data.flickTarget;
+ qreal adjDist = -data.flickTarget + data.move.value();
+ if (qAbs(adjDist) > qAbs(dist)) {
+ // Prevent painfully slow flicking - adjust velocity to suit flickDeceleration
+ qreal adjv2 = accel * 2.0f * qAbs(adjDist);
+ if (adjv2 > v2) {
+ v2 = adjv2;
+ v = qSqrt(v2);
+ if (dist > 0)
+ v = -v;
+ }
+ }
+ dist = adjDist;
+ accel = v2 / (2.0f * qAbs(dist));
+ } else {
+ data.flickTarget = velocity > 0 ? minExtent : maxExtent;
+ overshootDist = overShoot ? overShootDistance(vSize) : 0;
+ }
+ timeline.reset(data.move);
+ timeline.accel(data.move, v, accel, maxDistance + overshootDist);
+ timeline.callback(QDeclarativeTimeLineCallback(&data.move, fixupCallback, this));
+ if (!flickingHorizontally && q->xflick()) {
+ flickingHorizontally = true;
+ emit q->flickingChanged();
+ emit q->flickingHorizontallyChanged();
+ emit q->flickStarted();
+ }
+ if (!flickingVertically && q->yflick()) {
+ flickingVertically = true;
+ emit q->flickingChanged();
+ emit q->flickingVerticallyChanged();
+ emit q->flickStarted();
+ }
+ } else {
+ timeline.reset(data.move);
+ fixup(data, minExtent, maxExtent);
+ }
+}
+
+
+//----------------------------------------------------------------------------
+
+QSGGridView::QSGGridView(QSGItem *parent)
+ : QSGFlickable(*(new QSGGridViewPrivate), parent)
+{
+ Q_D(QSGGridView);
+ d->init();
+}
+
+QSGGridView::~QSGGridView()
+{
+ Q_D(QSGGridView);
+ d->clear();
+ if (d->ownModel)
+ delete d->model;
+ delete d->header;
+ delete d->footer;
+}
+
+// For internal use
+int QSGGridView::modelCount() const
+{
+ Q_D(const QSGGridView);
+ return d->model->count();
+}
+
+QVariant QSGGridView::model() const
+{
+ Q_D(const QSGGridView);
+ return d->modelVariant;
+}
+
+void QSGGridView::setModel(const QVariant &model)
+{
+ Q_D(QSGGridView);
+ if (d->modelVariant == model)
+ return;
+ if (d->model) {
+ disconnect(d->model, SIGNAL(itemsInserted(int,int)), this, SLOT(itemsInserted(int,int)));
+ disconnect(d->model, SIGNAL(itemsRemoved(int,int)), this, SLOT(itemsRemoved(int,int)));
+ disconnect(d->model, SIGNAL(itemsMoved(int,int,int)), this, SLOT(itemsMoved(int,int,int)));
+ disconnect(d->model, SIGNAL(modelReset()), this, SLOT(modelReset()));
+ disconnect(d->model, SIGNAL(createdItem(int,QSGItem*)), this, SLOT(createdItem(int,QSGItem*)));
+ disconnect(d->model, SIGNAL(destroyingItem(QSGItem*)), this, SLOT(destroyingItem(QSGItem*)));
+ }
+ d->clear();
+ d->modelVariant = model;
+ QObject *object = qvariant_cast<QObject*>(model);
+ QSGVisualModel *vim = 0;
+ if (object && (vim = qobject_cast<QSGVisualModel *>(object))) {
+ if (d->ownModel) {
+ delete d->model;
+ d->ownModel = false;
+ }
+ d->model = vim;
+ } else {
+ if (!d->ownModel) {
+ d->model = new QSGVisualDataModel(qmlContext(this), this);
+ d->ownModel = true;
+ }
+ if (QSGVisualDataModel *dataModel = qobject_cast<QSGVisualDataModel*>(d->model))
+ dataModel->setModel(model);
+ }
+ if (d->model) {
+ d->bufferMode = QSGGridViewPrivate::BufferBefore | QSGGridViewPrivate::BufferAfter;
+ if (isComponentComplete()) {
+ refill();
+ if ((d->currentIndex >= d->model->count() || d->currentIndex < 0) && !d->currentIndexCleared) {
+ setCurrentIndex(0);
+ } else {
+ d->moveReason = QSGGridViewPrivate::SetIndex;
+ d->updateCurrent(d->currentIndex);
+ if (d->highlight && d->currentItem) {
+ if (d->autoHighlight)
+ d->highlight->setPosition(d->currentItem->colPos(), d->currentItem->rowPos());
+ d->updateTrackedItem();
+ }
+ d->moveReason = QSGGridViewPrivate::Other;
+ }
+ }
+ connect(d->model, SIGNAL(itemsInserted(int,int)), this, SLOT(itemsInserted(int,int)));
+ connect(d->model, SIGNAL(itemsRemoved(int,int)), this, SLOT(itemsRemoved(int,int)));
+ connect(d->model, SIGNAL(itemsMoved(int,int,int)), this, SLOT(itemsMoved(int,int,int)));
+ connect(d->model, SIGNAL(modelReset()), this, SLOT(modelReset()));
+ connect(d->model, SIGNAL(createdItem(int,QSGItem*)), this, SLOT(createdItem(int,QSGItem*)));
+ connect(d->model, SIGNAL(destroyingItem(QSGItem*)), this, SLOT(destroyingItem(QSGItem*)));
+ emit countChanged();
+ }
+ emit modelChanged();
+}
+
+QDeclarativeComponent *QSGGridView::delegate() const
+{
+ Q_D(const QSGGridView);
+ if (d->model) {
+ if (QSGVisualDataModel *dataModel = qobject_cast<QSGVisualDataModel*>(d->model))
+ return dataModel->delegate();
+ }
+
+ return 0;
+}
+
+void QSGGridView::setDelegate(QDeclarativeComponent *delegate)
+{
+ Q_D(QSGGridView);
+ if (delegate == this->delegate())
+ return;
+
+ if (!d->ownModel) {
+ d->model = new QSGVisualDataModel(qmlContext(this));
+ d->ownModel = true;
+ }
+ if (QSGVisualDataModel *dataModel = qobject_cast<QSGVisualDataModel*>(d->model)) {
+ int oldCount = dataModel->count();
+ dataModel->setDelegate(delegate);
+ if (isComponentComplete()) {
+ for (int i = 0; i < d->visibleItems.count(); ++i)
+ d->releaseItem(d->visibleItems.at(i));
+ d->visibleItems.clear();
+ d->releaseItem(d->currentItem);
+ d->currentItem = 0;
+ refill();
+ d->moveReason = QSGGridViewPrivate::SetIndex;
+ d->updateCurrent(d->currentIndex);
+ if (d->highlight && d->currentItem) {
+ if (d->autoHighlight)
+ d->highlight->setPosition(d->currentItem->colPos(), d->currentItem->rowPos());
+ d->updateTrackedItem();
+ }
+ d->moveReason = QSGGridViewPrivate::Other;
+ }
+ if (oldCount != dataModel->count())
+ emit countChanged();
+ emit delegateChanged();
+ }
+}
+
+int QSGGridView::currentIndex() const
+{
+ Q_D(const QSGGridView);
+ return d->currentIndex;
+}
+
+void QSGGridView::setCurrentIndex(int index)
+{
+ Q_D(QSGGridView);
+ if (d->requestedIndex >= 0) // currently creating item
+ return;
+ d->currentIndexCleared = (index == -1);
+ if (index == d->currentIndex)
+ return;
+ if (isComponentComplete() && d->isValid()) {
+ d->moveReason = QSGGridViewPrivate::SetIndex;
+ d->updateCurrent(index);
+ } else {
+ d->currentIndex = index;
+ emit currentIndexChanged();
+ }
+}
+
+QSGItem *QSGGridView::currentItem()
+{
+ Q_D(QSGGridView);
+ if (!d->currentItem)
+ return 0;
+ return d->currentItem->item;
+}
+
+QSGItem *QSGGridView::highlightItem()
+{
+ Q_D(QSGGridView);
+ if (!d->highlight)
+ return 0;
+ return d->highlight->item;
+}
+
+int QSGGridView::count() const
+{
+ Q_D(const QSGGridView);
+ if (d->model)
+ return d->model->count();
+ return 0;
+}
+
+QDeclarativeComponent *QSGGridView::highlight() const
+{
+ Q_D(const QSGGridView);
+ return d->highlightComponent;
+}
+
+void QSGGridView::setHighlight(QDeclarativeComponent *highlight)
+{
+ Q_D(QSGGridView);
+ if (highlight != d->highlightComponent) {
+ d->highlightComponent = highlight;
+ d->updateCurrent(d->currentIndex);
+ emit highlightChanged();
+ }
+}
+
+bool QSGGridView::highlightFollowsCurrentItem() const
+{
+ Q_D(const QSGGridView);
+ return d->autoHighlight;
+}
+
+void QSGGridView::setHighlightFollowsCurrentItem(bool autoHighlight)
+{
+ Q_D(QSGGridView);
+ if (d->autoHighlight != autoHighlight) {
+ d->autoHighlight = autoHighlight;
+ if (autoHighlight) {
+ d->updateHighlight();
+ } else if (d->highlightXAnimator) {
+ d->highlightXAnimator->stop();
+ d->highlightYAnimator->stop();
+ }
+ }
+}
+
+int QSGGridView::highlightMoveDuration() const
+{
+ Q_D(const QSGGridView);
+ return d->highlightMoveDuration;
+}
+
+void QSGGridView::setHighlightMoveDuration(int duration)
+{
+ Q_D(QSGGridView);
+ if (d->highlightMoveDuration != duration) {
+ d->highlightMoveDuration = duration;
+ if (d->highlightYAnimator) {
+ d->highlightXAnimator->userDuration = d->highlightMoveDuration;
+ d->highlightYAnimator->userDuration = d->highlightMoveDuration;
+ }
+ emit highlightMoveDurationChanged();
+ }
+}
+
+qreal QSGGridView::preferredHighlightBegin() const
+{
+ Q_D(const QSGGridView);
+ return d->highlightRangeStart;
+}
+
+void QSGGridView::setPreferredHighlightBegin(qreal start)
+{
+ Q_D(QSGGridView);
+ d->highlightRangeStartValid = true;
+ if (d->highlightRangeStart == start)
+ return;
+ d->highlightRangeStart = start;
+ d->haveHighlightRange = d->highlightRange != NoHighlightRange && d->highlightRangeStart <= d->highlightRangeEnd;
+ emit preferredHighlightBeginChanged();
+}
+
+void QSGGridView::resetPreferredHighlightBegin()
+{
+ Q_D(QSGGridView);
+ d->highlightRangeStartValid = false;
+ if (d->highlightRangeStart == 0)
+ return;
+ d->highlightRangeStart = 0;
+ emit preferredHighlightBeginChanged();
+}
+
+qreal QSGGridView::preferredHighlightEnd() const
+{
+ Q_D(const QSGGridView);
+ return d->highlightRangeEnd;
+}
+
+void QSGGridView::setPreferredHighlightEnd(qreal end)
+{
+ Q_D(QSGGridView);
+ d->highlightRangeEndValid = true;
+ if (d->highlightRangeEnd == end)
+ return;
+ d->highlightRangeEnd = end;
+ d->haveHighlightRange = d->highlightRange != NoHighlightRange && d->highlightRangeStart <= d->highlightRangeEnd;
+ emit preferredHighlightEndChanged();
+}
+
+void QSGGridView::resetPreferredHighlightEnd()
+{
+ Q_D(QSGGridView);
+ d->highlightRangeEndValid = false;
+ if (d->highlightRangeEnd == 0)
+ return;
+ d->highlightRangeEnd = 0;
+ emit preferredHighlightEndChanged();
+}
+
+QSGGridView::HighlightRangeMode QSGGridView::highlightRangeMode() const
+{
+ Q_D(const QSGGridView);
+ return d->highlightRange;
+}
+
+void QSGGridView::setHighlightRangeMode(HighlightRangeMode mode)
+{
+ Q_D(QSGGridView);
+ if (d->highlightRange == mode)
+ return;
+ d->highlightRange = mode;
+ d->haveHighlightRange = d->highlightRange != NoHighlightRange && d->highlightRangeStart <= d->highlightRangeEnd;
+ emit highlightRangeModeChanged();
+}
+
+Qt::LayoutDirection QSGGridView::layoutDirection() const
+{
+ Q_D(const QSGGridView);
+ return d->layoutDirection;
+}
+
+void QSGGridView::setLayoutDirection(Qt::LayoutDirection layoutDirection)
+{
+ Q_D(QSGGridView);
+ if (d->layoutDirection != layoutDirection) {
+ d->layoutDirection = layoutDirection;
+ d->regenerate();
+ emit layoutDirectionChanged();
+ emit effectiveLayoutDirectionChanged();
+ }
+}
+
+Qt::LayoutDirection QSGGridView::effectiveLayoutDirection() const
+{
+ Q_D(const QSGGridView);
+ if (d->effectiveLayoutMirror)
+ return d->layoutDirection == Qt::RightToLeft ? Qt::LeftToRight : Qt::RightToLeft;
+ else
+ return d->layoutDirection;
+}
+
+QSGGridView::Flow QSGGridView::flow() const
+{
+ Q_D(const QSGGridView);
+ return d->flow;
+}
+
+void QSGGridView::setFlow(Flow flow)
+{
+ Q_D(QSGGridView);
+ if (d->flow != flow) {
+ d->flow = flow;
+ if (d->flow == LeftToRight) {
+ setContentWidth(-1);
+ setFlickableDirection(QSGFlickable::VerticalFlick);
+ } else {
+ setContentHeight(-1);
+ setFlickableDirection(QSGFlickable::HorizontalFlick);
+ }
+ setContentX(0);
+ setContentY(0);
+ d->regenerate();
+ emit flowChanged();
+ }
+}
+
+bool QSGGridView::isWrapEnabled() const
+{
+ Q_D(const QSGGridView);
+ return d->wrap;
+}
+
+void QSGGridView::setWrapEnabled(bool wrap)
+{
+ Q_D(QSGGridView);
+ if (d->wrap == wrap)
+ return;
+ d->wrap = wrap;
+ emit keyNavigationWrapsChanged();
+}
+
+int QSGGridView::cacheBuffer() const
+{
+ Q_D(const QSGGridView);
+ return d->buffer;
+}
+
+void QSGGridView::setCacheBuffer(int buffer)
+{
+ Q_D(QSGGridView);
+ if (d->buffer != buffer) {
+ d->buffer = buffer;
+ if (isComponentComplete())
+ refill();
+ emit cacheBufferChanged();
+ }
+}
+
+int QSGGridView::cellWidth() const
+{
+ Q_D(const QSGGridView);
+ return d->cellWidth;
+}
+
+void QSGGridView::setCellWidth(int cellWidth)
+{
+ Q_D(QSGGridView);
+ if (cellWidth != d->cellWidth && cellWidth > 0) {
+ d->cellWidth = qMax(1, cellWidth);
+ d->updateGrid();
+ emit cellWidthChanged();
+ d->layout();
+ }
+}
+
+int QSGGridView::cellHeight() const
+{
+ Q_D(const QSGGridView);
+ return d->cellHeight;
+}
+
+void QSGGridView::setCellHeight(int cellHeight)
+{
+ Q_D(QSGGridView);
+ if (cellHeight != d->cellHeight && cellHeight > 0) {
+ d->cellHeight = qMax(1, cellHeight);
+ d->updateGrid();
+ emit cellHeightChanged();
+ d->layout();
+ }
+}
+
+QSGGridView::SnapMode QSGGridView::snapMode() const
+{
+ Q_D(const QSGGridView);
+ return d->snapMode;
+}
+
+void QSGGridView::setSnapMode(SnapMode mode)
+{
+ Q_D(QSGGridView);
+ if (d->snapMode != mode) {
+ d->snapMode = mode;
+ emit snapModeChanged();
+ }
+}
+
+QDeclarativeComponent *QSGGridView::footer() const
+{
+ Q_D(const QSGGridView);
+ return d->footerComponent;
+}
+
+void QSGGridView::setFooter(QDeclarativeComponent *footer)
+{
+ Q_D(QSGGridView);
+ if (d->footerComponent != footer) {
+ if (d->footer) {
+ // XXX todo - the original did scene()->removeItem(). Why?
+ d->footer->item->setParentItem(0);
+ d->footer->item->deleteLater();
+ delete d->footer;
+ d->footer = 0;
+ }
+ d->footerComponent = footer;
+ if (isComponentComplete()) {
+ d->updateFooter();
+ d->updateGrid();
+ d->fixupPosition();
+ }
+ emit footerChanged();
+ }
+}
+
+QDeclarativeComponent *QSGGridView::header() const
+{
+ Q_D(const QSGGridView);
+ return d->headerComponent;
+}
+
+void QSGGridView::setHeader(QDeclarativeComponent *header)
+{
+ Q_D(QSGGridView);
+ if (d->headerComponent != header) {
+ if (d->header) {
+ // XXX todo - the original did scene()->removeItem(). Why?
+ d->header->item->setParentItem(0);
+ d->header->item->deleteLater();
+ delete d->header;
+ d->header = 0;
+ }
+ d->headerComponent = header;
+ if (isComponentComplete()) {
+ d->updateHeader();
+ d->updateFooter();
+ d->updateGrid();
+ d->fixupPosition();
+ }
+ emit headerChanged();
+ }
+}
+
+void QSGGridView::setContentX(qreal pos)
+{
+ Q_D(QSGGridView);
+ // Positioning the view manually should override any current movement state
+ d->moveReason = QSGGridViewPrivate::Other;
+ QSGFlickable::setContentX(pos);
+}
+
+void QSGGridView::setContentY(qreal pos)
+{
+ Q_D(QSGGridView);
+ // Positioning the view manually should override any current movement state
+ d->moveReason = QSGGridViewPrivate::Other;
+ QSGFlickable::setContentY(pos);
+}
+
+void QSGGridView::updatePolish()
+{
+ Q_D(QSGGridView);
+ QSGFlickable::updatePolish();
+ d->layout();
+}
+
+void QSGGridView::viewportMoved()
+{
+ Q_D(QSGGridView);
+ QSGFlickable::viewportMoved();
+ if (!d->itemCount)
+ return;
+ d->lazyRelease = true;
+ if (d->flickingHorizontally || d->flickingVertically) {
+ if (yflick()) {
+ if (d->vData.velocity > 0)
+ d->bufferMode = QSGGridViewPrivate::BufferBefore;
+ else if (d->vData.velocity < 0)
+ d->bufferMode = QSGGridViewPrivate::BufferAfter;
+ }
+
+ if (xflick()) {
+ if (d->hData.velocity > 0)
+ d->bufferMode = QSGGridViewPrivate::BufferBefore;
+ else if (d->hData.velocity < 0)
+ d->bufferMode = QSGGridViewPrivate::BufferAfter;
+ }
+ }
+ refill();
+ if (d->flickingHorizontally || d->flickingVertically || d->movingHorizontally || d->movingVertically)
+ d->moveReason = QSGGridViewPrivate::Mouse;
+ if (d->moveReason != QSGGridViewPrivate::SetIndex) {
+ if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange && d->highlight) {
+ // reposition highlight
+ qreal pos = d->highlight->rowPos();
+ qreal viewPos;
+ qreal highlightStart;
+ qreal highlightEnd;
+ if (d->isRightToLeftTopToBottom()) {
+ highlightStart = d->highlightRangeStartValid ? d->size()-d->highlightRangeEnd : d->highlightRangeStart;
+ highlightEnd = d->highlightRangeEndValid ? d->size()-d->highlightRangeStart : d->highlightRangeEnd;
+ viewPos = -d->position()-d->size();
+ } else {
+ highlightStart = d->highlightRangeStart;
+ highlightEnd = d->highlightRangeEnd;
+ viewPos = d->position();
+ }
+ if (pos > viewPos + highlightEnd - d->rowSize())
+ pos = viewPos + highlightEnd - d->rowSize();
+ if (pos < viewPos + highlightStart)
+ pos = viewPos + highlightStart;
+ d->highlight->setPosition(d->highlight->colPos(), qRound(pos));
+
+ // update current index
+ int idx = d->snapIndex();
+ if (idx >= 0 && idx != d->currentIndex) {
+ d->updateCurrent(idx);
+ if (d->currentItem && d->currentItem->colPos() != d->highlight->colPos() && d->autoHighlight) {
+ if (d->flow == LeftToRight)
+ d->highlightXAnimator->to = d->currentItem->item->x();
+ else
+ d->highlightYAnimator->to = d->currentItem->item->y();
+ }
+ }
+ }
+ }
+}
+
+qreal QSGGridView::minYExtent() const
+{
+ Q_D(const QSGGridView);
+ if (d->flow == QSGGridView::TopToBottom)
+ return QSGFlickable::minYExtent();
+ qreal extent = -d->startPosition();
+ if (d->header && d->visibleItems.count())
+ extent += d->header->item->height();
+ if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange) {
+ extent += d->highlightRangeStart;
+ extent = qMax(extent, -(d->rowPosAt(0) + d->rowSize() - d->highlightRangeEnd));
+ }
+ return extent;
+}
+
+qreal QSGGridView::maxYExtent() const
+{
+ Q_D(const QSGGridView);
+ if (d->flow == QSGGridView::TopToBottom)
+ return QSGFlickable::maxYExtent();
+ qreal extent;
+ if (!d->model || !d->model->count()) {
+ extent = 0;
+ } else if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange) {
+ extent = -(d->rowPosAt(d->model->count()-1) - d->highlightRangeStart);
+ if (d->highlightRangeEnd != d->highlightRangeStart)
+ extent = qMin(extent, -(d->endPosition() - d->highlightRangeEnd + 1));
+ } else {
+ extent = -(d->endPosition() - height());
+ }
+ if (d->footer)
+ extent -= d->footer->item->height();
+ const qreal minY = minYExtent();
+ if (extent > minY)
+ extent = minY;
+ return extent;
+}
+
+qreal QSGGridView::minXExtent() const
+{
+ Q_D(const QSGGridView);
+ if (d->flow == QSGGridView::LeftToRight)
+ return QSGFlickable::minXExtent();
+ qreal extent = -d->startPosition();
+ qreal highlightStart;
+ qreal highlightEnd;
+ qreal endPositionFirstItem;
+ if (d->isRightToLeftTopToBottom()) {
+ endPositionFirstItem = d->rowPosAt(d->model->count()-1);
+ highlightStart = d->highlightRangeStartValid
+ ? d->highlightRangeStart - (d->lastPosition()-endPositionFirstItem)
+ : d->size() - (d->lastPosition()-endPositionFirstItem);
+ highlightEnd = d->highlightRangeEndValid ? d->highlightRangeEnd : d->size();
+ if (d->footer && d->visibleItems.count())
+ extent += d->footer->item->width();
+ } else {
+ endPositionFirstItem = d->rowPosAt(0)+d->rowSize();
+ highlightStart = d->highlightRangeStart;
+ highlightEnd = d->highlightRangeEnd;
+ if (d->header && d->visibleItems.count())
+ extent += d->header->item->width();
+ }
+ if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange) {
+ extent += highlightStart;
+ extent = qMax(extent, -(endPositionFirstItem - highlightEnd));
+ }
+ return extent;
+}
+
+qreal QSGGridView::maxXExtent() const
+{
+ Q_D(const QSGGridView);
+ if (d->flow == QSGGridView::LeftToRight)
+ return QSGFlickable::maxXExtent();
+ qreal extent;
+ qreal highlightStart;
+ qreal highlightEnd;
+ qreal lastItemPosition = 0;
+ if (d->isRightToLeftTopToBottom()){
+ highlightStart = d->highlightRangeStartValid ? d->highlightRangeEnd : d->size();
+ highlightEnd = d->highlightRangeEndValid ? d->highlightRangeStart : d->size();
+ lastItemPosition = d->endPosition();
+ } else {
+ highlightStart = d->highlightRangeStart;
+ highlightEnd = d->highlightRangeEnd;
+ lastItemPosition = 0;
+ if (d->model && d->model->count())
+ lastItemPosition = d->rowPosAt(d->model->count()-1);
+ }
+ if (!d->model || !d->model->count()) {
+ extent = 0;
+ } else if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange) {
+ extent = -(lastItemPosition - highlightStart);
+ if (highlightEnd != highlightStart)
+ extent = d->isRightToLeftTopToBottom()
+ ? qMax(extent, -(d->endPosition() - highlightEnd + 1))
+ : qMin(extent, -(d->endPosition() - highlightEnd + 1));
+ } else {
+ extent = -(d->endPosition() - width());
+ }
+ if (d->isRightToLeftTopToBottom()) {
+ if (d->header)
+ extent -= d->header->item->width();
+ } else {
+ if (d->footer)
+ extent -= d->footer->item->width();
+ }
+
+ const qreal minX = minXExtent();
+ if (extent > minX)
+ extent = minX;
+ return extent;
+}
+
+void QSGGridView::keyPressEvent(QKeyEvent *event)
+{
+ Q_D(QSGGridView);
+ if (d->model && d->model->count() && d->interactive) {
+ d->moveReason = QSGGridViewPrivate::SetIndex;
+ int oldCurrent = currentIndex();
+ switch (event->key()) {
+ case Qt::Key_Up:
+ moveCurrentIndexUp();
+ break;
+ case Qt::Key_Down:
+ moveCurrentIndexDown();
+ break;
+ case Qt::Key_Left:
+ moveCurrentIndexLeft();
+ break;
+ case Qt::Key_Right:
+ moveCurrentIndexRight();
+ break;
+ default:
+ break;
+ }
+ if (oldCurrent != currentIndex()) {
+ event->accept();
+ return;
+ }
+ }
+ d->moveReason = QSGGridViewPrivate::Other;
+ event->ignore();
+ QSGFlickable::keyPressEvent(event);
+}
+
+void QSGGridView::moveCurrentIndexUp()
+{
+ Q_D(QSGGridView);
+ const int count = d->model ? d->model->count() : 0;
+ if (!count)
+ return;
+ if (d->flow == QSGGridView::LeftToRight) {
+ if (currentIndex() >= d->columns || d->wrap) {
+ int index = currentIndex() - d->columns;
+ setCurrentIndex((index >= 0 && index < count) ? index : count-1);
+ }
+ } else {
+ if (currentIndex() > 0 || d->wrap) {
+ int index = currentIndex() - 1;
+ setCurrentIndex((index >= 0 && index < count) ? index : count-1);
+ }
+ }
+}
+
+void QSGGridView::moveCurrentIndexDown()
+{
+ Q_D(QSGGridView);
+ const int count = d->model ? d->model->count() : 0;
+ if (!count)
+ return;
+ if (d->flow == QSGGridView::LeftToRight) {
+ if (currentIndex() < count - d->columns || d->wrap) {
+ int index = currentIndex()+d->columns;
+ setCurrentIndex((index >= 0 && index < count) ? index : 0);
+ }
+ } else {
+ if (currentIndex() < count - 1 || d->wrap) {
+ int index = currentIndex() + 1;
+ setCurrentIndex((index >= 0 && index < count) ? index : 0);
+ }
+ }
+}
+
+void QSGGridView::moveCurrentIndexLeft()
+{
+ Q_D(QSGGridView);
+ const int count = d->model ? d->model->count() : 0;
+ if (!count)
+ return;
+ if (effectiveLayoutDirection() == Qt::LeftToRight) {
+ if (d->flow == QSGGridView::LeftToRight) {
+ if (currentIndex() > 0 || d->wrap) {
+ int index = currentIndex() - 1;
+ setCurrentIndex((index >= 0 && index < count) ? index : count-1);
+ }
+ } else {
+ if (currentIndex() >= d->columns || d->wrap) {
+ int index = currentIndex() - d->columns;
+ setCurrentIndex((index >= 0 && index < count) ? index : count-1);
+ }
+ }
+ } else {
+ if (d->flow == QSGGridView::LeftToRight) {
+ if (currentIndex() < count - 1 || d->wrap) {
+ int index = currentIndex() + 1;
+ setCurrentIndex((index >= 0 && index < count) ? index : 0);
+ }
+ } else {
+ if (currentIndex() < count - d->columns || d->wrap) {
+ int index = currentIndex() + d->columns;
+ setCurrentIndex((index >= 0 && index < count) ? index : 0);
+ }
+ }
+ }
+}
+
+void QSGGridView::moveCurrentIndexRight()
+{
+ Q_D(QSGGridView);
+ const int count = d->model ? d->model->count() : 0;
+ if (!count)
+ return;
+ if (effectiveLayoutDirection() == Qt::LeftToRight) {
+ if (d->flow == QSGGridView::LeftToRight) {
+ if (currentIndex() < count - 1 || d->wrap) {
+ int index = currentIndex() + 1;
+ setCurrentIndex((index >= 0 && index < count) ? index : 0);
+ }
+ } else {
+ if (currentIndex() < count - d->columns || d->wrap) {
+ int index = currentIndex()+d->columns;
+ setCurrentIndex((index >= 0 && index < count) ? index : 0);
+ }
+ }
+ } else {
+ if (d->flow == QSGGridView::LeftToRight) {
+ if (currentIndex() > 0 || d->wrap) {
+ int index = currentIndex() - 1;
+ setCurrentIndex((index >= 0 && index < count) ? index : count-1);
+ }
+ } else {
+ if (currentIndex() >= d->columns || d->wrap) {
+ int index = currentIndex() - d->columns;
+ setCurrentIndex((index >= 0 && index < count) ? index : count-1);
+ }
+ }
+ }
+}
+
+void QSGGridViewPrivate::positionViewAtIndex(int index, int mode)
+{
+ Q_Q(QSGGridView);
+ if (!isValid())
+ return;
+ if (mode < QSGGridView::Beginning || mode > QSGGridView::Contain)
+ return;
+
+ int idx = qMax(qMin(index, model->count()-1), 0);
+
+ if (layoutScheduled)
+ layout();
+ qreal pos = isRightToLeftTopToBottom() ? -position() - size() : position();
+ FxGridItemSG *item = visibleItem(idx);
+ qreal maxExtent;
+ if (flow == QSGGridView::LeftToRight)
+ maxExtent = -q->maxYExtent();
+ else
+ maxExtent = isRightToLeftTopToBottom() ? q->minXExtent()-size() : -q->maxXExtent();
+ if (!item) {
+ int itemPos = rowPosAt(idx);
+ // save the currently visible items in case any of them end up visible again
+ QList<FxGridItemSG*> oldVisible = visibleItems;
+ visibleItems.clear();
+ visibleIndex = idx - idx % columns;
+ if (flow == QSGGridView::LeftToRight)
+ maxExtent = -q->maxYExtent();
+ else
+ maxExtent = isRightToLeftTopToBottom() ? q->minXExtent()-size() : -q->maxXExtent();
+ setPosition(qMin(qreal(itemPos), maxExtent));
+ // now release the reference to all the old visible items.
+ for (int i = 0; i < oldVisible.count(); ++i)
+ releaseItem(oldVisible.at(i));
+ item = visibleItem(idx);
+ }
+ if (item) {
+ qreal itemPos = item->rowPos();
+ switch (mode) {
+ case QSGGridView::Beginning:
+ pos = itemPos;
+ if (index < 0 && header) {
+ pos -= flow == QSGGridView::LeftToRight
+ ? header->item->height()
+ : header->item->width();
+ }
+ break;
+ case QSGGridView::Center:
+ pos = itemPos - (size() - rowSize())/2;
+ break;
+ case QSGGridView::End:
+ pos = itemPos - size() + rowSize();
+ if (index >= model->count() && footer) {
+ pos += flow == QSGGridView::LeftToRight
+ ? footer->item->height()
+ : footer->item->width();
+ }
+ break;
+ case QSGGridView::Visible:
+ if (itemPos > pos + size())
+ pos = itemPos - size() + rowSize();
+ else if (item->endRowPos() < pos)
+ pos = itemPos;
+ break;
+ case QSGGridView::Contain:
+ if (item->endRowPos() > pos + size())
+ pos = itemPos - size() + rowSize();
+ if (itemPos < pos)
+ pos = itemPos;
+ }
+ pos = qMin(pos, maxExtent);
+ qreal minExtent;
+ if (flow == QSGGridView::LeftToRight)
+ minExtent = -q->minYExtent();
+ else
+ minExtent = isRightToLeftTopToBottom() ? q->maxXExtent()-size() : -q->minXExtent();
+ pos = qMax(pos, minExtent);
+ moveReason = QSGGridViewPrivate::Other;
+ q->cancelFlick();
+ setPosition(pos);
+ }
+ fixupPosition();
+}
+
+void QSGGridView::positionViewAtIndex(int index, int mode)
+{
+ Q_D(QSGGridView);
+ if (!d->isValid() || index < 0 || index >= d->model->count())
+ return;
+ d->positionViewAtIndex(index, mode);
+}
+
+void QSGGridView::positionViewAtBeginning()
+{
+ Q_D(QSGGridView);
+ if (!d->isValid())
+ return;
+ d->positionViewAtIndex(-1, Beginning);
+}
+
+void QSGGridView::positionViewAtEnd()
+{
+ Q_D(QSGGridView);
+ if (!d->isValid())
+ return;
+ d->positionViewAtIndex(d->model->count(), End);
+}
+
+int QSGGridView::indexAt(qreal x, qreal y) const
+{
+ Q_D(const QSGGridView);
+ for (int i = 0; i < d->visibleItems.count(); ++i) {
+ const FxGridItemSG *listItem = d->visibleItems.at(i);
+ if(listItem->contains(x, y))
+ return listItem->index;
+ }
+
+ return -1;
+}
+
+void QSGGridView::componentComplete()
+{
+ Q_D(QSGGridView);
+ QSGFlickable::componentComplete();
+ d->updateHeader();
+ d->updateFooter();
+ d->updateGrid();
+ if (d->isValid()) {
+ refill();
+ d->moveReason = QSGGridViewPrivate::SetIndex;
+ if (d->currentIndex < 0 && !d->currentIndexCleared)
+ d->updateCurrent(0);
+ else
+ d->updateCurrent(d->currentIndex);
+ if (d->highlight && d->currentItem) {
+ if (d->autoHighlight)
+ d->highlight->setPosition(d->currentItem->colPos(), d->currentItem->rowPos());
+ d->updateTrackedItem();
+ }
+ d->moveReason = QSGGridViewPrivate::Other;
+ d->fixupPosition();
+ }
+}
+
+void QSGGridView::trackedPositionChanged()
+{
+ Q_D(QSGGridView);
+ if (!d->trackedItem || !d->currentItem)
+ return;
+ if (d->moveReason == QSGGridViewPrivate::SetIndex) {
+ const qreal trackedPos = d->trackedItem->rowPos();
+ qreal viewPos;
+ qreal highlightStart;
+ qreal highlightEnd;
+ if (d->isRightToLeftTopToBottom()) {
+ viewPos = -d->position()-d->size();
+ highlightStart = d->highlightRangeStartValid ? d->size()-d->highlightRangeEnd : d->highlightRangeStart;
+ highlightEnd = d->highlightRangeEndValid ? d->size()-d->highlightRangeStart : d->highlightRangeEnd;
+ } else {
+ viewPos = d->position();
+ highlightStart = d->highlightRangeStart;
+ highlightEnd = d->highlightRangeEnd;
+ }
+ qreal pos = viewPos;
+ if (d->haveHighlightRange) {
+ if (d->highlightRange == StrictlyEnforceRange) {
+ if (trackedPos > pos + highlightEnd - d->rowSize())
+ pos = trackedPos - highlightEnd + d->rowSize();
+ if (trackedPos < pos + highlightStart)
+ pos = trackedPos - highlightStart;
+ } else {
+ if (trackedPos < d->startPosition() + highlightStart) {
+ pos = d->startPosition();
+ } else if (d->trackedItem->endRowPos() > d->endPosition() - d->size() + highlightEnd) {
+ pos = d->endPosition() - d->size() + 1;
+ if (pos < d->startPosition())
+ pos = d->startPosition();
+ } else {
+ if (trackedPos < viewPos + highlightStart) {
+ pos = trackedPos - highlightStart;
+ } else if (trackedPos > viewPos + highlightEnd - d->rowSize()) {
+ pos = trackedPos - highlightEnd + d->rowSize();
+ }
+ }
+ }
+ } else {
+ if (trackedPos < viewPos && d->currentItem->rowPos() < viewPos) {
+ pos = qMax(trackedPos, d->currentItem->rowPos());
+ } else if (d->trackedItem->endRowPos() >= viewPos + d->size()
+ && d->currentItem->endRowPos() >= viewPos + d->size()) {
+ if (d->trackedItem->endRowPos() <= d->currentItem->endRowPos()) {
+ pos = d->trackedItem->endRowPos() - d->size() + 1;
+ if (d->rowSize() > d->size())
+ pos = trackedPos;
+ } else {
+ pos = d->currentItem->endRowPos() - d->size() + 1;
+ if (d->rowSize() > d->size())
+ pos = d->currentItem->rowPos();
+ }
+ }
+ }
+ if (viewPos != pos) {
+ cancelFlick();
+ d->calcVelocity = true;
+ d->setPosition(pos);
+ d->calcVelocity = false;
+ }
+ }
+}
+
+void QSGGridView::itemsInserted(int modelIndex, int count)
+{
+ Q_D(QSGGridView);
+ if (!isComponentComplete())
+ return;
+
+ int index = d->visibleItems.count() ? d->mapFromModel(modelIndex) : 0;
+ if (index < 0) {
+ int i = d->visibleItems.count() - 1;
+ while (i > 0 && d->visibleItems.at(i)->index == -1)
+ --i;
+ if (d->visibleItems.at(i)->index + 1 == modelIndex) {
+ // Special case of appending an item to the model.
+ index = d->visibleIndex + d->visibleItems.count();
+ } else {
+ if (modelIndex <= d->visibleIndex) {
+ // Insert before visible items
+ d->visibleIndex += count;
+ for (int i = 0; i < d->visibleItems.count(); ++i) {
+ FxGridItemSG *listItem = d->visibleItems.at(i);
+ if (listItem->index != -1 && listItem->index >= modelIndex)
+ listItem->index += count;
+ }
+ }
+ if (d->currentIndex >= modelIndex) {
+ // adjust current item index
+ d->currentIndex += count;
+ if (d->currentItem)
+ d->currentItem->index = d->currentIndex;
+ emit currentIndexChanged();
+ }
+ d->scheduleLayout();
+ d->itemCount += count;
+ emit countChanged();
+ return;
+ }
+ }
+
+ int insertCount = count;
+ if (index < d->visibleIndex && d->visibleItems.count()) {
+ insertCount -= d->visibleIndex - index;
+ index = d->visibleIndex;
+ modelIndex = d->visibleIndex;
+ }
+
+ qreal tempPos = d->isRightToLeftTopToBottom() ? -d->position()-d->size()+width()+1 : d->position();
+ int to = d->buffer+tempPos+d->size()-1;
+ int colPos = 0;
+ int rowPos = 0;
+ if (d->visibleItems.count()) {
+ index -= d->visibleIndex;
+ if (index < d->visibleItems.count()) {
+ colPos = d->visibleItems.at(index)->colPos();
+ rowPos = d->visibleItems.at(index)->rowPos();
+ } else {
+ // appending items to visible list
+ colPos = d->visibleItems.at(index-1)->colPos() + d->colSize();
+ rowPos = d->visibleItems.at(index-1)->rowPos();
+ if (colPos > d->colSize() * (d->columns-1)) {
+ colPos = 0;
+ rowPos += d->rowSize();
+ }
+ }
+ } else if (d->itemCount == 0 && d->header) {
+ rowPos = d->headerSize();
+ }
+
+ // Update the indexes of the following visible items.
+ for (int i = 0; i < d->visibleItems.count(); ++i) {
+ FxGridItemSG *listItem = d->visibleItems.at(i);
+ if (listItem->index != -1 && listItem->index >= modelIndex)
+ listItem->index += count;
+ }
+
+ bool addedVisible = false;
+ QList<FxGridItemSG*> added;
+ int i = 0;
+ while (i < insertCount && rowPos <= to + d->rowSize()*(d->columns - (colPos/d->colSize()))/qreal(d->columns)) {
+ if (!addedVisible) {
+ d->scheduleLayout();
+ addedVisible = true;
+ }
+ FxGridItemSG *item = d->createItem(modelIndex + i);
+ d->visibleItems.insert(index, item);
+ item->setPosition(colPos, rowPos);
+ added.append(item);
+ colPos += d->colSize();
+ if (colPos > d->colSize() * (d->columns-1)) {
+ colPos = 0;
+ rowPos += d->rowSize();
+ }
+ ++index;
+ ++i;
+ }
+ if (i < insertCount) {
+ // We didn't insert all our new items, which means anything
+ // beyond the current index is not visible - remove it.
+ while (d->visibleItems.count() > index) {
+ d->releaseItem(d->visibleItems.takeLast());
+ }
+ }
+
+ // update visibleIndex
+ d->visibleIndex = 0;
+ for (QList<FxGridItemSG*>::Iterator it = d->visibleItems.begin(); it != d->visibleItems.end(); ++it) {
+ if ((*it)->index != -1) {
+ d->visibleIndex = (*it)->index;
+ break;
+ }
+ }
+
+ if (d->itemCount && d->currentIndex >= modelIndex) {
+ // adjust current item index
+ d->currentIndex += count;
+ if (d->currentItem) {
+ d->currentItem->index = d->currentIndex;
+ d->currentItem->setPosition(d->colPosAt(d->currentIndex), d->rowPosAt(d->currentIndex));
+ }
+ emit currentIndexChanged();
+ } else if (d->itemCount == 0 && (!d->currentIndex || (d->currentIndex < 0 && !d->currentIndexCleared))) {
+ setCurrentIndex(0);
+ }
+
+ // everything is in order now - emit add() signal
+ for (int j = 0; j < added.count(); ++j)
+ added.at(j)->attached->emitAdd();
+
+ d->itemCount += count;
+ emit countChanged();
+}
+
+void QSGGridView::itemsRemoved(int modelIndex, int count)
+{
+ Q_D(QSGGridView);
+ if (!isComponentComplete())
+ return;
+
+ d->itemCount -= count;
+ bool currentRemoved = d->currentIndex >= modelIndex && d->currentIndex < modelIndex + count;
+ bool removedVisible = false;
+
+ // Remove the items from the visible list, skipping anything already marked for removal
+ QList<FxGridItemSG*>::Iterator it = d->visibleItems.begin();
+ while (it != d->visibleItems.end()) {
+ FxGridItemSG *item = *it;
+ if (item->index == -1 || item->index < modelIndex) {
+ // already removed, or before removed items
+ if (item->index < modelIndex && !removedVisible) {
+ d->scheduleLayout();
+ removedVisible = true;
+ }
+ ++it;
+ } else if (item->index >= modelIndex + count) {
+ // after removed items
+ item->index -= count;
+ ++it;
+ } else {
+ // removed item
+ if (!removedVisible) {
+ d->scheduleLayout();
+ removedVisible = true;
+ }
+ item->attached->emitRemove();
+ if (item->attached->delayRemove()) {
+ item->index = -1;
+ connect(item->attached, SIGNAL(delayRemoveChanged()), this, SLOT(destroyRemoved()), Qt::QueuedConnection);
+ ++it;
+ } else {
+ it = d->visibleItems.erase(it);
+ d->releaseItem(item);
+ }
+ }
+ }
+
+ // fix current
+ if (d->currentIndex >= modelIndex + count) {
+ d->currentIndex -= count;
+ if (d->currentItem)
+ d->currentItem->index -= count;
+ emit currentIndexChanged();
+ } else if (currentRemoved) {
+ // current item has been removed.
+ d->releaseItem(d->currentItem);
+ d->currentItem = 0;
+ d->currentIndex = -1;
+ if (d->itemCount)
+ d->updateCurrent(qMin(modelIndex, d->itemCount-1));
+ else
+ emit currentIndexChanged();
+ }
+
+ // update visibleIndex
+ d->visibleIndex = 0;
+ for (it = d->visibleItems.begin(); it != d->visibleItems.end(); ++it) {
+ if ((*it)->index != -1) {
+ d->visibleIndex = (*it)->index;
+ break;
+ }
+ }
+
+ if (removedVisible && d->visibleItems.isEmpty()) {
+ d->timeline.clear();
+ if (d->itemCount == 0) {
+ d->setPosition(0);
+ d->updateHeader();
+ d->updateFooter();
+ }
+ }
+
+ emit countChanged();
+}
+
+void QSGGridView::destroyRemoved()
+{
+ Q_D(QSGGridView);
+ for (QList<FxGridItemSG*>::Iterator it = d->visibleItems.begin();
+ it != d->visibleItems.end();) {
+ FxGridItemSG *listItem = *it;
+ if (listItem->index == -1 && listItem->attached->delayRemove() == false) {
+ d->releaseItem(listItem);
+ it = d->visibleItems.erase(it);
+ } else {
+ ++it;
+ }
+ }
+
+ // Correct the positioning of the items
+ d->layout();
+}
+
+void QSGGridView::itemsMoved(int from, int to, int count)
+{
+ Q_D(QSGGridView);
+ if (!isComponentComplete())
+ return;
+ QHash<int,FxGridItemSG*> moved;
+
+ FxGridItemSG *firstItem = d->firstVisibleItem();
+
+ QList<FxGridItemSG*>::Iterator it = d->visibleItems.begin();
+ while (it != d->visibleItems.end()) {
+ FxGridItemSG *item = *it;
+ if (item->index >= from && item->index < from + count) {
+ // take the items that are moving
+ item->index += (to-from);
+ moved.insert(item->index, item);
+ it = d->visibleItems.erase(it);
+ } else {
+ if (item->index > from && item->index != -1) {
+ // move everything after the moved items.
+ item->index -= count;
+ if (item->index < d->visibleIndex)
+ d->visibleIndex = item->index;
+ }
+ ++it;
+ }
+ }
+
+ int remaining = count;
+ int endIndex = d->visibleIndex;
+ it = d->visibleItems.begin();
+ while (it != d->visibleItems.end()) {
+ FxGridItemSG *item = *it;
+ if (remaining && item->index >= to && item->index < to + count) {
+ // place items in the target position, reusing any existing items
+ FxGridItemSG *movedItem = moved.take(item->index);
+ if (!movedItem)
+ movedItem = d->createItem(item->index);
+ it = d->visibleItems.insert(it, movedItem);
+ if (it == d->visibleItems.begin() && firstItem)
+ movedItem->setPosition(firstItem->colPos(), firstItem->rowPos());
+ ++it;
+ --remaining;
+ } else {
+ if (item->index != -1) {
+ if (item->index >= to) {
+ // update everything after the moved items.
+ item->index += count;
+ }
+ endIndex = item->index;
+ }
+ ++it;
+ }
+ }
+
+ // If we have moved items to the end of the visible items
+ // then add any existing moved items that we have
+ while (FxGridItemSG *item = moved.take(endIndex+1)) {
+ d->visibleItems.append(item);
+ ++endIndex;
+ }
+
+ // update visibleIndex
+ for (it = d->visibleItems.begin(); it != d->visibleItems.end(); ++it) {
+ if ((*it)->index != -1) {
+ d->visibleIndex = (*it)->index;
+ break;
+ }
+ }
+
+ // Fix current index
+ if (d->currentIndex >= 0 && d->currentItem) {
+ int oldCurrent = d->currentIndex;
+ d->currentIndex = d->model->indexOf(d->currentItem->item, this);
+ if (oldCurrent != d->currentIndex) {
+ d->currentItem->index = d->currentIndex;
+ emit currentIndexChanged();
+ }
+ }
+
+ // Whatever moved items remain are no longer visible items.
+ while (moved.count()) {
+ int idx = moved.begin().key();
+ FxGridItemSG *item = moved.take(idx);
+ if (d->currentItem && item->item == d->currentItem->item)
+ item->setPosition(d->colPosAt(idx), d->rowPosAt(idx));
+ d->releaseItem(item);
+ }
+
+ d->layout();
+}
+
+void QSGGridView::modelReset()
+{
+ Q_D(QSGGridView);
+ d->clear();
+ refill();
+ d->moveReason = QSGGridViewPrivate::SetIndex;
+ d->updateCurrent(d->currentIndex);
+ if (d->highlight && d->currentItem) {
+ if (d->autoHighlight)
+ d->highlight->setPosition(d->currentItem->colPos(), d->currentItem->rowPos());
+ d->updateTrackedItem();
+ }
+ d->moveReason = QSGGridViewPrivate::Other;
+
+ emit countChanged();
+}
+
+void QSGGridView::createdItem(int index, QSGItem *item)
+{
+ Q_D(QSGGridView);
+ if (d->requestedIndex != index) {
+ item->setParentItem(this);
+ d->unrequestedItems.insert(item, index);
+ if (d->flow == QSGGridView::LeftToRight) {
+ item->setPos(QPointF(d->colPosAt(index), d->rowPosAt(index)));
+ } else {
+ item->setPos(QPointF(d->rowPosAt(index), d->colPosAt(index)));
+ }
+ }
+}
+
+void QSGGridView::destroyingItem(QSGItem *item)
+{
+ Q_D(QSGGridView);
+ d->unrequestedItems.remove(item);
+}
+
+void QSGGridView::animStopped()
+{
+ Q_D(QSGGridView);
+ d->bufferMode = QSGGridViewPrivate::NoBuffer;
+ if (d->haveHighlightRange && d->highlightRange == QSGGridView::StrictlyEnforceRange)
+ d->updateHighlight();
+}
+
+void QSGGridView::refill()
+{
+ Q_D(QSGGridView);
+ if (d->isRightToLeftTopToBottom())
+ d->refill(-d->position()-d->size()+1, -d->position());
+ else
+ d->refill(d->position(), d->position()+d->size()-1);
+}
+
+
+QSGGridViewAttached *QSGGridView::qmlAttachedProperties(QObject *obj)
+{
+ return new QSGGridViewAttached(obj);
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/items/qsggridview_p.h b/src/declarative/items/qsggridview_p.h
new file mode 100644
index 0000000000..8eca17df55
--- /dev/null
+++ b/src/declarative/items/qsggridview_p.h
@@ -0,0 +1,290 @@
+// Commit: 95814418f9d6adeba365c795462e8afb00138211
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGGRIDVIEW_P_H
+#define QSGGRIDVIEW_P_H
+
+#include "qsgflickable_p.h"
+
+#include <private/qdeclarativeguard_p.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+class QSGVisualModel;
+class QSGGridViewAttached;
+class QSGGridViewPrivate;
+class Q_AUTOTEST_EXPORT QSGGridView : public QSGFlickable
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QSGGridView)
+
+ Q_PROPERTY(QVariant model READ model WRITE setModel NOTIFY modelChanged)
+ Q_PROPERTY(QDeclarativeComponent *delegate READ delegate WRITE setDelegate NOTIFY delegateChanged)
+ Q_PROPERTY(int currentIndex READ currentIndex WRITE setCurrentIndex NOTIFY currentIndexChanged)
+ Q_PROPERTY(QSGItem *currentItem READ currentItem NOTIFY currentIndexChanged)
+ Q_PROPERTY(int count READ count NOTIFY countChanged)
+
+ Q_PROPERTY(QDeclarativeComponent *highlight READ highlight WRITE setHighlight NOTIFY highlightChanged)
+ Q_PROPERTY(QSGItem *highlightItem READ highlightItem NOTIFY highlightItemChanged)
+ Q_PROPERTY(bool highlightFollowsCurrentItem READ highlightFollowsCurrentItem WRITE setHighlightFollowsCurrentItem)
+ Q_PROPERTY(int highlightMoveDuration READ highlightMoveDuration WRITE setHighlightMoveDuration NOTIFY highlightMoveDurationChanged)
+
+ Q_PROPERTY(qreal preferredHighlightBegin READ preferredHighlightBegin WRITE setPreferredHighlightBegin NOTIFY preferredHighlightBeginChanged RESET resetPreferredHighlightBegin)
+ Q_PROPERTY(qreal preferredHighlightEnd READ preferredHighlightEnd WRITE setPreferredHighlightEnd NOTIFY preferredHighlightEndChanged RESET resetPreferredHighlightEnd)
+ Q_PROPERTY(HighlightRangeMode highlightRangeMode READ highlightRangeMode WRITE setHighlightRangeMode NOTIFY highlightRangeModeChanged)
+
+ Q_PROPERTY(Flow flow READ flow WRITE setFlow NOTIFY flowChanged)
+ Q_PROPERTY(Qt::LayoutDirection layoutDirection READ layoutDirection WRITE setLayoutDirection NOTIFY layoutDirectionChanged)
+ Q_PROPERTY(Qt::LayoutDirection effectiveLayoutDirection READ effectiveLayoutDirection NOTIFY effectiveLayoutDirectionChanged)
+ Q_PROPERTY(bool keyNavigationWraps READ isWrapEnabled WRITE setWrapEnabled NOTIFY keyNavigationWrapsChanged)
+ Q_PROPERTY(int cacheBuffer READ cacheBuffer WRITE setCacheBuffer NOTIFY cacheBufferChanged)
+ Q_PROPERTY(int cellWidth READ cellWidth WRITE setCellWidth NOTIFY cellWidthChanged)
+ Q_PROPERTY(int cellHeight READ cellHeight WRITE setCellHeight NOTIFY cellHeightChanged)
+
+ Q_PROPERTY(SnapMode snapMode READ snapMode WRITE setSnapMode NOTIFY snapModeChanged)
+
+ Q_PROPERTY(QDeclarativeComponent *header READ header WRITE setHeader NOTIFY headerChanged)
+ Q_PROPERTY(QDeclarativeComponent *footer READ footer WRITE setFooter NOTIFY footerChanged)
+
+ Q_ENUMS(HighlightRangeMode)
+ Q_ENUMS(SnapMode)
+ Q_ENUMS(Flow)
+ Q_ENUMS(PositionMode)
+ Q_CLASSINFO("DefaultProperty", "data")
+
+public:
+ QSGGridView(QSGItem *parent=0);
+ ~QSGGridView();
+
+ QVariant model() const;
+ int modelCount() const;
+ void setModel(const QVariant &);
+
+ QDeclarativeComponent *delegate() const;
+ void setDelegate(QDeclarativeComponent *);
+
+ int currentIndex() const;
+ void setCurrentIndex(int idx);
+
+ QSGItem *currentItem();
+ QSGItem *highlightItem();
+ int count() const;
+
+ QDeclarativeComponent *highlight() const;
+ void setHighlight(QDeclarativeComponent *highlight);
+
+ bool highlightFollowsCurrentItem() const;
+ void setHighlightFollowsCurrentItem(bool);
+
+ int highlightMoveDuration() const;
+ void setHighlightMoveDuration(int);
+
+ enum HighlightRangeMode { NoHighlightRange, ApplyRange, StrictlyEnforceRange };
+ HighlightRangeMode highlightRangeMode() const;
+ void setHighlightRangeMode(HighlightRangeMode mode);
+
+ qreal preferredHighlightBegin() const;
+ void setPreferredHighlightBegin(qreal);
+ void resetPreferredHighlightBegin();
+
+ qreal preferredHighlightEnd() const;
+ void setPreferredHighlightEnd(qreal);
+ void resetPreferredHighlightEnd();
+
+ Qt::LayoutDirection layoutDirection() const;
+ void setLayoutDirection(Qt::LayoutDirection);
+ Qt::LayoutDirection effectiveLayoutDirection() const;
+
+ enum Flow { LeftToRight, TopToBottom };
+ Flow flow() const;
+ void setFlow(Flow);
+
+ bool isWrapEnabled() const;
+ void setWrapEnabled(bool);
+
+ int cacheBuffer() const;
+ void setCacheBuffer(int);
+
+ int cellWidth() const;
+ void setCellWidth(int);
+
+ int cellHeight() const;
+ void setCellHeight(int);
+
+ enum SnapMode { NoSnap, SnapToRow, SnapOneRow };
+ SnapMode snapMode() const;
+ void setSnapMode(SnapMode mode);
+
+ QDeclarativeComponent *footer() const;
+ void setFooter(QDeclarativeComponent *);
+
+ QDeclarativeComponent *header() const;
+ void setHeader(QDeclarativeComponent *);
+
+ virtual void setContentX(qreal pos);
+ virtual void setContentY(qreal pos);
+
+ enum PositionMode { Beginning, Center, End, Visible, Contain };
+
+ Q_INVOKABLE void positionViewAtIndex(int index, int mode);
+ Q_INVOKABLE int indexAt(qreal x, qreal y) const;
+ Q_INVOKABLE void positionViewAtBeginning();
+ Q_INVOKABLE void positionViewAtEnd();
+
+ static QSGGridViewAttached *qmlAttachedProperties(QObject *);
+
+public Q_SLOTS:
+ void moveCurrentIndexUp();
+ void moveCurrentIndexDown();
+ void moveCurrentIndexLeft();
+ void moveCurrentIndexRight();
+
+Q_SIGNALS:
+ void countChanged();
+ void currentIndexChanged();
+ void cellWidthChanged();
+ void cellHeightChanged();
+ void highlightChanged();
+ void highlightItemChanged();
+ void preferredHighlightBeginChanged();
+ void preferredHighlightEndChanged();
+ void highlightRangeModeChanged();
+ void highlightMoveDurationChanged();
+ void modelChanged();
+ void delegateChanged();
+ void flowChanged();
+ void layoutDirectionChanged();
+ void effectiveLayoutDirectionChanged();
+ void keyNavigationWrapsChanged();
+ void cacheBufferChanged();
+ void snapModeChanged();
+ void headerChanged();
+ void footerChanged();
+
+protected:
+ virtual void updatePolish();
+ virtual void viewportMoved();
+ virtual qreal minYExtent() const;
+ virtual qreal maxYExtent() const;
+ virtual qreal minXExtent() const;
+ virtual qreal maxXExtent() const;
+ virtual void keyPressEvent(QKeyEvent *);
+ virtual void componentComplete();
+
+private Q_SLOTS:
+ void trackedPositionChanged();
+ void itemsInserted(int index, int count);
+ void itemsRemoved(int index, int count);
+ void itemsMoved(int from, int to, int count);
+ void modelReset();
+ void destroyRemoved();
+ void createdItem(int index, QSGItem *item);
+ void destroyingItem(QSGItem *item);
+ void animStopped();
+
+private:
+ void refill();
+};
+
+class QSGGridViewAttached : public QObject
+{
+ Q_OBJECT
+public:
+ QSGGridViewAttached(QObject *parent)
+ : QObject(parent), m_view(0), m_isCurrent(false), m_delayRemove(false) {}
+ ~QSGGridViewAttached() {}
+
+ Q_PROPERTY(QSGGridView *view READ view NOTIFY viewChanged)
+ QSGGridView *view() { return m_view; }
+ void setView(QSGGridView *view) {
+ if (view != m_view) {
+ m_view = view;
+ emit viewChanged();
+ }
+ }
+
+ Q_PROPERTY(bool isCurrentItem READ isCurrentItem NOTIFY currentItemChanged)
+ bool isCurrentItem() const { return m_isCurrent; }
+ void setIsCurrentItem(bool c) {
+ if (m_isCurrent != c) {
+ m_isCurrent = c;
+ emit currentItemChanged();
+ }
+ }
+
+ Q_PROPERTY(bool delayRemove READ delayRemove WRITE setDelayRemove NOTIFY delayRemoveChanged)
+ bool delayRemove() const { return m_delayRemove; }
+ void setDelayRemove(bool delay) {
+ if (m_delayRemove != delay) {
+ m_delayRemove = delay;
+ emit delayRemoveChanged();
+ }
+ }
+
+ void emitAdd() { emit add(); }
+ void emitRemove() { emit remove(); }
+
+Q_SIGNALS:
+ void currentItemChanged();
+ void delayRemoveChanged();
+ void add();
+ void remove();
+ void viewChanged();
+
+public:
+ QDeclarativeGuard<QSGGridView> m_view;
+ bool m_isCurrent : 1;
+ bool m_delayRemove : 1;
+};
+
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QSGGridView)
+QML_DECLARE_TYPEINFO(QSGGridView, QML_HAS_ATTACHED_PROPERTIES)
+
+QT_END_HEADER
+
+#endif // QSGGRIDVIEW_P_H
diff --git a/src/declarative/items/qsgimage.cpp b/src/declarative/items/qsgimage.cpp
new file mode 100644
index 0000000000..706aaa7d5d
--- /dev/null
+++ b/src/declarative/items/qsgimage.cpp
@@ -0,0 +1,306 @@
+// Commit: 051a76c1d65d698f71dc75c89f91ae9021357eae
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgimage_p.h"
+#include "qsgimage_p_p.h"
+
+#include <private/qsgcontext_p.h>
+#include <private/qsgadaptationlayer_p.h>
+
+#include <QtGui/qpainter.h>
+
+QT_BEGIN_NAMESPACE
+
+QSGImagePrivate::QSGImagePrivate()
+ : fillMode(QSGImage::Stretch)
+ , paintedWidth(0)
+ , paintedHeight(0)
+ , pixmapChanged(false)
+{
+}
+
+QSGImage::QSGImage(QSGItem *parent)
+ : QSGImageBase(*(new QSGImagePrivate), parent)
+{
+}
+
+QSGImage::QSGImage(QSGImagePrivate &dd, QSGItem *parent)
+ : QSGImageBase(dd, parent)
+{
+}
+
+QSGImage::~QSGImage()
+{
+}
+
+void QSGImagePrivate::setPixmap(const QPixmap &pixmap)
+{
+ Q_Q(QSGImage);
+ pix.setPixmap(pixmap);
+
+ q->pixmapChange();
+ status = pix.isNull() ? QSGImageBase::Null : QSGImageBase::Ready;
+
+ q->update();
+}
+
+QSGImage::FillMode QSGImage::fillMode() const
+{
+ Q_D(const QSGImage);
+ return d->fillMode;
+}
+
+void QSGImage::setFillMode(FillMode mode)
+{
+ Q_D(QSGImage);
+ if (d->fillMode == mode)
+ return;
+ d->fillMode = mode;
+ update();
+ updatePaintedGeometry();
+ emit fillModeChanged();
+}
+
+qreal QSGImage::paintedWidth() const
+{
+ Q_D(const QSGImage);
+ return d->paintedWidth;
+}
+
+qreal QSGImage::paintedHeight() const
+{
+ Q_D(const QSGImage);
+ return d->paintedHeight;
+}
+
+void QSGImage::updatePaintedGeometry()
+{
+ Q_D(QSGImage);
+
+ if (d->fillMode == PreserveAspectFit) {
+ if (!d->pix.width() || !d->pix.height()) {
+ setImplicitWidth(0);
+ setImplicitHeight(0);
+ return;
+ }
+ qreal w = widthValid() ? width() : d->pix.width();
+ qreal widthScale = w / qreal(d->pix.width());
+ qreal h = heightValid() ? height() : d->pix.height();
+ qreal heightScale = h / qreal(d->pix.height());
+ if (widthScale <= heightScale) {
+ d->paintedWidth = w;
+ d->paintedHeight = widthScale * qreal(d->pix.height());
+ } else if(heightScale < widthScale) {
+ d->paintedWidth = heightScale * qreal(d->pix.width());
+ d->paintedHeight = h;
+ }
+ if (widthValid() && !heightValid()) {
+ setImplicitHeight(d->paintedHeight);
+ } else {
+ setImplicitHeight(d->pix.height());
+ }
+ if (heightValid() && !widthValid()) {
+ setImplicitWidth(d->paintedWidth);
+ } else {
+ setImplicitWidth(d->pix.width());
+ }
+ } else if (d->fillMode == PreserveAspectCrop) {
+ if (!d->pix.width() || !d->pix.height())
+ return;
+ qreal widthScale = width() / qreal(d->pix.width());
+ qreal heightScale = height() / qreal(d->pix.height());
+ if (widthScale < heightScale) {
+ widthScale = heightScale;
+ } else if(heightScale < widthScale) {
+ heightScale = widthScale;
+ }
+
+ d->paintedHeight = heightScale * qreal(d->pix.height());
+ d->paintedWidth = widthScale * qreal(d->pix.width());
+ } else {
+ d->paintedWidth = width();
+ d->paintedHeight = height();
+ }
+ emit paintedGeometryChanged();
+}
+
+void QSGImage::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
+{
+ QSGImageBase::geometryChanged(newGeometry, oldGeometry);
+ updatePaintedGeometry();
+}
+
+QRectF QSGImage::boundingRect() const
+{
+ Q_D(const QSGImage);
+ return QRectF(0, 0, qMax(width(), d->paintedWidth), qMax(height(), d->paintedHeight));
+}
+
+QSGTexture *QSGImage::texture() const
+{
+ Q_D(const QSGImage);
+ QSGTexture *t = d->pix.texture(d->sceneGraphContext());
+ if (t) {
+ t->setFiltering(QSGItemPrivate::get(this)->smooth ? QSGTexture::Linear : QSGTexture::Nearest);
+ t->setMipmapFiltering(QSGTexture::None);
+ t->setHorizontalWrapMode(QSGTexture::ClampToEdge);
+ t->setVerticalWrapMode(QSGTexture::ClampToEdge);
+ }
+ return t;
+}
+
+QSGNode *QSGImage::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
+{
+ Q_D(QSGImage);
+
+ QSGTexture *texture = d->pix.texture(d->sceneGraphContext());
+
+ if (!texture || width() <= 0 || height() <= 0) {
+ delete oldNode;
+ return 0;
+ }
+
+ QSGImageNode *node = static_cast<QSGImageNode *>(oldNode);
+ if (!node) {
+ d->pixmapChanged = true;
+ node = d->sceneGraphContext()->createImageNode();
+ node->setTexture(texture);
+ }
+
+ if (d->pixmapChanged) {
+ // force update the texture in the node to trigger reconstruction of
+ // geometry and the likes when a atlas segment has changed.
+ node->setTexture(0);
+ node->setTexture(texture);
+ d->pixmapChanged = false;
+ }
+
+ QRectF targetRect;
+ QRectF sourceRect;
+ QSGTexture::WrapMode hWrap = QSGTexture::ClampToEdge;
+ QSGTexture::WrapMode vWrap = QSGTexture::ClampToEdge;
+
+ switch (d->fillMode) {
+ default:
+ case Stretch:
+ targetRect = QRectF(0, 0, width(), height());
+ sourceRect = d->pix.rect();
+ break;
+
+ case PreserveAspectFit:
+ targetRect = QRectF((width() - d->paintedWidth) / 2., (height() - d->paintedHeight) / 2.,
+ d->paintedWidth, d->paintedHeight);
+ sourceRect = d->pix.rect();
+ break;
+
+ case PreserveAspectCrop: {
+ targetRect = QRect(0, 0, width(), height());
+ qreal wscale = width() / qreal(d->pix.width());
+ qreal hscale = height() / qreal(d->pix.height());
+
+ if (wscale > hscale) {
+ int src = (hscale / wscale) * qreal(d->pix.height());
+ sourceRect = QRectF(0, (d->pix.height() - src) / 2, d->pix.width(), src);
+ } else {
+ int src = (wscale / hscale) * qreal(d->pix.width());
+ sourceRect = QRectF((d->pix.width() - src) / 2, 0, src, d->pix.height());
+ }
+ }
+ break;
+
+ case Tile:
+ targetRect = QRectF(0, 0, width(), height());
+ sourceRect = QRectF(0, 0, width(), height());
+ hWrap = QSGTexture::Repeat;
+ vWrap = QSGTexture::Repeat;
+ break;
+
+ case TileHorizontally:
+ targetRect = QRectF(0, 0, width(), height());
+ sourceRect = QRectF(0, 0, width(), d->pix.height());
+ hWrap = QSGTexture::Repeat;
+ break;
+
+ case TileVertically:
+ targetRect = QRectF(0, 0, width(), height());
+ sourceRect = QRectF(0, 0, d->pix.width(), height());
+ vWrap = QSGTexture::Repeat;
+ break;
+
+ };
+
+ QRectF nsrect(sourceRect.x() / d->pix.width(),
+ sourceRect.y() / d->pix.height(),
+ sourceRect.width() / d->pix.width(),
+ sourceRect.height() / d->pix.height());
+
+ if (d->mirror) {
+ qreal oldLeft = nsrect.left();
+ nsrect.setLeft(nsrect.right());
+ nsrect.setRight(oldLeft);
+ }
+
+ node->setHorizontalWrapMode(hWrap);
+ node->setVerticalWrapMode(vWrap);
+ node->setFiltering(d->smooth ? QSGTexture::Linear : QSGTexture::Nearest);
+
+ node->setTargetRect(targetRect);
+ node->setSourceRect(nsrect);
+ node->update();
+
+ return node;
+}
+
+void QSGImage::pixmapChange()
+{
+ Q_D(QSGImage);
+ // PreserveAspectFit calculates the implicit size differently so we
+ // don't call our superclass pixmapChange(), since that would
+ // result in the implicit size being set incorrectly, then updated
+ // in updatePaintedGeometry()
+ if (d->fillMode != PreserveAspectFit)
+ QSGImageBase::pixmapChange();
+ updatePaintedGeometry();
+ d->pixmapChanged = true;
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/items/qsgimage_p.h b/src/declarative/items/qsgimage_p.h
new file mode 100644
index 0000000000..aad63d42c0
--- /dev/null
+++ b/src/declarative/items/qsgimage_p.h
@@ -0,0 +1,104 @@
+// Commit: ac5c099cc3c5b8c7eec7a49fdeb8a21037230350
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGIMAGE_P_H
+#define QSGIMAGE_P_H
+
+#include "qsgimagebase_p.h"
+#include <private/qsgtextureprovider_p.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QSGImagePrivate;
+class Q_AUTOTEST_EXPORT QSGImage : public QSGImageBase, public QSGTextureProvider
+{
+ Q_OBJECT
+ Q_ENUMS(FillMode)
+
+ Q_PROPERTY(FillMode fillMode READ fillMode WRITE setFillMode NOTIFY fillModeChanged)
+ Q_PROPERTY(qreal paintedWidth READ paintedWidth NOTIFY paintedGeometryChanged)
+ Q_PROPERTY(qreal paintedHeight READ paintedHeight NOTIFY paintedGeometryChanged)
+ Q_PROPERTY(QSGTexture *texture READ texture)
+
+ Q_INTERFACES(QSGTextureProvider)
+
+public:
+ QSGImage(QSGItem *parent=0);
+ ~QSGImage();
+
+ enum FillMode { Stretch, PreserveAspectFit, PreserveAspectCrop, Tile, TileVertically, TileHorizontally };
+ FillMode fillMode() const;
+ void setFillMode(FillMode);
+
+ qreal paintedWidth() const;
+ qreal paintedHeight() const;
+
+ QRectF boundingRect() const;
+
+ virtual QSGTexture *texture() const;
+
+Q_SIGNALS:
+ void fillModeChanged();
+ void paintedGeometryChanged();
+
+protected:
+ QSGImage(QSGImagePrivate &dd, QSGItem *parent);
+ void pixmapChange();
+ void updatePaintedGeometry();
+
+ virtual void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry);
+ virtual QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *);
+
+private:
+ Q_DISABLE_COPY(QSGImage)
+ Q_DECLARE_PRIVATE(QSGImage)
+};
+
+QT_END_NAMESPACE
+QML_DECLARE_TYPE(QSGImage)
+QT_END_HEADER
+
+#endif // QSGIMAGE_P_H
diff --git a/src/declarative/items/qsgimage_p_p.h b/src/declarative/items/qsgimage_p_p.h
new file mode 100644
index 0000000000..01b549df1f
--- /dev/null
+++ b/src/declarative/items/qsgimage_p_p.h
@@ -0,0 +1,81 @@
+// Commit: ac5c099cc3c5b8c7eec7a49fdeb8a21037230350
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGIMAGE_P_P_H
+#define QSGIMAGE_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 "qsgimagebase_p_p.h"
+#include "qsgimage_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QSGImagePrivate;
+
+class QSGImagePrivate : public QSGImageBasePrivate
+{
+ Q_DECLARE_PUBLIC(QSGImage)
+
+public:
+ QSGImagePrivate();
+
+ QSGImage::FillMode fillMode;
+ qreal paintedWidth;
+ qreal paintedHeight;
+ void setPixmap(const QPixmap &pix);
+
+ bool pixmapChanged : 1;
+};
+
+QT_END_NAMESPACE
+
+#endif // QSGIMAGE_P_P_H
diff --git a/src/declarative/items/qsgimagebase.cpp b/src/declarative/items/qsgimagebase.cpp
new file mode 100644
index 0000000000..9f2de03bbe
--- /dev/null
+++ b/src/declarative/items/qsgimagebase.cpp
@@ -0,0 +1,285 @@
+// Commit: 051a76c1d65d698f71dc75c89f91ae9021357eae
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgimagebase_p.h"
+#include "qsgimagebase_p_p.h"
+
+#include <QtDeclarative/qdeclarativeinfo.h>
+
+QT_BEGIN_NAMESPACE
+
+QSGImageBase::QSGImageBase(QSGItem *parent)
+: QSGImplicitSizeItem(*(new QSGImageBasePrivate), parent)
+{
+ setFlag(ItemHasContents);
+}
+
+QSGImageBase::QSGImageBase(QSGImageBasePrivate &dd, QSGItem *parent)
+: QSGImplicitSizeItem(dd, parent)
+{
+ setFlag(ItemHasContents);
+}
+
+QSGImageBase::~QSGImageBase()
+{
+}
+
+QSGImageBase::Status QSGImageBase::status() const
+{
+ Q_D(const QSGImageBase);
+ return d->status;
+}
+
+
+qreal QSGImageBase::progress() const
+{
+ Q_D(const QSGImageBase);
+ return d->progress;
+}
+
+
+bool QSGImageBase::asynchronous() const
+{
+ Q_D(const QSGImageBase);
+ return d->async;
+}
+
+void QSGImageBase::setAsynchronous(bool async)
+{
+ Q_D(QSGImageBase);
+ if (d->async != async) {
+ d->async = async;
+ emit asynchronousChanged();
+ }
+}
+
+QUrl QSGImageBase::source() const
+{
+ Q_D(const QSGImageBase);
+ return d->url;
+}
+
+void QSGImageBase::setSource(const QUrl &url)
+{
+ Q_D(QSGImageBase);
+ //equality is fairly expensive, so we bypass for simple, common case
+ if ((d->url.isEmpty() == url.isEmpty()) && url == d->url)
+ return;
+
+ d->url = url;
+ emit sourceChanged(d->url);
+
+ if (isComponentComplete())
+ load();
+}
+
+void QSGImageBase::setSourceSize(const QSize& size)
+{
+ Q_D(QSGImageBase);
+ if (d->sourcesize == size)
+ return;
+
+ d->sourcesize = size;
+ d->explicitSourceSize = true;
+ emit sourceSizeChanged();
+ if (isComponentComplete())
+ load();
+}
+
+QSize QSGImageBase::sourceSize() const
+{
+ Q_D(const QSGImageBase);
+
+ int width = d->sourcesize.width();
+ int height = d->sourcesize.height();
+ return QSize(width != -1 ? width : d->pix.width(), height != -1 ? height : d->pix.height());
+}
+
+void QSGImageBase::resetSourceSize()
+{
+ Q_D(QSGImageBase);
+ if (!d->explicitSourceSize)
+ return;
+ d->explicitSourceSize = false;
+ d->sourcesize = QSize();
+ emit sourceSizeChanged();
+ if (isComponentComplete())
+ load();
+}
+
+bool QSGImageBase::cache() const
+{
+ Q_D(const QSGImageBase);
+ return d->cache;
+}
+
+void QSGImageBase::setCache(bool cache)
+{
+ Q_D(QSGImageBase);
+ if (d->cache == cache)
+ return;
+
+ d->cache = cache;
+ emit cacheChanged();
+ if (isComponentComplete())
+ load();
+}
+
+void QSGImageBase::setMirror(bool mirror)
+{
+ Q_D(QSGImageBase);
+ if (mirror == d->mirror)
+ return;
+
+ d->mirror = mirror;
+
+ if (isComponentComplete())
+ update();
+
+ emit mirrorChanged();
+}
+
+bool QSGImageBase::mirror() const
+{
+ Q_D(const QSGImageBase);
+ return d->mirror;
+}
+
+void QSGImageBase::load()
+{
+ Q_D(QSGImageBase);
+
+ if (d->url.isEmpty()) {
+ d->pix.clear(this);
+ d->status = Null;
+ d->progress = 0.0;
+ pixmapChange();
+ emit progressChanged(d->progress);
+ emit statusChanged(d->status);
+ update();
+ } else {
+ QDeclarativePixmap::Options options;
+ if (d->async)
+ options |= QDeclarativePixmap::Asynchronous;
+ if (d->cache)
+ options |= QDeclarativePixmap::Cache;
+ d->pix.clear(this);
+ d->pix.load(qmlEngine(this), d->url, d->explicitSourceSize ? sourceSize() : QSize(), options);
+
+ if (d->pix.isLoading()) {
+ d->progress = 0.0;
+ d->status = Loading;
+ emit progressChanged(d->progress);
+ emit statusChanged(d->status);
+
+ static int thisRequestProgress = -1;
+ static int thisRequestFinished = -1;
+ if (thisRequestProgress == -1) {
+ thisRequestProgress =
+ QSGImageBase::staticMetaObject.indexOfSlot("requestProgress(qint64,qint64)");
+ thisRequestFinished =
+ QSGImageBase::staticMetaObject.indexOfSlot("requestFinished()");
+ }
+
+ d->pix.connectFinished(this, thisRequestFinished);
+ d->pix.connectDownloadProgress(this, thisRequestProgress);
+
+ } else {
+ requestFinished();
+ }
+ }
+}
+
+void QSGImageBase::requestFinished()
+{
+ Q_D(QSGImageBase);
+
+ QSGImageBase::Status oldStatus = d->status;
+ qreal oldProgress = d->progress;
+
+ if (d->pix.isError()) {
+ d->status = Error;
+ qmlInfo(this) << d->pix.error();
+ } else {
+ d->status = Ready;
+ }
+
+ d->progress = 1.0;
+
+ pixmapChange();
+
+ if (d->sourcesize.width() != d->pix.width() || d->sourcesize.height() != d->pix.height())
+ emit sourceSizeChanged();
+
+ if (d->status != oldStatus)
+ emit statusChanged(d->status);
+ if (d->progress != oldProgress)
+ emit progressChanged(d->progress);
+
+ update();
+}
+
+void QSGImageBase::requestProgress(qint64 received, qint64 total)
+{
+ Q_D(QSGImageBase);
+ if (d->status == Loading && total > 0) {
+ d->progress = qreal(received)/total;
+ emit progressChanged(d->progress);
+ }
+}
+
+void QSGImageBase::componentComplete()
+{
+ Q_D(QSGImageBase);
+ QSGItem::componentComplete();
+ if (d->url.isValid())
+ load();
+}
+
+void QSGImageBase::pixmapChange()
+{
+ Q_D(QSGImageBase);
+ setImplicitWidth(d->pix.width());
+ setImplicitHeight(d->pix.height());
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/items/qsgimagebase_p.h b/src/declarative/items/qsgimagebase_p.h
new file mode 100644
index 0000000000..00b14525f2
--- /dev/null
+++ b/src/declarative/items/qsgimagebase_p.h
@@ -0,0 +1,117 @@
+// Commit: af05f64d3edc860c3cf79c7f0bdf2377faae5f40
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGIMAGEBASE_P_H
+#define QSGIMAGEBASE_P_H
+
+#include "qsgimplicitsizeitem_p.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class QSGImageBasePrivate;
+class Q_AUTOTEST_EXPORT QSGImageBase : public QSGImplicitSizeItem
+{
+ Q_OBJECT
+ Q_ENUMS(Status)
+
+ Q_PROPERTY(Status status READ status NOTIFY statusChanged)
+ Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged)
+ Q_PROPERTY(qreal progress READ progress NOTIFY progressChanged)
+ Q_PROPERTY(bool asynchronous READ asynchronous WRITE setAsynchronous NOTIFY asynchronousChanged)
+ Q_PROPERTY(bool cache READ cache WRITE setCache NOTIFY cacheChanged)
+ Q_PROPERTY(QSize sourceSize READ sourceSize WRITE setSourceSize RESET resetSourceSize NOTIFY sourceSizeChanged)
+ Q_PROPERTY(bool mirror READ mirror WRITE setMirror NOTIFY mirrorChanged)
+
+public:
+ QSGImageBase(QSGItem *parent=0);
+ ~QSGImageBase();
+ enum Status { Null, Ready, Loading, Error };
+ Status status() const;
+ qreal progress() const;
+
+ QUrl source() const;
+ virtual void setSource(const QUrl &url);
+
+ bool asynchronous() const;
+ void setAsynchronous(bool);
+
+ bool cache() const;
+ void setCache(bool);
+
+ virtual void setSourceSize(const QSize&);
+ QSize sourceSize() const;
+ void resetSourceSize();
+
+ virtual void setMirror(bool mirror);
+ bool mirror() const;
+
+Q_SIGNALS:
+ void sourceChanged(const QUrl &);
+ void sourceSizeChanged();
+ void statusChanged(QSGImageBase::Status);
+ void progressChanged(qreal progress);
+ void asynchronousChanged();
+ void cacheChanged();
+ void mirrorChanged();
+
+protected:
+ virtual void load();
+ virtual void componentComplete();
+ virtual void pixmapChange();
+ QSGImageBase(QSGImageBasePrivate &dd, QSGItem *parent);
+
+private Q_SLOTS:
+ virtual void requestFinished();
+ void requestProgress(qint64,qint64);
+
+private:
+ Q_DISABLE_COPY(QSGImageBase)
+ Q_DECLARE_PRIVATE(QSGImageBase)
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QSGIMAGEBASE_P_H
diff --git a/src/declarative/items/qsgimagebase_p_p.h b/src/declarative/items/qsgimagebase_p_p.h
new file mode 100644
index 0000000000..8c67b41e8b
--- /dev/null
+++ b/src/declarative/items/qsgimagebase_p_p.h
@@ -0,0 +1,93 @@
+// Commit: 6f78a6080b84cc3ef96b73a4ff58d1b5a72f08f4
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGIMAGEBASE_P_P_H
+#define QSGIMAGEBASE_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 "qsgimplicitsizeitem_p_p.h"
+#include "qsgimagebase_p.h"
+
+#include <private/qdeclarativepixmapcache_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QNetworkReply;
+class QSGImageBasePrivate : public QSGImplicitSizeItemPrivate
+{
+ Q_DECLARE_PUBLIC(QSGImageBase)
+
+public:
+ QSGImageBasePrivate()
+ : status(QSGImageBase::Null),
+ progress(0.0),
+ explicitSourceSize(false),
+ async(false),
+ cache(true),
+ mirror(false)
+ {
+ }
+
+ QDeclarativePixmap pix;
+ QSGImageBase::Status status;
+ QUrl url;
+ qreal progress;
+ QSize sourcesize;
+ bool explicitSourceSize : 1;
+ bool async : 1;
+ bool cache : 1;
+ bool mirror: 1;
+};
+
+QT_END_NAMESPACE
+
+#endif // QSGIMAGEBASE_P_P_H
diff --git a/src/declarative/items/qsgimplicitsizeitem.cpp b/src/declarative/items/qsgimplicitsizeitem.cpp
new file mode 100644
index 0000000000..f2cc9bcbdb
--- /dev/null
+++ b/src/declarative/items/qsgimplicitsizeitem.cpp
@@ -0,0 +1,93 @@
+// Commit: 6f78a6080b84cc3ef96b73a4ff58d1b5a72f08f4
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "private/qsgimplicitsizeitem_p.h"
+#include "private/qsgimplicitsizeitem_p_p.h"
+
+QT_BEGIN_NAMESPACE
+
+void QSGImplicitSizeItemPrivate::implicitWidthChanged()
+{
+ Q_Q(QSGImplicitSizeItem);
+ emit q->implicitWidthChanged();
+}
+
+void QSGImplicitSizeItemPrivate::implicitHeightChanged()
+{
+ Q_Q(QSGImplicitSizeItem);
+ emit q->implicitHeightChanged();
+}
+
+QSGImplicitSizeItem::QSGImplicitSizeItem(QSGItem *parent)
+ : QSGItem(*(new QSGImplicitSizeItemPrivate), parent)
+{
+}
+
+QSGImplicitSizeItem::QSGImplicitSizeItem(QSGImplicitSizeItemPrivate &dd, QSGItem *parent)
+ : QSGItem(dd, parent)
+{
+}
+
+
+void QSGImplicitSizePaintedItemPrivate::implicitWidthChanged()
+{
+ Q_Q(QSGImplicitSizePaintedItem);
+ emit q->implicitWidthChanged();
+}
+
+void QSGImplicitSizePaintedItemPrivate::implicitHeightChanged()
+{
+ Q_Q(QSGImplicitSizePaintedItem);
+ emit q->implicitHeightChanged();
+}
+
+QSGImplicitSizePaintedItem::QSGImplicitSizePaintedItem(QSGItem *parent)
+ : QSGPaintedItem(*(new QSGImplicitSizePaintedItemPrivate), parent)
+{
+}
+
+QSGImplicitSizePaintedItem::QSGImplicitSizePaintedItem(QSGImplicitSizePaintedItemPrivate &dd, QSGItem *parent)
+ : QSGPaintedItem(dd, parent)
+{
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/items/qsgimplicitsizeitem_p.h b/src/declarative/items/qsgimplicitsizeitem_p.h
new file mode 100644
index 0000000000..36ef0e7f8b
--- /dev/null
+++ b/src/declarative/items/qsgimplicitsizeitem_p.h
@@ -0,0 +1,101 @@
+// Commit: 6f78a6080b84cc3ef96b73a4ff58d1b5a72f08f4
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGIMPLICITSIZEITEM_H
+#define QSGIMPLICITSIZEITEM_H
+
+#include "qsgpainteditem.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class QSGImplicitSizeItemPrivate;
+class Q_AUTOTEST_EXPORT QSGImplicitSizeItem : public QSGItem
+{
+ Q_OBJECT
+ Q_PROPERTY(qreal implicitWidth READ implicitWidth NOTIFY implicitWidthChanged)
+ Q_PROPERTY(qreal implicitHeight READ implicitHeight NOTIFY implicitHeightChanged)
+
+public:
+ QSGImplicitSizeItem(QSGItem *parent = 0);
+
+protected:
+ QSGImplicitSizeItem(QSGImplicitSizeItemPrivate &dd, QSGItem *parent);
+
+Q_SIGNALS:
+ void implicitWidthChanged();
+ void implicitHeightChanged();
+
+private:
+ Q_DISABLE_COPY(QSGImplicitSizeItem)
+ Q_DECLARE_PRIVATE(QSGImplicitSizeItem)
+};
+
+class QSGImplicitSizePaintedItemPrivate;
+class Q_AUTOTEST_EXPORT QSGImplicitSizePaintedItem : public QSGPaintedItem
+{
+ Q_OBJECT
+ Q_PROPERTY(qreal implicitWidth READ implicitWidth NOTIFY implicitWidthChanged)
+ Q_PROPERTY(qreal implicitHeight READ implicitHeight NOTIFY implicitHeightChanged)
+
+public:
+ QSGImplicitSizePaintedItem(QSGItem *parent = 0);
+
+protected:
+ QSGImplicitSizePaintedItem(QSGImplicitSizePaintedItemPrivate &dd, QSGItem *parent);
+ virtual void drawContents(QPainter *, const QRect &) {};
+
+Q_SIGNALS:
+ void implicitWidthChanged();
+ void implicitHeightChanged();
+
+private:
+ Q_DISABLE_COPY(QSGImplicitSizePaintedItem)
+ Q_DECLARE_PRIVATE(QSGImplicitSizePaintedItem)
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QSGIMPLICITSIZEITEM_H
diff --git a/src/declarative/items/qsgimplicitsizeitem_p_p.h b/src/declarative/items/qsgimplicitsizeitem_p_p.h
new file mode 100644
index 0000000000..f67ecfab9f
--- /dev/null
+++ b/src/declarative/items/qsgimplicitsizeitem_p_p.h
@@ -0,0 +1,92 @@
+// Commit: 6f78a6080b84cc3ef96b73a4ff58d1b5a72f08f4
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGIMPLICITSIZEITEM_P_H
+#define QSGIMPLICITSIZEITEM_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/qsgitem_p.h"
+#include "private/qsgpainteditem_p.h"
+#include "private/qsgimplicitsizeitem_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QSGImplicitSizeItemPrivate : public QSGItemPrivate
+{
+ Q_DECLARE_PUBLIC(QSGImplicitSizeItem)
+
+public:
+ QSGImplicitSizeItemPrivate()
+ {
+ }
+
+ virtual void implicitWidthChanged();
+ virtual void implicitHeightChanged();
+};
+
+
+class QSGImplicitSizePaintedItemPrivate : public QSGPaintedItemPrivate
+{
+ Q_DECLARE_PUBLIC(QSGImplicitSizePaintedItem)
+
+public:
+ QSGImplicitSizePaintedItemPrivate()
+ {
+ }
+
+ virtual void implicitWidthChanged();
+ virtual void implicitHeightChanged();
+};
+
+QT_END_NAMESPACE
+
+#endif // QSGIMPLICITSIZEITEM_P_H
diff --git a/src/declarative/items/qsgitem.cpp b/src/declarative/items/qsgitem.cpp
new file mode 100644
index 0000000000..f2d26955aa
--- /dev/null
+++ b/src/declarative/items/qsgitem.cpp
@@ -0,0 +1,3143 @@
+// Commit: c44be8c0b27756a2025ebad1945632f3f7e4bebc
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgitem.h"
+
+#include "qsgcanvas.h"
+#include <QtScript/qscriptengine.h>
+#include "qsgcanvas_p.h"
+
+#include "qsgevents_p_p.h"
+
+#include <QtDeclarative/qdeclarativeitem.h>
+#include <QtDeclarative/qdeclarativeengine.h>
+#include <QtDeclarative/qdeclarativeview.h>
+#include <QtDeclarative/qdeclarativecomponent.h>
+#include <QtDeclarative/qdeclarativeinfo.h>
+#include <QtGui/qgraphicstransform.h>
+#include <QtGui/qpen.h>
+#include <QtGui/qinputcontext.h>
+#include <QtCore/qdebug.h>
+#include <QtCore/qcoreevent.h>
+#include <QtCore/qnumeric.h>
+
+#include <private/qdeclarativeengine_p.h>
+#include <private/qdeclarativestategroup_p.h>
+#include <private/qdeclarativeopenmetaobject_p.h>
+#include <private/qdeclarativestate_p.h>
+#include <private/qlistmodelinterface_p.h>
+#include <private/qsgitem_p.h>
+
+#include <float.h>
+
+// XXX todo Readd parentNotifier for faster parent bindings
+// XXX todo Check that elements that create items handle memory correctly after visual ownership change
+
+QT_BEGIN_NAMESPACE
+
+QSGTransformPrivate::QSGTransformPrivate()
+{
+}
+
+QSGTransform::QSGTransform(QObject *parent)
+: QObject(*(new QSGTransformPrivate), parent)
+{
+}
+
+QSGTransform::QSGTransform(QSGTransformPrivate &dd, QObject *parent)
+: QObject(dd, parent)
+{
+}
+
+QSGTransform::~QSGTransform()
+{
+ Q_D(QSGTransform);
+ for (int ii = 0; ii < d->items.count(); ++ii) {
+ QSGItemPrivate *p = QSGItemPrivate::get(d->items.at(ii));
+ p->transforms.removeOne(this);
+ p->dirty(QSGItemPrivate::Transform);
+ }
+}
+
+void QSGTransform::update()
+{
+ Q_D(QSGTransform);
+ for (int ii = 0; ii < d->items.count(); ++ii) {
+ QSGItemPrivate *p = QSGItemPrivate::get(d->items.at(ii));
+ p->dirty(QSGItemPrivate::Transform);
+ }
+}
+
+QSGContents::QSGContents(QSGItem *item)
+: m_item(item), m_x(0), m_y(0), m_width(0), m_height(0)
+{
+ //### optimize
+ connect(this, SIGNAL(rectChanged(QRectF)), m_item, SIGNAL(childrenRectChanged(QRectF)));
+}
+
+QSGContents::~QSGContents()
+{
+ QList<QSGItem *> children = m_item->childItems();
+ for (int i = 0; i < children.count(); ++i) {
+ QSGItem *child = children.at(i);
+ QSGItemPrivate::get(child)->removeItemChangeListener(this, QSGItemPrivate::Geometry | QSGItemPrivate::Destroyed);
+ }
+}
+
+QRectF QSGContents::rectF() const
+{
+ return QRectF(m_x, m_y, m_width, m_height);
+}
+
+void QSGContents::calcHeight(QSGItem *changed)
+{
+ qreal oldy = m_y;
+ qreal oldheight = m_height;
+
+ if (changed) {
+ qreal top = oldy;
+ qreal bottom = oldy + oldheight;
+ qreal y = changed->y();
+ if (y + changed->height() > bottom)
+ bottom = y + changed->height();
+ if (y < top)
+ top = y;
+ m_y = top;
+ m_height = bottom - top;
+ } else {
+ qreal top = FLT_MAX;
+ qreal bottom = 0;
+ QList<QSGItem *> children = m_item->childItems();
+ for (int i = 0; i < children.count(); ++i) {
+ QSGItem *child = children.at(i);
+ qreal y = child->y();
+ if (y + child->height() > bottom)
+ bottom = y + child->height();
+ if (y < top)
+ top = y;
+ }
+ if (!children.isEmpty())
+ m_y = top;
+ m_height = qMax(bottom - top, qreal(0.0));
+ }
+
+ if (m_height != oldheight || m_y != oldy)
+ emit rectChanged(rectF());
+}
+
+void QSGContents::calcWidth(QSGItem *changed)
+{
+ qreal oldx = m_x;
+ qreal oldwidth = m_width;
+
+ if (changed) {
+ qreal left = oldx;
+ qreal right = oldx + oldwidth;
+ qreal x = changed->x();
+ if (x + changed->width() > right)
+ right = x + changed->width();
+ if (x < left)
+ left = x;
+ m_x = left;
+ m_width = right - left;
+ } else {
+ qreal left = FLT_MAX;
+ qreal right = 0;
+ QList<QSGItem *> children = m_item->childItems();
+ for (int i = 0; i < children.count(); ++i) {
+ QSGItem *child = children.at(i);
+ qreal x = child->x();
+ if (x + child->width() > right)
+ right = x + child->width();
+ if (x < left)
+ left = x;
+ }
+ if (!children.isEmpty())
+ m_x = left;
+ m_width = qMax(right - left, qreal(0.0));
+ }
+
+ if (m_width != oldwidth || m_x != oldx)
+ emit rectChanged(rectF());
+}
+
+void QSGContents::complete()
+{
+ QList<QSGItem *> children = m_item->childItems();
+ for (int i = 0; i < children.count(); ++i) {
+ QSGItem *child = children.at(i);
+ QSGItemPrivate::get(child)->addItemChangeListener(this, QSGItemPrivate::Geometry | QSGItemPrivate::Destroyed);
+ //###what about changes to visibility?
+ }
+
+ calcGeometry();
+}
+
+void QSGContents::itemGeometryChanged(QSGItem *changed, const QRectF &newGeometry, const QRectF &oldGeometry)
+{
+ Q_UNUSED(changed)
+ //### we can only pass changed if the left edge has moved left, or the right edge has moved right
+ if (newGeometry.width() != oldGeometry.width() || newGeometry.x() != oldGeometry.x())
+ calcWidth(/*changed*/);
+ if (newGeometry.height() != oldGeometry.height() || newGeometry.y() != oldGeometry.y())
+ calcHeight(/*changed*/);
+}
+
+void QSGContents::itemDestroyed(QSGItem *item)
+{
+ if (item)
+ QSGItemPrivate::get(item)->removeItemChangeListener(this, QSGItemPrivate::Geometry | QSGItemPrivate::Destroyed);
+ calcGeometry();
+}
+
+void QSGContents::childRemoved(QSGItem *item)
+{
+ if (item)
+ QSGItemPrivate::get(item)->removeItemChangeListener(this, QSGItemPrivate::Geometry | QSGItemPrivate::Destroyed);
+ calcGeometry();
+}
+
+void QSGContents::childAdded(QSGItem *item)
+{
+ if (item)
+ QSGItemPrivate::get(item)->addItemChangeListener(this, QSGItemPrivate::Geometry | QSGItemPrivate::Destroyed);
+ calcWidth(item);
+ calcHeight(item);
+}
+
+QSGItemKeyFilter::QSGItemKeyFilter(QSGItem *item)
+: m_processPost(false), m_next(0)
+{
+ QSGItemPrivate *p = item?QSGItemPrivate::get(item):0;
+ if (p) {
+ m_next = p->keyHandler;
+ p->keyHandler = this;
+ }
+}
+
+QSGItemKeyFilter::~QSGItemKeyFilter()
+{
+}
+
+void QSGItemKeyFilter::keyPressed(QKeyEvent *event, bool post)
+{
+ if (m_next) m_next->keyPressed(event, post);
+}
+
+void QSGItemKeyFilter::keyReleased(QKeyEvent *event, bool post)
+{
+ if (m_next) m_next->keyReleased(event, post);
+}
+
+void QSGItemKeyFilter::inputMethodEvent(QInputMethodEvent *event, bool post)
+{
+ if (m_next)
+ m_next->inputMethodEvent(event, post);
+ else
+ event->ignore();
+}
+
+QVariant QSGItemKeyFilter::inputMethodQuery(Qt::InputMethodQuery query) const
+{
+ if (m_next) return m_next->inputMethodQuery(query);
+ return QVariant();
+}
+
+void QSGItemKeyFilter::componentComplete()
+{
+ if (m_next) m_next->componentComplete();
+}
+
+QSGKeyNavigationAttached::QSGKeyNavigationAttached(QObject *parent)
+: QObject(*(new QSGKeyNavigationAttachedPrivate), parent),
+ QSGItemKeyFilter(qobject_cast<QSGItem*>(parent))
+{
+ m_processPost = true;
+}
+
+QSGKeyNavigationAttached *
+QSGKeyNavigationAttached::qmlAttachedProperties(QObject *obj)
+{
+ return new QSGKeyNavigationAttached(obj);
+}
+
+QSGItem *QSGKeyNavigationAttached::left() const
+{
+ Q_D(const QSGKeyNavigationAttached);
+ return d->left;
+}
+
+void QSGKeyNavigationAttached::setLeft(QSGItem *i)
+{
+ Q_D(QSGKeyNavigationAttached);
+ if (d->left == i)
+ return;
+ d->left = i;
+ d->leftSet = true;
+ QSGKeyNavigationAttached* other =
+ qobject_cast<QSGKeyNavigationAttached*>(qmlAttachedPropertiesObject<QSGKeyNavigationAttached>(i));
+ if (other && !other->d_func()->rightSet){
+ other->d_func()->right = qobject_cast<QSGItem*>(parent());
+ emit other->rightChanged();
+ }
+ emit leftChanged();
+}
+
+QSGItem *QSGKeyNavigationAttached::right() const
+{
+ Q_D(const QSGKeyNavigationAttached);
+ return d->right;
+}
+
+void QSGKeyNavigationAttached::setRight(QSGItem *i)
+{
+ Q_D(QSGKeyNavigationAttached);
+ if (d->right == i)
+ return;
+ d->right = i;
+ d->rightSet = true;
+ QSGKeyNavigationAttached* other =
+ qobject_cast<QSGKeyNavigationAttached*>(qmlAttachedPropertiesObject<QSGKeyNavigationAttached>(i));
+ if (other && !other->d_func()->leftSet){
+ other->d_func()->left = qobject_cast<QSGItem*>(parent());
+ emit other->leftChanged();
+ }
+ emit rightChanged();
+}
+
+QSGItem *QSGKeyNavigationAttached::up() const
+{
+ Q_D(const QSGKeyNavigationAttached);
+ return d->up;
+}
+
+void QSGKeyNavigationAttached::setUp(QSGItem *i)
+{
+ Q_D(QSGKeyNavigationAttached);
+ if (d->up == i)
+ return;
+ d->up = i;
+ d->upSet = true;
+ QSGKeyNavigationAttached* other =
+ qobject_cast<QSGKeyNavigationAttached*>(qmlAttachedPropertiesObject<QSGKeyNavigationAttached>(i));
+ if (other && !other->d_func()->downSet){
+ other->d_func()->down = qobject_cast<QSGItem*>(parent());
+ emit other->downChanged();
+ }
+ emit upChanged();
+}
+
+QSGItem *QSGKeyNavigationAttached::down() const
+{
+ Q_D(const QSGKeyNavigationAttached);
+ return d->down;
+}
+
+void QSGKeyNavigationAttached::setDown(QSGItem *i)
+{
+ Q_D(QSGKeyNavigationAttached);
+ if (d->down == i)
+ return;
+ d->down = i;
+ d->downSet = true;
+ QSGKeyNavigationAttached* other =
+ qobject_cast<QSGKeyNavigationAttached*>(qmlAttachedPropertiesObject<QSGKeyNavigationAttached>(i));
+ if(other && !other->d_func()->upSet){
+ other->d_func()->up = qobject_cast<QSGItem*>(parent());
+ emit other->upChanged();
+ }
+ emit downChanged();
+}
+
+QSGItem *QSGKeyNavigationAttached::tab() const
+{
+ Q_D(const QSGKeyNavigationAttached);
+ return d->tab;
+}
+
+void QSGKeyNavigationAttached::setTab(QSGItem *i)
+{
+ Q_D(QSGKeyNavigationAttached);
+ if (d->tab == i)
+ return;
+ d->tab = i;
+ d->tabSet = true;
+ QSGKeyNavigationAttached* other =
+ qobject_cast<QSGKeyNavigationAttached*>(qmlAttachedPropertiesObject<QSGKeyNavigationAttached>(i));
+ if(other && !other->d_func()->backtabSet){
+ other->d_func()->backtab = qobject_cast<QSGItem*>(parent());
+ emit other->backtabChanged();
+ }
+ emit tabChanged();
+}
+
+QSGItem *QSGKeyNavigationAttached::backtab() const
+{
+ Q_D(const QSGKeyNavigationAttached);
+ return d->backtab;
+}
+
+void QSGKeyNavigationAttached::setBacktab(QSGItem *i)
+{
+ Q_D(QSGKeyNavigationAttached);
+ if (d->backtab == i)
+ return;
+ d->backtab = i;
+ d->backtabSet = true;
+ QSGKeyNavigationAttached* other =
+ qobject_cast<QSGKeyNavigationAttached*>(qmlAttachedPropertiesObject<QSGKeyNavigationAttached>(i));
+ if(other && !other->d_func()->tabSet){
+ other->d_func()->tab = qobject_cast<QSGItem*>(parent());
+ emit other->tabChanged();
+ }
+ emit backtabChanged();
+}
+
+QSGKeyNavigationAttached::Priority QSGKeyNavigationAttached::priority() const
+{
+ return m_processPost ? AfterItem : BeforeItem;
+}
+
+void QSGKeyNavigationAttached::setPriority(Priority order)
+{
+ bool processPost = order == AfterItem;
+ if (processPost != m_processPost) {
+ m_processPost = processPost;
+ emit priorityChanged();
+ }
+}
+
+void QSGKeyNavigationAttached::keyPressed(QKeyEvent *event, bool post)
+{
+ Q_D(QSGKeyNavigationAttached);
+ event->ignore();
+
+ if (post != m_processPost) {
+ QSGItemKeyFilter::keyPressed(event, post);
+ return;
+ }
+
+ bool mirror = false;
+ switch(event->key()) {
+ case Qt::Key_Left: {
+ if (QSGItem *parentItem = qobject_cast<QSGItem*>(parent()))
+ mirror = QSGItemPrivate::get(parentItem)->effectiveLayoutMirror;
+ QSGItem* leftItem = mirror ? d->right : d->left;
+ if (leftItem) {
+ setFocusNavigation(leftItem, mirror ? "right" : "left");
+ event->accept();
+ }
+ break;
+ }
+ case Qt::Key_Right: {
+ if (QSGItem *parentItem = qobject_cast<QSGItem*>(parent()))
+ mirror = QSGItemPrivate::get(parentItem)->effectiveLayoutMirror;
+ QSGItem* rightItem = mirror ? d->left : d->right;
+ if (rightItem) {
+ setFocusNavigation(rightItem, mirror ? "left" : "right");
+ event->accept();
+ }
+ break;
+ }
+ case Qt::Key_Up:
+ if (d->up) {
+ setFocusNavigation(d->up, "up");
+ event->accept();
+ }
+ break;
+ case Qt::Key_Down:
+ if (d->down) {
+ setFocusNavigation(d->down, "down");
+ event->accept();
+ }
+ break;
+ case Qt::Key_Tab:
+ if (d->tab) {
+ setFocusNavigation(d->tab, "tab");
+ event->accept();
+ }
+ break;
+ case Qt::Key_Backtab:
+ if (d->backtab) {
+ setFocusNavigation(d->backtab, "backtab");
+ event->accept();
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (!event->isAccepted()) QSGItemKeyFilter::keyPressed(event, post);
+}
+
+void QSGKeyNavigationAttached::keyReleased(QKeyEvent *event, bool post)
+{
+ Q_D(QSGKeyNavigationAttached);
+ event->ignore();
+
+ if (post != m_processPost) {
+ QSGItemKeyFilter::keyReleased(event, post);
+ return;
+ }
+
+ bool mirror = false;
+ switch(event->key()) {
+ case Qt::Key_Left:
+ if (QSGItem *parentItem = qobject_cast<QSGItem*>(parent()))
+ mirror = QSGItemPrivate::get(parentItem)->effectiveLayoutMirror;
+ if (mirror ? d->right : d->left)
+ event->accept();
+ break;
+ case Qt::Key_Right:
+ if (QSGItem *parentItem = qobject_cast<QSGItem*>(parent()))
+ mirror = QSGItemPrivate::get(parentItem)->effectiveLayoutMirror;
+ if (mirror ? d->left : d->right)
+ event->accept();
+ break;
+ case Qt::Key_Up:
+ if (d->up) {
+ event->accept();
+ }
+ break;
+ case Qt::Key_Down:
+ if (d->down) {
+ event->accept();
+ }
+ break;
+ case Qt::Key_Tab:
+ if (d->tab) {
+ event->accept();
+ }
+ break;
+ case Qt::Key_Backtab:
+ if (d->backtab) {
+ event->accept();
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (!event->isAccepted()) QSGItemKeyFilter::keyReleased(event, post);
+}
+
+void QSGKeyNavigationAttached::setFocusNavigation(QSGItem *currentItem, const char *dir)
+{
+ QSGItem *initialItem = currentItem;
+ bool isNextItem = false;
+ do {
+ isNextItem = false;
+ if (currentItem->isVisible() && currentItem->isEnabled()) {
+ currentItem->setFocus(true);
+ } else {
+ QObject *attached =
+ qmlAttachedPropertiesObject<QSGKeyNavigationAttached>(currentItem, false);
+ if (attached) {
+ QSGItem *tempItem = qvariant_cast<QSGItem*>(attached->property(dir));
+ if (tempItem) {
+ currentItem = tempItem;
+ isNextItem = true;
+ }
+ }
+ }
+ }
+ while (currentItem != initialItem && isNextItem);
+}
+
+const QSGKeysAttached::SigMap QSGKeysAttached::sigMap[] = {
+ { Qt::Key_Left, "leftPressed" },
+ { Qt::Key_Right, "rightPressed" },
+ { Qt::Key_Up, "upPressed" },
+ { Qt::Key_Down, "downPressed" },
+ { Qt::Key_Tab, "tabPressed" },
+ { Qt::Key_Backtab, "backtabPressed" },
+ { Qt::Key_Asterisk, "asteriskPressed" },
+ { Qt::Key_NumberSign, "numberSignPressed" },
+ { Qt::Key_Escape, "escapePressed" },
+ { Qt::Key_Return, "returnPressed" },
+ { Qt::Key_Enter, "enterPressed" },
+ { Qt::Key_Delete, "deletePressed" },
+ { Qt::Key_Space, "spacePressed" },
+ { Qt::Key_Back, "backPressed" },
+ { Qt::Key_Cancel, "cancelPressed" },
+ { Qt::Key_Select, "selectPressed" },
+ { Qt::Key_Yes, "yesPressed" },
+ { Qt::Key_No, "noPressed" },
+ { Qt::Key_Context1, "context1Pressed" },
+ { Qt::Key_Context2, "context2Pressed" },
+ { Qt::Key_Context3, "context3Pressed" },
+ { Qt::Key_Context4, "context4Pressed" },
+ { Qt::Key_Call, "callPressed" },
+ { Qt::Key_Hangup, "hangupPressed" },
+ { Qt::Key_Flip, "flipPressed" },
+ { Qt::Key_Menu, "menuPressed" },
+ { Qt::Key_VolumeUp, "volumeUpPressed" },
+ { Qt::Key_VolumeDown, "volumeDownPressed" },
+ { 0, 0 }
+};
+
+bool QSGKeysAttachedPrivate::isConnected(const char *signalName)
+{
+ return isSignalConnected(signalIndex(signalName));
+}
+
+QSGKeysAttached::QSGKeysAttached(QObject *parent)
+: QObject(*(new QSGKeysAttachedPrivate), parent),
+ QSGItemKeyFilter(qobject_cast<QSGItem*>(parent))
+{
+ Q_D(QSGKeysAttached);
+ m_processPost = false;
+ d->item = qobject_cast<QSGItem*>(parent);
+}
+
+QSGKeysAttached::~QSGKeysAttached()
+{
+}
+
+QSGKeysAttached::Priority QSGKeysAttached::priority() const
+{
+ return m_processPost ? AfterItem : BeforeItem;
+}
+
+void QSGKeysAttached::setPriority(Priority order)
+{
+ bool processPost = order == AfterItem;
+ if (processPost != m_processPost) {
+ m_processPost = processPost;
+ emit priorityChanged();
+ }
+}
+
+void QSGKeysAttached::componentComplete()
+{
+ Q_D(QSGKeysAttached);
+ if (d->item) {
+ for (int ii = 0; ii < d->targets.count(); ++ii) {
+ QSGItem *targetItem = d->targets.at(ii);
+ if (targetItem && (targetItem->flags() & QSGItem::ItemAcceptsInputMethod)) {
+ d->item->setFlag(QSGItem::ItemAcceptsInputMethod);
+ break;
+ }
+ }
+ }
+}
+
+void QSGKeysAttached::keyPressed(QKeyEvent *event, bool post)
+{
+ Q_D(QSGKeysAttached);
+ if (post != m_processPost || !d->enabled || d->inPress) {
+ event->ignore();
+ QSGItemKeyFilter::keyPressed(event, post);
+ return;
+ }
+
+ // first process forwards
+ if (d->item && d->item->canvas()) {
+ d->inPress = true;
+ for (int ii = 0; ii < d->targets.count(); ++ii) {
+ QSGItem *i = d->targets.at(ii);
+ if (i && i->isVisible()) {
+ d->item->canvas()->sendEvent(i, event);
+ if (event->isAccepted()) {
+ d->inPress = false;
+ return;
+ }
+ }
+ }
+ d->inPress = false;
+ }
+
+ QSGKeyEvent ke(*event);
+ QByteArray keySignal = keyToSignal(event->key());
+ if (!keySignal.isEmpty()) {
+ keySignal += "(QSGKeyEvent*)";
+ if (d->isConnected(keySignal)) {
+ // If we specifically handle a key then default to accepted
+ ke.setAccepted(true);
+ int idx = QSGKeysAttached::staticMetaObject.indexOfSignal(keySignal);
+ metaObject()->method(idx).invoke(this, Qt::DirectConnection, Q_ARG(QSGKeyEvent*, &ke));
+ }
+ }
+ if (!ke.isAccepted())
+ emit pressed(&ke);
+ event->setAccepted(ke.isAccepted());
+
+ if (!event->isAccepted()) QSGItemKeyFilter::keyPressed(event, post);
+}
+
+void QSGKeysAttached::keyReleased(QKeyEvent *event, bool post)
+{
+ Q_D(QSGKeysAttached);
+ if (post != m_processPost || !d->enabled || d->inRelease) {
+ event->ignore();
+ QSGItemKeyFilter::keyReleased(event, post);
+ return;
+ }
+
+ if (d->item && d->item->canvas()) {
+ d->inRelease = true;
+ for (int ii = 0; ii < d->targets.count(); ++ii) {
+ QSGItem *i = d->targets.at(ii);
+ if (i && i->isVisible()) {
+ d->item->canvas()->sendEvent(i, event);
+ if (event->isAccepted()) {
+ d->inRelease = false;
+ return;
+ }
+ }
+ }
+ d->inRelease = false;
+ }
+
+ QSGKeyEvent ke(*event);
+ emit released(&ke);
+ event->setAccepted(ke.isAccepted());
+
+ if (!event->isAccepted()) QSGItemKeyFilter::keyReleased(event, post);
+}
+
+void QSGKeysAttached::inputMethodEvent(QInputMethodEvent *event, bool post)
+{
+ Q_D(QSGKeysAttached);
+ if (post == m_processPost && d->item && !d->inIM && d->item->canvas()) {
+ d->inIM = true;
+ for (int ii = 0; ii < d->targets.count(); ++ii) {
+ QSGItem *i = d->targets.at(ii);
+ if (i && i->isVisible() && (i->flags() & QSGItem::ItemAcceptsInputMethod)) {
+ d->item->canvas()->sendEvent(i, event);
+ if (event->isAccepted()) {
+ d->imeItem = i;
+ d->inIM = false;
+ return;
+ }
+ }
+ }
+ d->inIM = false;
+ }
+ QSGItemKeyFilter::inputMethodEvent(event, post);
+}
+
+QVariant QSGKeysAttached::inputMethodQuery(Qt::InputMethodQuery query) const
+{
+ Q_D(const QSGKeysAttached);
+ if (d->item) {
+ for (int ii = 0; ii < d->targets.count(); ++ii) {
+ QSGItem *i = d->targets.at(ii);
+ if (i && i->isVisible() && (i->flags() & QSGItem::ItemAcceptsInputMethod) && i == d->imeItem) {
+ //### how robust is i == d->imeItem check?
+ QVariant v = i->inputMethodQuery(query);
+ if (v.userType() == QVariant::RectF)
+ v = d->item->mapRectFromItem(i, v.toRectF()); //### cost?
+ return v;
+ }
+ }
+ }
+ return QSGItemKeyFilter::inputMethodQuery(query);
+}
+
+QSGKeysAttached *QSGKeysAttached::qmlAttachedProperties(QObject *obj)
+{
+ return new QSGKeysAttached(obj);
+}
+
+
+QSGLayoutMirroringAttached::QSGLayoutMirroringAttached(QObject *parent) : QObject(parent), itemPrivate(0)
+{
+ if (QSGItem *item = qobject_cast<QSGItem*>(parent)) {
+ itemPrivate = QSGItemPrivate::get(item);
+ itemPrivate->attachedLayoutDirection = this;
+ } else
+ qmlInfo(parent) << tr("LayoutDirection attached property only works with Items");
+}
+
+QSGLayoutMirroringAttached * QSGLayoutMirroringAttached::qmlAttachedProperties(QObject *object)
+{
+ return new QSGLayoutMirroringAttached(object);
+}
+
+bool QSGLayoutMirroringAttached::enabled() const
+{
+ return itemPrivate ? itemPrivate->effectiveLayoutMirror : false;
+}
+
+void QSGLayoutMirroringAttached::setEnabled(bool enabled)
+{
+ if (!itemPrivate)
+ return;
+
+ itemPrivate->isMirrorImplicit = false;
+ if (enabled != itemPrivate->effectiveLayoutMirror) {
+ itemPrivate->setLayoutMirror(enabled);
+ if (itemPrivate->inheritMirrorFromItem)
+ itemPrivate->resolveLayoutMirror();
+ }
+}
+
+void QSGLayoutMirroringAttached::resetEnabled()
+{
+ if (itemPrivate && !itemPrivate->isMirrorImplicit) {
+ itemPrivate->isMirrorImplicit = true;
+ itemPrivate->resolveLayoutMirror();
+ }
+}
+
+bool QSGLayoutMirroringAttached::childrenInherit() const
+{
+ return itemPrivate ? itemPrivate->inheritMirrorFromItem : false;
+}
+
+void QSGLayoutMirroringAttached::setChildrenInherit(bool childrenInherit) {
+ if (itemPrivate && childrenInherit != itemPrivate->inheritMirrorFromItem) {
+ itemPrivate->inheritMirrorFromItem = childrenInherit;
+ itemPrivate->resolveLayoutMirror();
+ childrenInheritChanged();
+ }
+}
+
+void QSGItemPrivate::resolveLayoutMirror()
+{
+ Q_Q(QSGItem);
+ if (QSGItem *parentItem = q->parentItem()) {
+ QSGItemPrivate *parentPrivate = QSGItemPrivate::get(parentItem);
+ setImplicitLayoutMirror(parentPrivate->inheritedLayoutMirror, parentPrivate->inheritMirrorFromParent);
+ } else {
+ setImplicitLayoutMirror(isMirrorImplicit ? false : effectiveLayoutMirror, inheritMirrorFromItem);
+ }
+}
+
+void QSGItemPrivate::setImplicitLayoutMirror(bool mirror, bool inherit)
+{
+ inherit = inherit || inheritMirrorFromItem;
+ if (!isMirrorImplicit && inheritMirrorFromItem)
+ mirror = effectiveLayoutMirror;
+ if (mirror == inheritedLayoutMirror && inherit == inheritMirrorFromParent)
+ return;
+
+ inheritMirrorFromParent = inherit;
+ inheritedLayoutMirror = inheritMirrorFromParent ? mirror : false;
+
+ if (isMirrorImplicit)
+ setLayoutMirror(inherit ? inheritedLayoutMirror : false);
+ for (int i = 0; i < childItems.count(); ++i) {
+ if (QSGItem *child = qobject_cast<QSGItem *>(childItems.at(i))) {
+ QSGItemPrivate *childPrivate = QSGItemPrivate::get(child);
+ childPrivate->setImplicitLayoutMirror(inheritedLayoutMirror, inheritMirrorFromParent);
+ }
+ }
+}
+
+void QSGItemPrivate::setLayoutMirror(bool mirror)
+{
+ if (mirror != effectiveLayoutMirror) {
+ effectiveLayoutMirror = mirror;
+ if (_anchors) {
+ QSGAnchorsPrivate *anchor_d = QSGAnchorsPrivate::get(_anchors);
+ anchor_d->fillChanged();
+ anchor_d->centerInChanged();
+ anchor_d->updateHorizontalAnchors();
+ emit _anchors->mirroredChanged();
+ }
+ mirrorChange();
+ if (attachedLayoutDirection) {
+ emit attachedLayoutDirection->enabledChanged();
+ }
+ }
+}
+
+QSGItem::QSGItem(QSGItem* parent)
+: QObject(*(new QSGItemPrivate), parent)
+{
+ Q_D(QSGItem);
+ d->init(parent);
+}
+
+QSGItem::QSGItem(QSGItemPrivate &dd, QSGItem *parent)
+: QObject(dd, parent)
+{
+ Q_D(QSGItem);
+ d->init(parent);
+}
+
+QSGItem::~QSGItem()
+{
+ Q_D(QSGItem);
+
+ // XXX todo - optimize
+ setParentItem(0);
+ while (!d->childItems.isEmpty())
+ d->childItems.first()->setParentItem(0);
+
+ for (int ii = 0; ii < d->changeListeners.count(); ++ii) {
+ QSGAnchorsPrivate *anchor = d->changeListeners.at(ii).listener->anchorPrivate();
+ if (anchor)
+ anchor->clearItem(this);
+ }
+
+ // XXX todo - the original checks if the parent is being destroyed
+ for (int ii = 0; ii < d->changeListeners.count(); ++ii) {
+ QSGAnchorsPrivate *anchor = d->changeListeners.at(ii).listener->anchorPrivate();
+ if (anchor && anchor->item && anchor->item->parent() != this) //child will be deleted anyway
+ anchor->updateOnComplete();
+ }
+
+ for (int ii = 0; ii < d->changeListeners.count(); ++ii) {
+ const QSGItemPrivate::ChangeListener &change = d->changeListeners.at(ii);
+ if (change.types & QSGItemPrivate::Destroyed)
+ change.listener->itemDestroyed(this);
+ }
+ d->changeListeners.clear();
+ delete d->_anchorLines; d->_anchorLines = 0;
+ delete d->_anchors; d->_anchors = 0;
+ delete d->_stateGroup; d->_stateGroup = 0;
+ delete d->_contents; d->_contents = 0;
+}
+
+void QSGItem::setParentItem(QSGItem *parentItem)
+{
+ Q_D(QSGItem);
+ if (parentItem == d->parentItem)
+ return;
+
+ d->removeFromDirtyList();
+
+ QSGItem *oldParentItem = d->parentItem;
+ QSGItem *scopeFocusedItem = 0;
+
+ if (oldParentItem) {
+ QSGItemPrivate *op = QSGItemPrivate::get(oldParentItem);
+
+ QSGItem *scopeItem = 0;
+
+ if (d->canvas && hasFocus()) {
+ scopeItem = oldParentItem;
+ while (!scopeItem->isFocusScope()) scopeItem = scopeItem->parentItem();
+ scopeFocusedItem = this;
+ } else if (d->canvas && !isFocusScope() && d->subFocusItem) {
+ scopeItem = oldParentItem;
+ while (!scopeItem->isFocusScope()) scopeItem = scopeItem->parentItem();
+ scopeFocusedItem = d->subFocusItem;
+ }
+
+ if (scopeFocusedItem)
+ QSGCanvasPrivate::get(d->canvas)->clearFocusInScope(scopeItem, scopeFocusedItem,
+ QSGCanvasPrivate::DontChangeFocusProperty);
+
+ op->removeChild(this);
+ }
+
+ d->parentItem = parentItem;
+
+ QSGCanvas *parentCanvas = parentItem?QSGItemPrivate::get(parentItem)->canvas:0;
+ if (d->canvas != parentCanvas) {
+ if (d->canvas && d->itemNodeInstance)
+ QSGCanvasPrivate::get(d->canvas)->cleanup(d->itemNodeInstance);
+
+ QSGItemPrivate::InitializationState initState;
+ initState.clear();
+ d->initCanvas(&initState, parentCanvas);
+ }
+
+ d->dirty(QSGItemPrivate::ParentChanged);
+
+ if (d->parentItem)
+ QSGItemPrivate::get(d->parentItem)->addChild(this);
+
+ d->setEffectiveVisibleRecur(d->calcEffectiveVisible());
+ d->setEffectiveEnableRecur(d->calcEffectiveEnable());
+
+ if (scopeFocusedItem && d->parentItem && d->canvas) {
+ // We need to test whether this item becomes scope focused
+ QSGItem *scopeItem = 0;
+ scopeItem = d->parentItem;
+ while (!scopeItem->isFocusScope()) scopeItem = scopeItem->parentItem();
+
+ if (scopeItem->scopedFocusItem()) {
+ QSGItemPrivate::get(scopeFocusedItem)->focus = false;
+ emit scopeFocusedItem->focusChanged(false);
+ } else {
+ QSGCanvasPrivate::get(d->canvas)->setFocusInScope(scopeItem, scopeFocusedItem,
+ QSGCanvasPrivate::DontChangeFocusProperty);
+ }
+ }
+
+ d->resolveLayoutMirror();
+
+ d->itemChange(ItemParentHasChanged, d->parentItem);
+
+ emit parentChanged(d->parentItem);
+}
+
+void QSGItem::stackBefore(const QSGItem *sibling)
+{
+ Q_D(QSGItem);
+ if (!sibling || sibling == this || !d->parentItem || d->parentItem != QSGItemPrivate::get(sibling)->parentItem) {
+ qWarning("QSGItem::stackBefore: Cannot stack before %p, which must be a sibling", sibling);
+ return;
+ }
+
+ QSGItemPrivate *parentPrivate = QSGItemPrivate::get(d->parentItem);
+
+ int myIndex = parentPrivate->childItems.indexOf(this);
+ int siblingIndex = parentPrivate->childItems.indexOf(const_cast<QSGItem *>(sibling));
+
+ Q_ASSERT(myIndex != -1 && siblingIndex != -1);
+
+ if (myIndex == siblingIndex - 1)
+ return;
+
+ parentPrivate->childItems.removeAt(myIndex);
+
+ if (myIndex < siblingIndex) --siblingIndex;
+
+ parentPrivate->childItems.insert(siblingIndex, this);
+
+ parentPrivate->dirty(QSGItemPrivate::ChildrenStackingChanged);
+
+ for (int ii = qMin(siblingIndex, myIndex); ii < parentPrivate->childItems.count(); ++ii)
+ QSGItemPrivate::get(parentPrivate->childItems.at(ii))->siblingOrderChanged();
+}
+
+void QSGItem::stackAfter(const QSGItem *sibling)
+{
+ Q_D(QSGItem);
+ if (!sibling || sibling == this || !d->parentItem || d->parentItem != QSGItemPrivate::get(sibling)->parentItem) {
+ qWarning("QSGItem::stackAfter: Cannot stack after %p, which must be a sibling", sibling);
+ return;
+ }
+
+ QSGItemPrivate *parentPrivate = QSGItemPrivate::get(d->parentItem);
+
+ int myIndex = parentPrivate->childItems.indexOf(this);
+ int siblingIndex = parentPrivate->childItems.indexOf(const_cast<QSGItem *>(sibling));
+
+ Q_ASSERT(myIndex != -1 && siblingIndex != -1);
+
+ if (myIndex == siblingIndex + 1)
+ return;
+
+ parentPrivate->childItems.removeAt(myIndex);
+
+ if (myIndex < siblingIndex) --siblingIndex;
+
+ parentPrivate->childItems.insert(siblingIndex + 1, this);
+
+ parentPrivate->dirty(QSGItemPrivate::ChildrenStackingChanged);
+
+ for (int ii = qMin(myIndex, siblingIndex + 1); ii < parentPrivate->childItems.count(); ++ii)
+ QSGItemPrivate::get(parentPrivate->childItems.at(ii))->siblingOrderChanged();
+}
+
+/*!
+ Returns the QSGItem parent of this item.
+*/
+QSGItem *QSGItem::parentItem() const
+{
+ Q_D(const QSGItem);
+ return d->parentItem;
+}
+
+QSGEngine *QSGItem::sceneGraphEngine() const
+{
+ return canvas()->sceneGraphEngine();
+}
+
+QSGCanvas *QSGItem::canvas() const
+{
+ Q_D(const QSGItem);
+ return d->canvas;
+}
+
+static bool itemZOrder_sort(QSGItem *lhs, QSGItem *rhs)
+{
+ return lhs->z() < rhs->z();
+}
+
+QList<QSGItem *> QSGItemPrivate::paintOrderChildItems() const
+{
+ // XXX todo - optimize, don't sort and return items that are
+ // ignored anyway, like invisible or disabled items.
+ QList<QSGItem *> items = childItems;
+ qStableSort(items.begin(), items.end(), itemZOrder_sort);
+ return items;
+}
+
+void QSGItemPrivate::addChild(QSGItem *child)
+{
+ Q_Q(QSGItem);
+
+ Q_ASSERT(!childItems.contains(child));
+
+ childItems.append(child);
+
+ dirty(QSGItemPrivate::ChildrenChanged);
+
+ itemChange(QSGItem::ItemChildAddedChange, child);
+
+ emit q->childrenChanged();
+}
+
+void QSGItemPrivate::removeChild(QSGItem *child)
+{
+ Q_Q(QSGItem);
+
+ Q_ASSERT(child);
+ Q_ASSERT(childItems.contains(child));
+ childItems.removeOne(child);
+ Q_ASSERT(!childItems.contains(child));
+
+ dirty(QSGItemPrivate::ChildrenChanged);
+
+ itemChange(QSGItem::ItemChildRemovedChange, child);
+
+ emit q->childrenChanged();
+}
+
+void QSGItemPrivate::InitializationState::clear()
+{
+ focusScope = 0;
+}
+
+void QSGItemPrivate::InitializationState::clear(QSGItem *fs)
+{
+ focusScope = fs;
+}
+
+QSGItem *QSGItemPrivate::InitializationState::getFocusScope(QSGItem *item)
+{
+ if (!focusScope) {
+ QSGItem *fs = item->parentItem();
+ while (!fs->isFocusScope())
+ fs = fs->parentItem();
+ focusScope = fs;
+ }
+ return focusScope;
+}
+
+void QSGItemPrivate::initCanvas(InitializationState *state, QSGCanvas *c)
+{
+ Q_Q(QSGItem);
+
+ if (canvas) {
+ removeFromDirtyList();
+ QSGCanvasPrivate *c = QSGCanvasPrivate::get(canvas);
+ if (polishScheduled)
+ c->itemsToPolish.remove(q);
+ if (c->mouseGrabberItem == q)
+ c->mouseGrabberItem = 0;
+ }
+
+ canvas = c;
+
+ if (canvas && polishScheduled)
+ QSGCanvasPrivate::get(canvas)->itemsToPolish.insert(q);
+
+ if (canvas && hoverEnabled && !canvas->hasMouseTracking())
+ canvas->setMouseTracking(true);
+
+ // XXX todo - why aren't these added to the destroy list?
+ itemNodeInstance = 0;
+ opacityNode = 0;
+ clipNode = 0;
+ rootNode = 0;
+ groupNode = 0;
+ paintNode = 0;
+ paintNodeIndex = 0;
+
+ InitializationState _dummy;
+ InitializationState *childState = state;
+
+ if (c && q->isFocusScope()) {
+ _dummy.clear(q);
+ childState = &_dummy;
+ }
+
+ for (int ii = 0; ii < childItems.count(); ++ii) {
+ QSGItem *child = childItems.at(ii);
+ QSGItemPrivate::get(child)->initCanvas(childState, c);
+ }
+
+ if (c && focus) {
+ // Fixup
+ if (state->getFocusScope(q)->scopedFocusItem()) {
+ focus = false;
+ emit q->focusChanged(false);
+ } else {
+ QSGCanvasPrivate::get(canvas)->setFocusInScope(state->getFocusScope(q), q);
+ }
+ }
+
+ dirty(Canvas);
+
+ itemChange(QSGItem::ItemSceneChange, c);
+}
+
+/*!
+Returns a transform that maps points from canvas space into item space.
+*/
+QTransform QSGItemPrivate::canvasToItemTransform() const
+{
+ // XXX todo - optimize
+ return itemToCanvasTransform().inverted();
+}
+
+/*!
+Returns a transform that maps points from item space into canvas space.
+*/
+QTransform QSGItemPrivate::itemToCanvasTransform() const
+{
+ // XXX todo
+ QTransform rv = parentItem?QSGItemPrivate::get(parentItem)->itemToCanvasTransform():QTransform();
+ itemToParentTransform(rv);
+ return rv;
+}
+
+/*!
+Motifies \a t with this items local transform relative to its parent.
+*/
+void QSGItemPrivate::itemToParentTransform(QTransform &t) const
+{
+ if (x || y)
+ t.translate(x, y);
+
+ if (!transforms.isEmpty()) {
+ QMatrix4x4 m(t);
+ for (int ii = transforms.count() - 1; ii >= 0; --ii)
+ transforms.at(ii)->applyTo(&m);
+ t = m.toTransform();
+ }
+
+ if (scale != 1. || rotation != 0.) {
+ QPointF tp = computeTransformOrigin();
+ t.translate(tp.x(), tp.y());
+ t.scale(scale, scale);
+ t.rotate(rotation);
+ t.translate(-tp.x(), -tp.y());
+ }
+}
+
+bool QSGItem::isComponentComplete() const
+{
+ Q_D(const QSGItem);
+ return d->componentComplete;
+}
+
+QSGItemPrivate::QSGItemPrivate()
+: _anchors(0), _contents(0), baselineOffset(0), _anchorLines(0), _stateGroup(0), origin(QSGItem::Center),
+
+ flags(0), widthValid(false), heightValid(false), componentComplete(true),
+ keepMouse(false), hoverEnabled(false), smooth(false), focus(false), activeFocus(false), notifiedFocus(false),
+ notifiedActiveFocus(false), filtersChildMouseEvents(false), explicitVisible(true),
+ effectiveVisible(true), explicitEnable(true), effectiveEnable(true), polishScheduled(false),
+ inheritedLayoutMirror(false), effectiveLayoutMirror(false), isMirrorImplicit(true),
+ inheritMirrorFromParent(false), inheritMirrorFromItem(false), childrenDoNotOverlap(false),
+
+ canvas(0), parentItem(0),
+
+ subFocusItem(0),
+
+ x(0), y(0), width(0), height(0), implicitWidth(0), implicitHeight(0),
+ z(0), scale(1), rotation(0), opacity(1),
+
+ attachedLayoutDirection(0), acceptedMouseButtons(0),
+ imHints(Qt::ImhNone),
+
+ keyHandler(0),
+
+ dirtyAttributes(0), nextDirtyItem(0), prevDirtyItem(0),
+
+ itemNodeInstance(0), opacityNode(0), clipNode(0), rootNode(0), groupNode(0), paintNode(0)
+ , paintNodeIndex(0), effectRefCount(0), hideRefCount(0)
+{
+}
+
+void QSGItemPrivate::init(QSGItem *parent)
+{
+ Q_Q(QSGItem);
+ baselineOffset.invalidate();
+
+ if (parent) {
+ q->setParentItem(parent);
+ QSGItemPrivate *parentPrivate = QSGItemPrivate::get(parent);
+ setImplicitLayoutMirror(parentPrivate->inheritedLayoutMirror, parentPrivate->inheritMirrorFromParent);
+ }
+}
+
+void QSGItemPrivate::data_append(QDeclarativeListProperty<QObject> *prop, QObject *o)
+{
+ if (!o)
+ return;
+
+ QSGItem *that = static_cast<QSGItem *>(prop->object);
+
+ // This test is measurably (albeit only slightly) faster than qobject_cast<>()
+ const QMetaObject *mo = o->metaObject();
+ while (mo && mo != &QSGItem::staticMetaObject) {
+ if (mo == &QDeclarativeItem::staticMetaObject)
+ qWarning("Cannot add a QtQuick 1.0 item (%s) into a QtQuick 2.0 scene!", o->metaObject()->className());
+ mo = mo->d.superdata;
+ }
+
+ if (mo) {
+ QSGItem *item = static_cast<QSGItem *>(o);
+ item->setParentItem(that);
+ } else {
+ // XXX todo - do we really want this behavior?
+ o->setParent(that);
+ }
+}
+
+int QSGItemPrivate::data_count(QDeclarativeListProperty<QObject> *prop)
+{
+ Q_UNUSED(prop);
+ // XXX todo
+ return 0;
+}
+
+QObject *QSGItemPrivate::data_at(QDeclarativeListProperty<QObject> *prop, int i)
+{
+ Q_UNUSED(prop);
+ Q_UNUSED(i);
+ // XXX todo
+ return 0;
+}
+
+void QSGItemPrivate::data_clear(QDeclarativeListProperty<QObject> *prop)
+{
+ Q_UNUSED(prop);
+ // XXX todo
+}
+
+QObject *QSGItemPrivate::resources_at(QDeclarativeListProperty<QObject> *prop, int index)
+{
+ const QObjectList children = prop->object->children();
+ if (index < children.count())
+ return children.at(index);
+ else
+ return 0;
+}
+
+void QSGItemPrivate::resources_append(QDeclarativeListProperty<QObject> *prop, QObject *o)
+{
+ // XXX todo - do we really want this behavior?
+ o->setParent(prop->object);
+}
+
+int QSGItemPrivate::resources_count(QDeclarativeListProperty<QObject> *prop)
+{
+ return prop->object->children().count();
+}
+
+void QSGItemPrivate::resources_clear(QDeclarativeListProperty<QObject> *prop)
+{
+ // XXX todo - do we really want this behavior?
+ const QObjectList children = prop->object->children();
+ for (int index = 0; index < children.count(); index++)
+ children.at(index)->setParent(0);
+}
+
+QSGItem *QSGItemPrivate::children_at(QDeclarativeListProperty<QSGItem> *prop, int index)
+{
+ QSGItemPrivate *p = QSGItemPrivate::get(static_cast<QSGItem *>(prop->object));
+ if (index >= p->childItems.count() || index < 0)
+ return 0;
+ else
+ return p->childItems.at(index);
+}
+
+void QSGItemPrivate::children_append(QDeclarativeListProperty<QSGItem> *prop, QSGItem *o)
+{
+ if (!o)
+ return;
+
+ QSGItem *that = static_cast<QSGItem *>(prop->object);
+ if (o->parentItem() == that)
+ o->setParentItem(0);
+
+ o->setParentItem(that);
+}
+
+int QSGItemPrivate::children_count(QDeclarativeListProperty<QSGItem> *prop)
+{
+ QSGItemPrivate *p = QSGItemPrivate::get(static_cast<QSGItem *>(prop->object));
+ return p->childItems.count();
+}
+
+void QSGItemPrivate::children_clear(QDeclarativeListProperty<QSGItem> *prop)
+{
+ QSGItem *that = static_cast<QSGItem *>(prop->object);
+ QSGItemPrivate *p = QSGItemPrivate::get(that);
+ while (!p->childItems.isEmpty())
+ p->childItems.at(0)->setParentItem(0);
+}
+
+int QSGItemPrivate::transform_count(QDeclarativeListProperty<QSGTransform> *prop)
+{
+ QSGItem *that = static_cast<QSGItem *>(prop->object);
+ return QSGItemPrivate::get(that)->transforms.count();
+}
+
+void QSGTransform::appendToItem(QSGItem *item)
+{
+ Q_D(QSGTransform);
+ if (!item)
+ return;
+
+ QSGItemPrivate *p = QSGItemPrivate::get(item);
+
+ if (!d->items.isEmpty() && !p->transforms.isEmpty() && p->transforms.contains(this)) {
+ p->transforms.removeOne(this);
+ p->transforms.append(this);
+ } else {
+ p->transforms.append(this);
+ d->items.append(item);
+ }
+
+ p->dirty(QSGItemPrivate::Transform);
+}
+
+void QSGTransform::prependToItem(QSGItem *item)
+{
+ Q_D(QSGTransform);
+ if (!item)
+ return;
+
+ QSGItemPrivate *p = QSGItemPrivate::get(item);
+
+ if (!d->items.isEmpty() && !p->transforms.isEmpty() && p->transforms.contains(this)) {
+ p->transforms.removeOne(this);
+ p->transforms.prepend(this);
+ } else {
+ p->transforms.prepend(this);
+ d->items.append(item);
+ }
+
+ p->dirty(QSGItemPrivate::Transform);
+}
+
+void QSGItemPrivate::transform_append(QDeclarativeListProperty<QSGTransform> *prop, QSGTransform *transform)
+{
+ if (!transform)
+ return;
+
+ QSGItem *that = static_cast<QSGItem *>(prop->object);
+ transform->appendToItem(that);
+}
+
+QSGTransform *QSGItemPrivate::transform_at(QDeclarativeListProperty<QSGTransform> *prop, int idx)
+{
+ QSGItem *that = static_cast<QSGItem *>(prop->object);
+ QSGItemPrivate *p = QSGItemPrivate::get(that);
+
+ if (idx < 0 || idx >= p->transforms.count())
+ return 0;
+ else
+ return p->transforms.at(idx);
+}
+
+void QSGItemPrivate::transform_clear(QDeclarativeListProperty<QSGTransform> *prop)
+{
+ QSGItem *that = static_cast<QSGItem *>(prop->object);
+ QSGItemPrivate *p = QSGItemPrivate::get(that);
+
+ for (int ii = 0; ii < p->transforms.count(); ++ii) {
+ QSGTransform *t = p->transforms.at(ii);
+ QSGTransformPrivate *tp = QSGTransformPrivate::get(t);
+ tp->items.removeOne(that);
+ }
+
+ p->transforms.clear();
+
+ p->dirty(QSGItemPrivate::Transform);
+}
+
+QSGAnchors *QSGItemPrivate::anchors() const
+{
+ if (!_anchors) {
+ Q_Q(const QSGItem);
+ _anchors = new QSGAnchors(const_cast<QSGItem *>(q));
+ if (!componentComplete)
+ _anchors->classBegin();
+ }
+ return _anchors;
+}
+
+QSGItemPrivate::AnchorLines *QSGItemPrivate::anchorLines() const
+{
+ Q_Q(const QSGItem);
+ if (!_anchorLines) _anchorLines =
+ new AnchorLines(const_cast<QSGItem *>(q));
+ return _anchorLines;
+}
+
+void QSGItemPrivate::siblingOrderChanged()
+{
+ Q_Q(QSGItem);
+ for(int ii = 0; ii < changeListeners.count(); ++ii) {
+ const QSGItemPrivate::ChangeListener &change = changeListeners.at(ii);
+ if (change.types & QSGItemPrivate::SiblingOrder) {
+ change.listener->itemSiblingOrderChanged(q);
+ }
+ }
+}
+
+QDeclarativeListProperty<QObject> QSGItemPrivate::data()
+{
+ return QDeclarativeListProperty<QObject>(q_func(), 0, QSGItemPrivate::data_append,
+ QSGItemPrivate::data_count,
+ QSGItemPrivate::data_at,
+ QSGItemPrivate::data_clear);
+}
+
+QRectF QSGItem::childrenRect()
+{
+ Q_D(QSGItem);
+ if (!d->_contents) {
+ d->_contents = new QSGContents(this);
+ if (d->componentComplete)
+ d->_contents->complete();
+ }
+ return d->_contents->rectF();
+}
+
+QList<QSGItem *> QSGItem::childItems() const
+{
+ Q_D(const QSGItem);
+ return d->childItems;
+}
+
+bool QSGItem::clip() const
+{
+ return flags() & ItemClipsChildrenToShape;
+}
+
+void QSGItem::setClip(bool c)
+{
+ if (clip() == c)
+ return;
+
+ setFlag(ItemClipsChildrenToShape, c);
+
+ emit clipChanged(c);
+}
+
+void QSGItem::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
+{
+ Q_D(QSGItem);
+
+ if (d->_anchors)
+ QSGAnchorsPrivate::get(d->_anchors)->updateMe();
+
+ for(int ii = 0; ii < d->changeListeners.count(); ++ii) {
+ const QSGItemPrivate::ChangeListener &change = d->changeListeners.at(ii);
+ if (change.types & QSGItemPrivate::Geometry)
+ change.listener->itemGeometryChanged(this, newGeometry, oldGeometry);
+ }
+
+ if (newGeometry.x() != oldGeometry.x())
+ emit xChanged();
+ if (newGeometry.y() != oldGeometry.y())
+ emit yChanged();
+ if (newGeometry.width() != oldGeometry.width())
+ emit widthChanged();
+ if (newGeometry.height() != oldGeometry.height())
+ emit heightChanged();
+}
+
+/*!
+ Called by the rendering thread when it is time to sync the state of the QML objects with the
+ scene graph objects. The function should return the root of the scene graph subtree for
+ this item. \a oldNode is the node that was returned the last time the function was called.
+
+ The main thread is blocked while this function is executed so it is safe to read
+ values from the QSGItem instance and other objects in the main thread.
+
+ \warning This is the only function in which it is allowed to make use of scene graph
+ objects from the main thread. Use of scene graph objects outside this function will
+ result in race conditions and potential crashes.
+ */
+
+QSGNode *QSGItem::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
+{
+ delete oldNode;
+ return 0;
+}
+
+QSGTransformNode *QSGItemPrivate::createTransformNode()
+{
+ return new QSGTransformNode;
+}
+
+void QSGItem::updatePolish()
+{
+}
+
+void QSGItemPrivate::removeItemChangeListener(QSGItemChangeListener *listener, ChangeTypes types)
+{
+ ChangeListener change(listener, types);
+ changeListeners.removeOne(change);
+}
+
+void QSGItem::keyPressEvent(QKeyEvent *event)
+{
+ event->ignore();
+}
+
+void QSGItem::keyReleaseEvent(QKeyEvent *event)
+{
+ event->ignore();
+}
+
+void QSGItem::inputMethodEvent(QInputMethodEvent *event)
+{
+ event->ignore();
+}
+
+void QSGItem::focusInEvent(QFocusEvent *)
+{
+}
+
+void QSGItem::focusOutEvent(QFocusEvent *)
+{
+}
+
+void QSGItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
+{
+ event->ignore();
+}
+
+void QSGItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
+{
+ event->ignore();
+}
+
+void QSGItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
+{
+ event->ignore();
+}
+
+void QSGItem::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
+{
+ mousePressEvent(event);
+}
+
+void QSGItem::mouseUngrabEvent()
+{
+ // XXX todo
+}
+
+void QSGItem::wheelEvent(QGraphicsSceneWheelEvent *event)
+{
+ event->ignore();
+}
+
+void QSGItem::touchEvent(QTouchEvent *event)
+{
+ event->ignore();
+}
+
+void QSGItem::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
+{
+ Q_UNUSED(event);
+}
+
+void QSGItem::hoverMoveEvent(QGraphicsSceneHoverEvent *event)
+{
+ Q_UNUSED(event);
+}
+
+void QSGItem::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
+{
+ Q_UNUSED(event);
+}
+
+bool QSGItem::childMouseEventFilter(QSGItem *, QEvent *)
+{
+ return false;
+}
+
+Qt::InputMethodHints QSGItem::inputMethodHints() const
+{
+ Q_D(const QSGItem);
+ return d->imHints;
+}
+
+void QSGItem::setInputMethodHints(Qt::InputMethodHints hints)
+{
+ Q_D(QSGItem);
+ d->imHints = hints;
+
+ if (!d->canvas || d->canvas->activeFocusItem() != this)
+ return;
+
+ QSGCanvasPrivate::get(d->canvas)->updateInputMethodData();
+#ifndef QT_NO_IM
+ if (d->canvas->hasFocus())
+ if (QInputContext *inputContext = d->canvas->inputContext())
+ inputContext->update();
+#endif
+}
+
+void QSGItem::updateMicroFocus()
+{
+#ifndef QT_NO_IM
+ Q_D(QSGItem);
+ if (d->canvas && d->canvas->hasFocus())
+ if (QInputContext *inputContext = d->canvas->inputContext())
+ inputContext->update();
+#endif
+}
+
+QVariant QSGItem::inputMethodQuery(Qt::InputMethodQuery query) const
+{
+ Q_D(const QSGItem);
+ QVariant v;
+
+ if (d->keyHandler)
+ v = d->keyHandler->inputMethodQuery(query);
+
+ return v;
+}
+
+QSGAnchorLine QSGItemPrivate::left() const
+{
+ return anchorLines()->left;
+}
+
+QSGAnchorLine QSGItemPrivate::right() const
+{
+ return anchorLines()->right;
+}
+
+QSGAnchorLine QSGItemPrivate::horizontalCenter() const
+{
+ return anchorLines()->hCenter;
+}
+
+QSGAnchorLine QSGItemPrivate::top() const
+{
+ return anchorLines()->top;
+}
+
+QSGAnchorLine QSGItemPrivate::bottom() const
+{
+ return anchorLines()->bottom;
+}
+
+QSGAnchorLine QSGItemPrivate::verticalCenter() const
+{
+ return anchorLines()->vCenter;
+}
+
+QSGAnchorLine QSGItemPrivate::baseline() const
+{
+ return anchorLines()->baseline;
+}
+
+qreal QSGItem::baselineOffset() const
+{
+ Q_D(const QSGItem);
+ if (!d->baselineOffset.isValid()) {
+ return 0.0;
+ } else
+ return d->baselineOffset;
+}
+
+void QSGItem::setBaselineOffset(qreal offset)
+{
+ Q_D(QSGItem);
+ if (offset == d->baselineOffset)
+ return;
+
+ d->baselineOffset = offset;
+
+ for(int ii = 0; ii < d->changeListeners.count(); ++ii) {
+ const QSGItemPrivate::ChangeListener &change = d->changeListeners.at(ii);
+ if (change.types & QSGItemPrivate::Geometry) {
+ QSGAnchorsPrivate *anchor = change.listener->anchorPrivate();
+ if (anchor)
+ anchor->updateVerticalAnchors();
+ }
+ }
+ emit baselineOffsetChanged(offset);
+}
+
+void QSGItem::update()
+{
+ Q_D(QSGItem);
+ Q_ASSERT(flags() & ItemHasContents);
+ d->dirty(QSGItemPrivate::Content);
+}
+
+void QSGItem::polish()
+{
+ Q_D(QSGItem);
+ if (!d->polishScheduled) {
+ d->polishScheduled = true;
+ if (d->canvas)
+ QSGCanvasPrivate::get(d->canvas)->itemsToPolish.insert(this);
+ }
+}
+
+QScriptValue QSGItem::mapFromItem(const QScriptValue &item, qreal x, qreal y) const
+{
+ QScriptValue sv = QDeclarativeEnginePrivate::getScriptEngine(qmlEngine(this))->newObject();
+ QSGItem *itemObj = qobject_cast<QSGItem*>(item.toQObject());
+ if (!itemObj && !item.isNull()) {
+ qmlInfo(this) << "mapFromItem() given argument \"" << item.toString() << "\" which is neither null nor an Item";
+ return 0;
+ }
+
+ // If QSGItem::mapFromItem() is called with 0, behaves the same as mapFromScene()
+ QPointF p = mapFromItem(itemObj, QPointF(x, y));
+ sv.setProperty(QLatin1String("x"), p.x());
+ sv.setProperty(QLatin1String("y"), p.y());
+ return sv;
+}
+
+QTransform QSGItem::itemTransform(QSGItem *other, bool *ok) const
+{
+ Q_D(const QSGItem);
+
+ // XXX todo - we need to be able to handle common parents better and detect
+ // invalid cases
+ if (ok) *ok = true;
+
+ QTransform t = d->itemToCanvasTransform();
+ if (other) t *= QSGItemPrivate::get(other)->canvasToItemTransform();
+
+ return t;
+}
+
+QScriptValue QSGItem::mapToItem(const QScriptValue &item, qreal x, qreal y) const
+{
+ QScriptValue sv = QDeclarativeEnginePrivate::getScriptEngine(qmlEngine(this))->newObject();
+ QSGItem *itemObj = qobject_cast<QSGItem*>(item.toQObject());
+ if (!itemObj && !item.isNull()) {
+ qmlInfo(this) << "mapToItem() given argument \"" << item.toString() << "\" which is neither null nor an Item";
+ return 0;
+ }
+
+ // If QSGItem::mapToItem() is called with 0, behaves the same as mapToScene()
+ QPointF p = mapToItem(itemObj, QPointF(x, y));
+ sv.setProperty(QLatin1String("x"), p.x());
+ sv.setProperty(QLatin1String("y"), p.y());
+ return sv;
+}
+
+void QSGItem::forceActiveFocus()
+{
+ setFocus(true);
+ QSGItem *parent = parentItem();
+ while (parent) {
+ if (parent->flags() & QSGItem::ItemIsFocusScope) {
+ parent->setFocus(true);
+ }
+ parent = parent->parentItem();
+ }
+}
+
+QSGItem *QSGItem::childAt(qreal x, qreal y) const
+{
+ // XXX todo - should this include transform etc.?
+ const QList<QSGItem *> children = childItems();
+ for (int i = children.count()-1; i >= 0; --i) {
+ if (QSGItem *child = qobject_cast<QSGItem *>(children.at(i))) {
+ if (child->isVisible() && child->x() <= x
+ && child->x() + child->width() >= x
+ && child->y() <= y
+ && child->y() + child->height() >= y)
+ return child;
+ }
+ }
+ return 0;
+}
+
+QDeclarativeListProperty<QObject> QSGItemPrivate::resources()
+{
+ return QDeclarativeListProperty<QObject>(q_func(), 0, QSGItemPrivate::resources_append,
+ QSGItemPrivate::resources_count,
+ QSGItemPrivate::resources_at,
+ QSGItemPrivate::resources_clear);
+}
+
+QDeclarativeListProperty<QSGItem> QSGItemPrivate::children()
+{
+ return QDeclarativeListProperty<QSGItem>(q_func(), 0, QSGItemPrivate::children_append,
+ QSGItemPrivate::children_count,
+ QSGItemPrivate::children_at,
+ QSGItemPrivate::children_clear);
+
+}
+
+QDeclarativeListProperty<QDeclarativeState> QSGItemPrivate::states()
+{
+ return _states()->statesProperty();
+}
+
+QDeclarativeListProperty<QDeclarativeTransition> QSGItemPrivate::transitions()
+{
+ return _states()->transitionsProperty();
+}
+
+QString QSGItemPrivate::state() const
+{
+ if (!_stateGroup)
+ return QString();
+ else
+ return _stateGroup->state();
+}
+
+void QSGItemPrivate::setState(const QString &state)
+{
+ _states()->setState(state);
+}
+
+QDeclarativeListProperty<QSGTransform> QSGItem::transform()
+{
+ Q_D(QSGItem);
+ return QDeclarativeListProperty<QSGTransform>(this, 0, d->transform_append, d->transform_count,
+ d->transform_at, d->transform_clear);
+}
+
+void QSGItem::classBegin()
+{
+ Q_D(QSGItem);
+ d->componentComplete = false;
+ if (d->_stateGroup)
+ d->_stateGroup->classBegin();
+ if (d->_anchors)
+ d->_anchors->classBegin();
+}
+
+void QSGItem::componentComplete()
+{
+ Q_D(QSGItem);
+ d->componentComplete = true;
+ if (d->_stateGroup)
+ d->_stateGroup->componentComplete();
+ if (d->_anchors) {
+ d->_anchors->componentComplete();
+ QSGAnchorsPrivate::get(d->_anchors)->updateOnComplete();
+ }
+ if (d->keyHandler)
+ d->keyHandler->componentComplete();
+ if (d->_contents)
+ d->_contents->complete();
+}
+
+QDeclarativeStateGroup *QSGItemPrivate::_states()
+{
+ Q_Q(QSGItem);
+ if (!_stateGroup) {
+ _stateGroup = new QDeclarativeStateGroup;
+ if (!componentComplete)
+ _stateGroup->classBegin();
+ QObject::connect(_stateGroup, SIGNAL(stateChanged(QString)),
+ q, SIGNAL(stateChanged(QString)));
+ }
+
+ return _stateGroup;
+}
+
+QSGItemPrivate::AnchorLines::AnchorLines(QSGItem *q)
+{
+ left.item = q;
+ left.anchorLine = QSGAnchorLine::Left;
+ right.item = q;
+ right.anchorLine = QSGAnchorLine::Right;
+ hCenter.item = q;
+ hCenter.anchorLine = QSGAnchorLine::HCenter;
+ top.item = q;
+ top.anchorLine = QSGAnchorLine::Top;
+ bottom.item = q;
+ bottom.anchorLine = QSGAnchorLine::Bottom;
+ vCenter.item = q;
+ vCenter.anchorLine = QSGAnchorLine::VCenter;
+ baseline.item = q;
+ baseline.anchorLine = QSGAnchorLine::Baseline;
+}
+
+QPointF QSGItemPrivate::computeTransformOrigin() const
+{
+ switch(origin) {
+ default:
+ case QSGItem::TopLeft:
+ return QPointF(0, 0);
+ case QSGItem::Top:
+ return QPointF(width / 2., 0);
+ case QSGItem::TopRight:
+ return QPointF(width, 0);
+ case QSGItem::Left:
+ return QPointF(0, height / 2.);
+ case QSGItem::Center:
+ return QPointF(width / 2., height / 2.);
+ case QSGItem::Right:
+ return QPointF(width, height / 2.);
+ case QSGItem::BottomLeft:
+ return QPointF(0, height);
+ case QSGItem::Bottom:
+ return QPointF(width / 2., height);
+ case QSGItem::BottomRight:
+ return QPointF(width, height);
+ }
+}
+
+void QSGItemPrivate::transformChanged()
+{
+}
+
+void QSGItemPrivate::deliverKeyEvent(QKeyEvent *e)
+{
+ Q_Q(QSGItem);
+
+ Q_ASSERT(e->isAccepted());
+ if (keyHandler) {
+ if (e->type() == QEvent::KeyPress)
+ keyHandler->keyPressed(e, false);
+ else
+ keyHandler->keyReleased(e, false);
+
+ if (e->isAccepted())
+ return;
+ else
+ e->accept();
+ }
+
+ if (e->type() == QEvent::KeyPress)
+ q->keyPressEvent(e);
+ else
+ q->keyReleaseEvent(e);
+
+ if (e->isAccepted())
+ return;
+
+ if (keyHandler) {
+ e->accept();
+
+ if (e->type() == QEvent::KeyPress)
+ keyHandler->keyPressed(e, true);
+ else
+ keyHandler->keyReleased(e, true);
+ }
+}
+
+void QSGItemPrivate::deliverInputMethodEvent(QInputMethodEvent *e)
+{
+ Q_Q(QSGItem);
+
+ Q_ASSERT(e->isAccepted());
+ if (keyHandler) {
+ keyHandler->inputMethodEvent(e, false);
+
+ if (e->isAccepted())
+ return;
+ else
+ e->accept();
+ }
+
+ q->inputMethodEvent(e);
+
+ if (e->isAccepted())
+ return;
+
+ if (keyHandler) {
+ e->accept();
+
+ keyHandler->inputMethodEvent(e, true);
+ }
+}
+
+void QSGItemPrivate::deliverFocusEvent(QFocusEvent *e)
+{
+ Q_Q(QSGItem);
+
+ if (e->type() == QEvent::FocusIn) {
+ q->focusInEvent(e);
+ } else {
+ q->focusOutEvent(e);
+ }
+}
+
+void QSGItemPrivate::deliverMouseEvent(QGraphicsSceneMouseEvent *e)
+{
+ Q_Q(QSGItem);
+
+ Q_ASSERT(e->isAccepted());
+
+ switch(e->type()) {
+ default:
+ Q_ASSERT(!"Unknown event type");
+ case QEvent::GraphicsSceneMouseMove:
+ q->mouseMoveEvent(e);
+ break;
+ case QEvent::GraphicsSceneMousePress:
+ q->mousePressEvent(e);
+ break;
+ case QEvent::GraphicsSceneMouseRelease:
+ q->mouseReleaseEvent(e);
+ break;
+ case QEvent::GraphicsSceneMouseDoubleClick:
+ q->mouseDoubleClickEvent(e);
+ break;
+ }
+}
+
+void QSGItemPrivate::deliverWheelEvent(QGraphicsSceneWheelEvent *e)
+{
+ Q_Q(QSGItem);
+ q->wheelEvent(e);
+}
+
+void QSGItemPrivate::deliverTouchEvent(QTouchEvent *e)
+{
+ Q_Q(QSGItem);
+ q->touchEvent(e);
+}
+
+void QSGItemPrivate::deliverHoverEvent(QGraphicsSceneHoverEvent *e)
+{
+ Q_Q(QSGItem);
+ switch(e->type()) {
+ default:
+ Q_ASSERT(!"Unknown event type");
+ case QEvent::GraphicsSceneHoverEnter:
+ q->hoverEnterEvent(e);
+ break;
+ case QEvent::GraphicsSceneHoverLeave:
+ q->hoverLeaveEvent(e);
+ break;
+ case QEvent::GraphicsSceneHoverMove:
+ q->hoverMoveEvent(e);
+ break;
+ }
+}
+
+void QSGItem::itemChange(ItemChange change, const ItemChangeData &value)
+{
+ Q_UNUSED(change);
+ Q_UNUSED(value);
+}
+
+/*! \internal */
+// XXX todo - do we want/need this anymore?
+QRectF QSGItem::boundingRect() const
+{
+ Q_D(const QSGItem);
+ return QRectF(0, 0, d->width, d->height);
+}
+
+QSGItem::TransformOrigin QSGItem::transformOrigin() const
+{
+ Q_D(const QSGItem);
+ return d->origin;
+}
+
+void QSGItem::setTransformOrigin(TransformOrigin origin)
+{
+ Q_D(QSGItem);
+ if (origin == d->origin)
+ return;
+
+ d->origin = origin;
+ d->dirty(QSGItemPrivate::TransformOrigin);
+
+ emit transformOriginChanged(d->origin);
+}
+
+QPointF QSGItem::transformOriginPoint() const
+{
+ Q_D(const QSGItem);
+ return d->computeTransformOrigin();
+}
+
+qreal QSGItem::z() const
+{
+ Q_D(const QSGItem);
+ return d->z;
+}
+
+void QSGItem::setZ(qreal v)
+{
+ Q_D(QSGItem);
+ if (d->z == v)
+ return;
+
+ d->z = v;
+
+ d->dirty(QSGItemPrivate::ZValue);
+ if (d->parentItem)
+ QSGItemPrivate::get(d->parentItem)->dirty(QSGItemPrivate::ChildrenStackingChanged);
+
+ emit zChanged();
+}
+
+qreal QSGItem::rotation() const
+{
+ Q_D(const QSGItem);
+ return d->rotation;
+}
+
+void QSGItem::setRotation(qreal r)
+{
+ Q_D(QSGItem);
+ if (d->rotation == r)
+ return;
+
+ d->rotation = r;
+
+ d->dirty(QSGItemPrivate::BasicTransform);
+
+ d->itemChange(ItemRotationHasChanged, r);
+
+ emit rotationChanged();
+}
+
+qreal QSGItem::scale() const
+{
+ Q_D(const QSGItem);
+ return d->scale;
+}
+
+void QSGItem::setScale(qreal s)
+{
+ Q_D(QSGItem);
+ if (d->scale == s)
+ return;
+
+ d->scale = s;
+
+ d->dirty(QSGItemPrivate::BasicTransform);
+
+ emit scaleChanged();
+}
+
+qreal QSGItem::opacity() const
+{
+ Q_D(const QSGItem);
+ return d->opacity;
+}
+
+void QSGItem::setOpacity(qreal o)
+{
+ Q_D(QSGItem);
+ if (d->opacity == o)
+ return;
+
+ d->opacity = o;
+
+ d->dirty(QSGItemPrivate::OpacityValue);
+
+ d->itemChange(ItemOpacityHasChanged, o);
+
+ emit opacityChanged();
+}
+
+bool QSGItem::isVisible() const
+{
+ Q_D(const QSGItem);
+ return d->effectiveVisible;
+}
+
+void QSGItem::setVisible(bool v)
+{
+ Q_D(QSGItem);
+ if (v == d->explicitVisible)
+ return;
+
+ d->explicitVisible = v;
+
+ d->setEffectiveVisibleRecur(d->calcEffectiveVisible());
+}
+
+bool QSGItem::isEnabled() const
+{
+ Q_D(const QSGItem);
+ return d->effectiveEnable;
+}
+
+void QSGItem::setEnabled(bool e)
+{
+ Q_D(QSGItem);
+ if (e == d->explicitEnable)
+ return;
+
+ d->explicitEnable = e;
+
+ d->setEffectiveEnableRecur(d->calcEffectiveEnable());
+}
+
+bool QSGItemPrivate::calcEffectiveVisible() const
+{
+ // XXX todo - Should the effective visible of an element with no parent just be the current
+ // effective visible? This would prevent pointless re-processing in the case of an element
+ // moving to/from a no-parent situation, but it is different from what graphics view does.
+ return explicitVisible && (!parentItem || QSGItemPrivate::get(parentItem)->effectiveVisible);
+}
+
+void QSGItemPrivate::setEffectiveVisibleRecur(bool newEffectiveVisible)
+{
+ Q_Q(QSGItem);
+
+ if (newEffectiveVisible && !explicitVisible) {
+ // This item locally overrides visibility
+ return;
+ }
+
+ if (newEffectiveVisible == effectiveVisible) {
+ // No change necessary
+ return;
+ }
+
+ effectiveVisible = newEffectiveVisible;
+ dirty(Visible);
+ if (parentItem) QSGItemPrivate::get(parentItem)->dirty(ChildrenStackingChanged);
+
+ if (canvas) {
+ QSGCanvasPrivate *canvasPriv = QSGCanvasPrivate::get(canvas);
+ if (canvasPriv->mouseGrabberItem == q)
+ q->ungrabMouse();
+ }
+
+ for (int ii = 0; ii < childItems.count(); ++ii)
+ QSGItemPrivate::get(childItems.at(ii))->setEffectiveVisibleRecur(newEffectiveVisible);
+
+ for(int ii = 0; ii < changeListeners.count(); ++ii) {
+ const QSGItemPrivate::ChangeListener &change = changeListeners.at(ii);
+ if (change.types & QSGItemPrivate::Visibility)
+ change.listener->itemVisibilityChanged(q);
+ }
+
+ emit q->visibleChanged();
+}
+
+bool QSGItemPrivate::calcEffectiveEnable() const
+{
+ // XXX todo - Should the effective enable of an element with no parent just be the current
+ // effective enable? This would prevent pointless re-processing in the case of an element
+ // moving to/from a no-parent situation, but it is different from what graphics view does.
+ return explicitEnable && (!parentItem || QSGItemPrivate::get(parentItem)->effectiveEnable);
+}
+
+void QSGItemPrivate::setEffectiveEnableRecur(bool newEffectiveEnable)
+{
+ Q_Q(QSGItem);
+
+ // XXX todo - need to fixup focus
+
+ if (newEffectiveEnable && !explicitEnable) {
+ // This item locally overrides enable
+ return;
+ }
+
+ if (newEffectiveEnable == effectiveEnable) {
+ // No change necessary
+ return;
+ }
+
+ effectiveEnable = newEffectiveEnable;
+
+ if (canvas) {
+ QSGCanvasPrivate *canvasPriv = QSGCanvasPrivate::get(canvas);
+ if (canvasPriv->mouseGrabberItem == q)
+ q->ungrabMouse();
+ }
+
+ for (int ii = 0; ii < childItems.count(); ++ii)
+ QSGItemPrivate::get(childItems.at(ii))->setEffectiveEnableRecur(newEffectiveEnable);
+
+ emit q->enabledChanged();
+}
+
+QString QSGItemPrivate::dirtyToString() const
+{
+#define DIRTY_TO_STRING(value) if (dirtyAttributes & value) { \
+ if (!rv.isEmpty()) \
+ rv.append(QLatin1String("|")); \
+ rv.append(QLatin1String(#value)); \
+}
+
+// QString rv = QLatin1String("0x") + QString::number(dirtyAttributes, 16);
+ QString rv;
+
+ DIRTY_TO_STRING(TransformOrigin);
+ DIRTY_TO_STRING(Transform);
+ DIRTY_TO_STRING(BasicTransform);
+ DIRTY_TO_STRING(Position);
+ DIRTY_TO_STRING(Size);
+ DIRTY_TO_STRING(ZValue);
+ DIRTY_TO_STRING(Content);
+ DIRTY_TO_STRING(Smooth);
+ DIRTY_TO_STRING(OpacityValue);
+ DIRTY_TO_STRING(ChildrenChanged);
+ DIRTY_TO_STRING(ChildrenStackingChanged);
+ DIRTY_TO_STRING(ParentChanged);
+ DIRTY_TO_STRING(Clip);
+ DIRTY_TO_STRING(Canvas);
+ DIRTY_TO_STRING(EffectReference);
+ DIRTY_TO_STRING(Visible);
+ DIRTY_TO_STRING(HideReference);
+
+ return rv;
+}
+
+void QSGItemPrivate::dirty(DirtyType type)
+{
+ Q_Q(QSGItem);
+ if (type & (TransformOrigin | Transform | BasicTransform | Position | Size))
+ transformChanged();
+
+ if (!(dirtyAttributes & type) || (canvas && !prevDirtyItem)) {
+ dirtyAttributes |= type;
+ if (canvas) {
+ addToDirtyList();
+ QSGCanvasPrivate::get(canvas)->dirtyItem(q);
+ }
+ }
+}
+
+void QSGItemPrivate::addToDirtyList()
+{
+ Q_Q(QSGItem);
+
+ Q_ASSERT(canvas);
+ if (!prevDirtyItem) {
+ Q_ASSERT(!nextDirtyItem);
+
+ QSGCanvasPrivate *p = QSGCanvasPrivate::get(canvas);
+ nextDirtyItem = p->dirtyItemList;
+ if (nextDirtyItem) QSGItemPrivate::get(nextDirtyItem)->prevDirtyItem = &nextDirtyItem;
+ prevDirtyItem = &p->dirtyItemList;
+ p->dirtyItemList = q;
+ p->dirtyItem(q);
+ }
+ Q_ASSERT(prevDirtyItem);
+}
+
+void QSGItemPrivate::removeFromDirtyList()
+{
+ if (prevDirtyItem) {
+ if (nextDirtyItem) QSGItemPrivate::get(nextDirtyItem)->prevDirtyItem = prevDirtyItem;
+ *prevDirtyItem = nextDirtyItem;
+ prevDirtyItem = 0;
+ nextDirtyItem = 0;
+ }
+ Q_ASSERT(!prevDirtyItem);
+ Q_ASSERT(!nextDirtyItem);
+}
+
+void QSGItemPrivate::refFromEffectItem(bool hide)
+{
+ ++effectRefCount;
+ if (1 == effectRefCount) {
+ dirty(EffectReference);
+ if (parentItem) QSGItemPrivate::get(parentItem)->dirty(ChildrenStackingChanged);
+ }
+ if (hide) {
+ if (++hideRefCount == 1)
+ dirty(HideReference);
+ }
+}
+
+void QSGItemPrivate::derefFromEffectItem(bool unhide)
+{
+ Q_ASSERT(effectRefCount);
+ --effectRefCount;
+ if (0 == effectRefCount) {
+ dirty(EffectReference);
+ if (parentItem) QSGItemPrivate::get(parentItem)->dirty(ChildrenStackingChanged);
+ }
+ if (unhide) {
+ if (--hideRefCount == 0)
+ dirty(HideReference);
+ }
+}
+
+void QSGItemPrivate::itemChange(QSGItem::ItemChange change, const QSGItem::ItemChangeData &data)
+{
+ Q_Q(QSGItem);
+ switch(change) {
+ case QSGItem::ItemChildAddedChange:
+ q->itemChange(change, data);
+ if (_contents && componentComplete)
+ _contents->childAdded(data.item);
+ for(int ii = 0; ii < changeListeners.count(); ++ii) {
+ const QSGItemPrivate::ChangeListener &change = changeListeners.at(ii);
+ if (change.types & QSGItemPrivate::Children) {
+ change.listener->itemChildAdded(q, data.item);
+ }
+ }
+ break;
+ case QSGItem::ItemChildRemovedChange:
+ q->itemChange(change, data);
+ if (_contents && componentComplete)
+ _contents->childRemoved(data.item);
+ for(int ii = 0; ii < changeListeners.count(); ++ii) {
+ const QSGItemPrivate::ChangeListener &change = changeListeners.at(ii);
+ if (change.types & QSGItemPrivate::Children) {
+ change.listener->itemChildRemoved(q, data.item);
+ }
+ }
+ break;
+ case QSGItem::ItemSceneChange:
+ q->itemChange(change, data);
+ break;
+ case QSGItem::ItemVisibleHasChanged:
+ q->itemChange(change, data);
+ for(int ii = 0; ii < changeListeners.count(); ++ii) {
+ const QSGItemPrivate::ChangeListener &change = changeListeners.at(ii);
+ if (change.types & QSGItemPrivate::Visibility) {
+ change.listener->itemVisibilityChanged(q);
+ }
+ }
+ break;
+ case QSGItem::ItemParentHasChanged:
+ q->itemChange(change, data);
+ for(int ii = 0; ii < changeListeners.count(); ++ii) {
+ const QSGItemPrivate::ChangeListener &change = changeListeners.at(ii);
+ if (change.types & QSGItemPrivate::Parent) {
+ change.listener->itemParentChanged(q, data.item);
+ }
+ }
+ break;
+ case QSGItem::ItemOpacityHasChanged:
+ q->itemChange(change, data);
+ for(int ii = 0; ii < changeListeners.count(); ++ii) {
+ const QSGItemPrivate::ChangeListener &change = changeListeners.at(ii);
+ if (change.types & QSGItemPrivate::Opacity) {
+ change.listener->itemOpacityChanged(q);
+ }
+ }
+ break;
+ case QSGItem::ItemActiveFocusHasChanged:
+ q->itemChange(change, data);
+ break;
+ case QSGItem::ItemRotationHasChanged:
+ q->itemChange(change, data);
+ for(int ii = 0; ii < changeListeners.count(); ++ii) {
+ const QSGItemPrivate::ChangeListener &change = changeListeners.at(ii);
+ if (change.types & QSGItemPrivate::Rotation) {
+ change.listener->itemRotationChanged(q);
+ }
+ }
+ break;
+ }
+}
+
+bool QSGItem::smooth() const
+{
+ Q_D(const QSGItem);
+ return d->smooth;
+}
+
+void QSGItem::setSmooth(bool smooth)
+{
+ Q_D(QSGItem);
+ if (d->smooth == smooth)
+ return;
+
+ d->smooth = smooth;
+ d->dirty(QSGItemPrivate::Smooth);
+
+ emit smoothChanged(smooth);
+}
+
+QSGItem::Flags QSGItem::flags() const
+{
+ Q_D(const QSGItem);
+ return (QSGItem::Flags)d->flags;
+}
+
+void QSGItem::setFlag(Flag flag, bool enabled)
+{
+ Q_D(QSGItem);
+ if (enabled)
+ setFlags((Flags)(d->flags | (quint32)flag));
+ else
+ setFlags((Flags)(d->flags & ~(quint32)flag));
+}
+
+void QSGItem::setFlags(Flags flags)
+{
+ Q_D(QSGItem);
+
+ if ((flags & ItemIsFocusScope) != (d->flags & ItemIsFocusScope)) {
+ if (flags & ItemIsFocusScope && !d->childItems.isEmpty() && d->canvas) {
+ qWarning("QSGItem: Cannot set FocusScope once item has children and is in a canvas.");
+ flags &= ~ItemIsFocusScope;
+ } else if (d->flags & ItemIsFocusScope) {
+ qWarning("QSGItem: Cannot unset FocusScope flag.");
+ flags |= ItemIsFocusScope;
+ }
+ }
+
+ if ((flags & ItemClipsChildrenToShape ) != (d->flags & ItemClipsChildrenToShape))
+ d->dirty(QSGItemPrivate::Clip);
+
+ d->flags = flags;
+}
+
+qreal QSGItem::x() const
+{
+ Q_D(const QSGItem);
+ return d->x;
+}
+
+qreal QSGItem::y() const
+{
+ Q_D(const QSGItem);
+ return d->y;
+}
+
+QPointF QSGItem::pos() const
+{
+ Q_D(const QSGItem);
+ return QPointF(d->x, d->y);
+}
+
+void QSGItem::setX(qreal v)
+{
+ Q_D(QSGItem);
+ if (d->x == v)
+ return;
+
+ qreal oldx = d->x;
+ d->x = v;
+
+ d->dirty(QSGItemPrivate::Position);
+
+ geometryChanged(QRectF(x(), y(), width(), height()),
+ QRectF(oldx, y(), width(), height()));
+}
+
+void QSGItem::setY(qreal v)
+{
+ Q_D(QSGItem);
+ if (d->y == v)
+ return;
+
+ qreal oldy = d->y;
+ d->y = v;
+
+ d->dirty(QSGItemPrivate::Position);
+
+ geometryChanged(QRectF(x(), y(), width(), height()),
+ QRectF(x(), oldy, width(), height()));
+}
+
+void QSGItem::setPos(const QPointF &pos)
+{
+ Q_D(QSGItem);
+ if (QPointF(d->x, d->y) == pos)
+ return;
+
+ qreal oldx = d->x;
+ qreal oldy = d->y;
+
+ d->x = pos.x();
+ d->y = pos.y();
+
+ d->dirty(QSGItemPrivate::Position);
+
+ geometryChanged(QRectF(x(), y(), width(), height()),
+ QRectF(oldx, oldy, width(), height()));
+}
+
+qreal QSGItem::width() const
+{
+ Q_D(const QSGItem);
+ return d->width;
+}
+
+void QSGItem::setWidth(qreal w)
+{
+ Q_D(QSGItem);
+ if (qIsNaN(w))
+ return;
+
+ d->widthValid = true;
+ if (d->width == w)
+ return;
+
+ qreal oldWidth = d->width;
+ d->width = w;
+
+ d->dirty(QSGItemPrivate::Size);
+
+ geometryChanged(QRectF(x(), y(), width(), height()),
+ QRectF(x(), y(), oldWidth, height()));
+}
+
+void QSGItem::resetWidth()
+{
+ Q_D(QSGItem);
+ d->widthValid = false;
+ setImplicitWidth(implicitWidth());
+}
+
+void QSGItemPrivate::implicitWidthChanged()
+{
+ Q_Q(QSGItem);
+ emit q->implicitWidthChanged();
+}
+
+qreal QSGItemPrivate::getImplicitWidth() const
+{
+ return implicitWidth;
+}
+
+qreal QSGItem::implicitWidth() const
+{
+ Q_D(const QSGItem);
+ return d->getImplicitWidth();
+}
+
+void QSGItem::setImplicitWidth(qreal w)
+{
+ Q_D(QSGItem);
+ bool changed = w != d->implicitWidth;
+ d->implicitWidth = w;
+ if (d->width == w || widthValid()) {
+ if (changed)
+ d->implicitWidthChanged();
+ return;
+ }
+
+ qreal oldWidth = d->width;
+ d->width = w;
+
+ d->dirty(QSGItemPrivate::Size);
+
+ geometryChanged(QRectF(x(), y(), width(), height()),
+ QRectF(x(), y(), oldWidth, height()));
+
+ if (changed)
+ d->implicitWidthChanged();
+}
+
+bool QSGItem::widthValid() const
+{
+ Q_D(const QSGItem);
+ return d->widthValid;
+}
+
+qreal QSGItem::height() const
+{
+ Q_D(const QSGItem);
+ return d->height;
+}
+
+void QSGItem::setHeight(qreal h)
+{
+ Q_D(QSGItem);
+ if (qIsNaN(h))
+ return;
+
+ d->heightValid = true;
+ if (d->height == h)
+ return;
+
+ qreal oldHeight = d->height;
+ d->height = h;
+
+ d->dirty(QSGItemPrivate::Size);
+
+ geometryChanged(QRectF(x(), y(), width(), height()),
+ QRectF(x(), y(), width(), oldHeight));
+}
+
+void QSGItem::resetHeight()
+{
+ Q_D(QSGItem);
+ d->heightValid = false;
+ setImplicitHeight(implicitHeight());
+}
+
+void QSGItemPrivate::implicitHeightChanged()
+{
+ Q_Q(QSGItem);
+ emit q->implicitHeightChanged();
+}
+
+qreal QSGItemPrivate::getImplicitHeight() const
+{
+ return implicitHeight;
+}
+
+qreal QSGItem::implicitHeight() const
+{
+ Q_D(const QSGItem);
+ return d->getImplicitHeight();
+}
+
+void QSGItem::setImplicitHeight(qreal h)
+{
+ Q_D(QSGItem);
+ bool changed = h != d->implicitHeight;
+ d->implicitHeight = h;
+ if (d->height == h || heightValid()) {
+ if (changed)
+ d->implicitHeightChanged();
+ return;
+ }
+
+ qreal oldHeight = d->height;
+ d->height = h;
+
+ d->dirty(QSGItemPrivate::Size);
+
+ geometryChanged(QRectF(x(), y(), width(), height()),
+ QRectF(x(), y(), width(), oldHeight));
+
+ if (changed)
+ d->implicitHeightChanged();
+}
+
+bool QSGItem::heightValid() const
+{
+ Q_D(const QSGItem);
+ return d->heightValid;
+}
+
+void QSGItem::setSize(const QSizeF &size)
+{
+ Q_D(QSGItem);
+ d->heightValid = true;
+ d->widthValid = true;
+
+ if (QSizeF(d->width, d->height) == size)
+ return;
+
+ qreal oldHeight = d->height;
+ qreal oldWidth = d->width;
+ d->height = size.height();
+ d->width = size.width();
+
+ d->dirty(QSGItemPrivate::Size);
+
+ geometryChanged(QRectF(x(), y(), width(), height()),
+ QRectF(x(), y(), oldWidth, oldHeight));
+}
+
+bool QSGItem::hasActiveFocus() const
+{
+ Q_D(const QSGItem);
+ return d->activeFocus;
+}
+
+bool QSGItem::hasFocus() const
+{
+ Q_D(const QSGItem);
+ return d->focus;
+}
+
+void QSGItem::setFocus(bool focus)
+{
+ Q_D(QSGItem);
+ if (d->focus == focus)
+ return;
+
+ if (d->canvas) {
+ // Need to find our nearest focus scope
+ QSGItem *scope = parentItem();
+ while (scope && !scope->isFocusScope())
+ scope = scope->parentItem();
+ if (focus)
+ QSGCanvasPrivate::get(d->canvas)->setFocusInScope(scope, this);
+ else
+ QSGCanvasPrivate::get(d->canvas)->clearFocusInScope(scope, this);
+ } else {
+ d->focus = focus;
+ emit focusChanged(focus);
+ }
+}
+
+bool QSGItem::isFocusScope() const
+{
+ return flags() & ItemIsFocusScope;
+}
+
+QSGItem *QSGItem::scopedFocusItem() const
+{
+ Q_D(const QSGItem);
+ if (!isFocusScope())
+ return 0;
+ else
+ return d->subFocusItem;
+}
+
+
+Qt::MouseButtons QSGItem::acceptedMouseButtons() const
+{
+ Q_D(const QSGItem);
+ return d->acceptedMouseButtons;
+}
+
+void QSGItem::setAcceptedMouseButtons(Qt::MouseButtons buttons)
+{
+ Q_D(QSGItem);
+ d->acceptedMouseButtons = buttons;
+}
+
+bool QSGItem::filtersChildMouseEvents() const
+{
+ Q_D(const QSGItem);
+ return d->filtersChildMouseEvents;
+}
+
+void QSGItem::setFiltersChildMouseEvents(bool filter)
+{
+ Q_D(QSGItem);
+ d->filtersChildMouseEvents = filter;
+}
+
+bool QSGItem::isUnderMouse() const
+{
+ Q_D(const QSGItem);
+ if (!d->canvas)
+ return false;
+
+ QPoint cursorPos = QCursor::pos();
+ if (QRectF(0, 0, width(), height()).contains(mapFromScene(d->canvas->mapFromGlobal(cursorPos))))
+ return true;
+ return false;
+}
+
+bool QSGItem::acceptHoverEvents() const
+{
+ Q_D(const QSGItem);
+ return d->hoverEnabled;
+}
+
+void QSGItem::setAcceptHoverEvents(bool enabled)
+{
+ Q_D(QSGItem);
+ d->hoverEnabled = enabled;
+
+ if (d->canvas && d->hoverEnabled && !d->canvas->hasMouseTracking())
+ d->canvas->setMouseTracking(true);
+}
+
+void QSGItem::grabMouse()
+{
+ Q_D(QSGItem);
+ if (!d->canvas)
+ return;
+ QSGCanvasPrivate *canvasPriv = QSGCanvasPrivate::get(d->canvas);
+ if (canvasPriv->mouseGrabberItem == this)
+ return;
+
+ QSGItem *oldGrabber = canvasPriv->mouseGrabberItem;
+ canvasPriv->mouseGrabberItem = this;
+ if (oldGrabber)
+ oldGrabber->mouseUngrabEvent();
+}
+
+void QSGItem::ungrabMouse()
+{
+ Q_D(QSGItem);
+ if (!d->canvas)
+ return;
+ QSGCanvasPrivate *canvasPriv = QSGCanvasPrivate::get(d->canvas);
+ if (canvasPriv->mouseGrabberItem != this) {
+ qWarning("QSGItem::ungrabMouse(): Item is not the mouse grabber.");
+ return;
+ }
+
+ canvasPriv->mouseGrabberItem = 0;
+ mouseUngrabEvent();
+}
+
+bool QSGItem::keepMouseGrab() const
+{
+ Q_D(const QSGItem);
+ return d->keepMouse;
+}
+
+void QSGItem::setKeepMouseGrab(bool keep)
+{
+ Q_D(QSGItem);
+ d->keepMouse = keep;
+}
+
+QPointF QSGItem::mapToItem(const QSGItem *item, const QPointF &point) const
+{
+ QPointF p = mapToScene(point);
+ if (item)
+ p = item->mapFromScene(p);
+ return p;
+}
+
+QPointF QSGItem::mapToScene(const QPointF &point) const
+{
+ Q_D(const QSGItem);
+ return d->itemToCanvasTransform().map(point);
+}
+
+QRectF QSGItem::mapRectToItem(const QSGItem *item, const QRectF &rect) const
+{
+ Q_D(const QSGItem);
+ QTransform t = d->itemToCanvasTransform();
+ if (item)
+ t *= QSGItemPrivate::get(item)->canvasToItemTransform();
+ return t.mapRect(rect);
+}
+
+QRectF QSGItem::mapRectToScene(const QRectF &rect) const
+{
+ Q_D(const QSGItem);
+ return d->itemToCanvasTransform().mapRect(rect);
+}
+
+QPointF QSGItem::mapFromItem(const QSGItem *item, const QPointF &point) const
+{
+ QPointF p = item?item->mapToScene(point):point;
+ return mapFromScene(p);
+}
+
+QPointF QSGItem::mapFromScene(const QPointF &point) const
+{
+ Q_D(const QSGItem);
+ return d->canvasToItemTransform().map(point);
+}
+
+QRectF QSGItem::mapRectFromItem(const QSGItem *item, const QRectF &rect) const
+{
+ Q_D(const QSGItem);
+ QTransform t = item?QSGItemPrivate::get(item)->itemToCanvasTransform():QTransform();
+ t *= d->canvasToItemTransform();
+ return t.mapRect(rect);
+}
+
+QRectF QSGItem::mapRectFromScene(const QRectF &rect) const
+{
+ Q_D(const QSGItem);
+ return d->canvasToItemTransform().mapRect(rect);
+}
+
+bool QSGItem::event(QEvent *ev)
+{
+ return QObject::event(ev);
+
+#if 0
+ if (ev->type() == QEvent::PolishRequest) {
+ Q_D(QSGItem);
+ d->polishScheduled = false;
+ updatePolish();
+ return true;
+ } else {
+ return QObject::event(ev);
+ }
+#endif
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug debug, QSGItem *item)
+{
+ if (!item) {
+ debug << "QSGItem(0)";
+ return debug;
+ }
+
+ debug << item->metaObject()->className() << "(this =" << ((void*)item)
+ << ", name=" << item->objectName()
+ << ", parent =" << ((void*)item->parentItem())
+ << ", geometry =" << QRectF(item->pos(), QSizeF(item->width(), item->height()))
+ << ", z =" << item->z() << ')';
+ return debug;
+}
+#endif
+
+qint64 QSGItemPrivate::consistentTime = -1;
+void QSGItemPrivate::setConsistentTime(qint64 t)
+{
+ consistentTime = t;
+}
+
+class QElapsedTimerConsistentTimeHack
+{
+public:
+ void start() {
+ t1 = QSGItemPrivate::consistentTime;
+ t2 = 0;
+ }
+ qint64 elapsed() {
+ return QSGItemPrivate::consistentTime - t1;
+ }
+ qint64 restart() {
+ qint64 val = QSGItemPrivate::consistentTime - t1;
+ t1 = QSGItemPrivate::consistentTime;
+ t2 = 0;
+ return val;
+ }
+
+private:
+ qint64 t1;
+ qint64 t2;
+};
+
+void QSGItemPrivate::start(QElapsedTimer &t)
+{
+ if (QSGItemPrivate::consistentTime == -1)
+ t.start();
+ else
+ ((QElapsedTimerConsistentTimeHack*)&t)->start();
+}
+
+qint64 QSGItemPrivate::elapsed(QElapsedTimer &t)
+{
+ if (QSGItemPrivate::consistentTime == -1)
+ return t.elapsed();
+ else
+ return ((QElapsedTimerConsistentTimeHack*)&t)->elapsed();
+}
+
+qint64 QSGItemPrivate::restart(QElapsedTimer &t)
+{
+ if (QSGItemPrivate::consistentTime == -1)
+ return t.restart();
+ else
+ return ((QElapsedTimerConsistentTimeHack*)&t)->restart();
+}
+
+QT_END_NAMESPACE
+
+#include <moc_qsgitem.cpp>
diff --git a/src/declarative/items/qsgitem.h b/src/declarative/items/qsgitem.h
new file mode 100644
index 0000000000..564d819000
--- /dev/null
+++ b/src/declarative/items/qsgitem.h
@@ -0,0 +1,399 @@
+// Commit: 6f78a6080b84cc3ef96b73a4ff58d1b5a72f08f4
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGITEM_H
+#define QSGITEM_H
+
+#include <QtDeclarative/qdeclarative.h>
+#include <QtDeclarative/qdeclarativecomponent.h>
+
+#include <QtCore/QObject>
+#include <QtCore/QList>
+#include <QtGui/qgraphicssceneevent.h>
+#include <QtGui/qfont.h>
+#include <QtGui/qaction.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QSGItem;
+class QSGTransformPrivate;
+class QSGTransform : public QObject
+{
+ Q_OBJECT
+public:
+ QSGTransform(QObject *parent = 0);
+ ~QSGTransform();
+
+ void appendToItem(QSGItem *);
+ void prependToItem(QSGItem *);
+
+ virtual void applyTo(QMatrix4x4 *matrix) const = 0;
+
+protected Q_SLOTS:
+ void update();
+
+protected:
+ QSGTransform(QSGTransformPrivate &dd, QObject *parent);
+
+private:
+ Q_DECLARE_PRIVATE(QSGTransform);
+};
+
+class QDeclarativeState;
+class QSGAnchorLine;
+class QDeclarativeTransition;
+class QSGKeyEvent;
+class QSGAnchors;
+class QSGItemPrivate;
+class QSGCanvas;
+class QSGEngine;
+class QTouchEvent;
+class QSGNode;
+class QSGTransformNode;
+class Q_DECLARATIVE_EXPORT QSGItem : public QObject, public QDeclarativeParserStatus
+{
+ Q_OBJECT
+ Q_INTERFACES(QDeclarativeParserStatus)
+
+ Q_PROPERTY(QSGItem *parent READ parentItem WRITE setParentItem NOTIFY parentChanged DESIGNABLE false FINAL)
+ Q_PRIVATE_PROPERTY(QSGItem::d_func(), QDeclarativeListProperty<QObject> data READ data DESIGNABLE false)
+ Q_PRIVATE_PROPERTY(QSGItem::d_func(), QDeclarativeListProperty<QObject> resources READ resources DESIGNABLE false)
+ Q_PRIVATE_PROPERTY(QSGItem::d_func(), QDeclarativeListProperty<QSGItem> children READ children NOTIFY childrenChanged DESIGNABLE false)
+
+ Q_PROPERTY(QPointF pos READ pos FINAL)
+ Q_PROPERTY(qreal x READ x WRITE setX NOTIFY xChanged FINAL)
+ Q_PROPERTY(qreal y READ y WRITE setY NOTIFY yChanged FINAL)
+ Q_PROPERTY(qreal z READ z WRITE setZ NOTIFY zChanged FINAL)
+ Q_PROPERTY(qreal width READ width WRITE setWidth NOTIFY widthChanged RESET resetWidth FINAL)
+ Q_PROPERTY(qreal height READ height WRITE setHeight NOTIFY heightChanged RESET resetHeight FINAL)
+
+ Q_PROPERTY(qreal opacity READ opacity WRITE setOpacity NOTIFY opacityChanged FINAL)
+ Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled NOTIFY enabledChanged)
+ Q_PROPERTY(bool visible READ isVisible WRITE setVisible NOTIFY visibleChanged FINAL)
+
+ Q_PRIVATE_PROPERTY(QSGItem::d_func(), QDeclarativeListProperty<QDeclarativeState> states READ states DESIGNABLE false)
+ Q_PRIVATE_PROPERTY(QSGItem::d_func(), QDeclarativeListProperty<QDeclarativeTransition> transitions READ transitions DESIGNABLE false)
+ Q_PRIVATE_PROPERTY(QSGItem::d_func(), QString state READ state WRITE setState NOTIFY stateChanged)
+ Q_PROPERTY(QRectF childrenRect READ childrenRect NOTIFY childrenRectChanged DESIGNABLE false FINAL)
+ Q_PRIVATE_PROPERTY(QSGItem::d_func(), QSGAnchors * anchors READ anchors DESIGNABLE false CONSTANT FINAL)
+ Q_PRIVATE_PROPERTY(QSGItem::d_func(), QSGAnchorLine left READ left CONSTANT FINAL)
+ Q_PRIVATE_PROPERTY(QSGItem::d_func(), QSGAnchorLine right READ right CONSTANT FINAL)
+ Q_PRIVATE_PROPERTY(QSGItem::d_func(), QSGAnchorLine horizontalCenter READ horizontalCenter CONSTANT FINAL)
+ Q_PRIVATE_PROPERTY(QSGItem::d_func(), QSGAnchorLine top READ top CONSTANT FINAL)
+ Q_PRIVATE_PROPERTY(QSGItem::d_func(), QSGAnchorLine bottom READ bottom CONSTANT FINAL)
+ Q_PRIVATE_PROPERTY(QSGItem::d_func(), QSGAnchorLine verticalCenter READ verticalCenter CONSTANT FINAL)
+ Q_PRIVATE_PROPERTY(QSGItem::d_func(), QSGAnchorLine baseline READ baseline CONSTANT FINAL)
+ Q_PROPERTY(qreal baselineOffset READ baselineOffset WRITE setBaselineOffset NOTIFY baselineOffsetChanged)
+
+ Q_PROPERTY(bool clip READ clip WRITE setClip NOTIFY clipChanged)
+
+ Q_PROPERTY(bool focus READ hasFocus WRITE setFocus NOTIFY focusChanged FINAL)
+ Q_PROPERTY(bool activeFocus READ hasActiveFocus NOTIFY activeFocusChanged FINAL)
+
+ Q_PROPERTY(qreal rotation READ rotation WRITE setRotation NOTIFY rotationChanged)
+ Q_PROPERTY(qreal scale READ scale WRITE setScale NOTIFY scaleChanged)
+ Q_PROPERTY(TransformOrigin transformOrigin READ transformOrigin WRITE setTransformOrigin NOTIFY transformOriginChanged)
+ Q_PROPERTY(QPointF transformOriginPoint READ transformOriginPoint) // XXX todo - notify?
+ Q_PROPERTY(QDeclarativeListProperty<QSGTransform> transform READ transform DESIGNABLE false FINAL)
+
+ Q_PROPERTY(bool smooth READ smooth WRITE setSmooth NOTIFY smoothChanged)
+ Q_PROPERTY(qreal implicitWidth READ implicitWidth WRITE setImplicitWidth NOTIFY implicitWidthChanged)
+ Q_PROPERTY(qreal implicitHeight READ implicitHeight WRITE setImplicitHeight NOTIFY implicitHeightChanged)
+
+ Q_ENUMS(TransformOrigin)
+ Q_CLASSINFO("DefaultProperty", "data")
+
+public:
+ enum Flag {
+ ItemClipsChildrenToShape = 0x01,
+ ItemAcceptsInputMethod = 0x02,
+ ItemIsFocusScope = 0x04,
+ ItemHasContents = 0x08,
+ // Remember to increment the size of QSGItemPrivate::flags
+ };
+ Q_DECLARE_FLAGS(Flags, Flag)
+
+ enum ItemChange {
+ ItemChildAddedChange, // value.item
+ ItemChildRemovedChange, // value.item
+ ItemSceneChange, // value.canvas
+ ItemVisibleHasChanged, // value.realValue
+ ItemParentHasChanged, // value.item
+ ItemOpacityHasChanged, // value.realValue
+ ItemActiveFocusHasChanged, // value.boolValue
+ ItemRotationHasChanged, // value.realValue
+ };
+
+ union ItemChangeData {
+ ItemChangeData(QSGItem *v) : item(v) {}
+ ItemChangeData(QSGCanvas *v) : canvas(v) {}
+ ItemChangeData(qreal v) : realValue(v) {}
+ ItemChangeData(bool v) : boolValue(v) {}
+
+ QSGItem *item;
+ QSGCanvas *canvas;
+ qreal realValue;
+ bool boolValue;
+ };
+
+ enum TransformOrigin {
+ TopLeft, Top, TopRight,
+ Left, Center, Right,
+ BottomLeft, Bottom, BottomRight
+ };
+
+ QSGItem(QSGItem *parent = 0);
+ virtual ~QSGItem();
+
+ QSGEngine *sceneGraphEngine() const;
+
+ QSGCanvas *canvas() const;
+ QSGItem *parentItem() const;
+ void setParentItem(QSGItem *parent);
+ void stackBefore(const QSGItem *);
+ void stackAfter(const QSGItem *);
+
+ QRectF childrenRect();
+ QList<QSGItem *> childItems() const;
+
+ bool clip() const;
+ void setClip(bool);
+
+ qreal baselineOffset() const;
+ void setBaselineOffset(qreal);
+
+ QDeclarativeListProperty<QSGTransform> transform();
+
+ qreal x() const;
+ qreal y() const;
+ QPointF pos() const;
+ void setX(qreal);
+ void setY(qreal);
+ void setPos(const QPointF &);
+
+ qreal width() const;
+ void setWidth(qreal);
+ void resetWidth();
+ qreal implicitWidth() const;
+
+ qreal height() const;
+ void setHeight(qreal);
+ void resetHeight();
+ qreal implicitHeight() const;
+
+ void setSize(const QSizeF &size);
+
+ TransformOrigin transformOrigin() const;
+ void setTransformOrigin(TransformOrigin);
+ QPointF transformOriginPoint() const;
+
+ qreal z() const;
+ void setZ(qreal);
+
+ qreal rotation() const;
+ void setRotation(qreal);
+ qreal scale() const;
+ void setScale(qreal);
+
+ qreal opacity() const;
+ void setOpacity(qreal);
+
+ bool isVisible() const;
+ void setVisible(bool);
+
+ bool isEnabled() const;
+ void setEnabled(bool);
+
+ bool smooth() const;
+ void setSmooth(bool);
+
+ Flags flags() const;
+ void setFlag(Flag flag, bool enabled = true);
+ void setFlags(Flags flags);
+
+ QRectF boundingRect() const;
+
+ bool hasActiveFocus() const;
+ bool hasFocus() const;
+ void setFocus(bool);
+ bool isFocusScope() const;
+ QSGItem *scopedFocusItem() const;
+
+ Qt::MouseButtons acceptedMouseButtons() const;
+ void setAcceptedMouseButtons(Qt::MouseButtons buttons);
+ bool acceptHoverEvents() const;
+ void setAcceptHoverEvents(bool enabled);
+
+ bool isUnderMouse() const;
+ void grabMouse();
+ void ungrabMouse();
+ bool keepMouseGrab() const;
+ void setKeepMouseGrab(bool);
+ bool filtersChildMouseEvents() const;
+ void setFiltersChildMouseEvents(bool filter);
+
+ QTransform itemTransform(QSGItem *, bool *) const;
+ QPointF mapToItem(const QSGItem *item, const QPointF &point) const;
+ QPointF mapToScene(const QPointF &point) const;
+ QRectF mapRectToItem(const QSGItem *item, const QRectF &rect) const;
+ QRectF mapRectToScene(const QRectF &rect) const;
+ QPointF mapFromItem(const QSGItem *item, const QPointF &point) const;
+ QPointF mapFromScene(const QPointF &point) const;
+ QRectF mapRectFromItem(const QSGItem *item, const QRectF &rect) const;
+ QRectF mapRectFromScene(const QRectF &rect) const;
+
+ void polish();
+
+ Q_INVOKABLE QScriptValue mapFromItem(const QScriptValue &item, qreal x, qreal y) const;
+ Q_INVOKABLE QScriptValue mapToItem(const QScriptValue &item, qreal x, qreal y) const;
+ Q_INVOKABLE void forceActiveFocus();
+ Q_INVOKABLE QSGItem *childAt(qreal x, qreal y) const;
+
+ Qt::InputMethodHints inputMethodHints() const;
+ void setInputMethodHints(Qt::InputMethodHints hints);
+ virtual QVariant inputMethodQuery(Qt::InputMethodQuery query) const;
+
+ struct UpdatePaintNodeData {
+ QSGTransformNode *transformNode;
+ private:
+ friend class QSGCanvasPrivate;
+ UpdatePaintNodeData();
+ };
+
+public Q_SLOTS:
+ void update();
+ void updateMicroFocus();
+
+Q_SIGNALS:
+ void childrenRectChanged(const QRectF &);
+ void baselineOffsetChanged(qreal);
+ void stateChanged(const QString &);
+ void focusChanged(bool);
+ void activeFocusChanged(bool);
+ void parentChanged(QSGItem *);
+ void transformOriginChanged(TransformOrigin);
+ void smoothChanged(bool);
+ void clipChanged(bool);
+
+ // XXX todo
+ void childrenChanged();
+ void opacityChanged();
+ void enabledChanged();
+ void visibleChanged();
+ void rotationChanged();
+ void scaleChanged();
+
+ void xChanged();
+ void yChanged();
+ void widthChanged();
+ void heightChanged();
+ void zChanged();
+ void implicitWidthChanged();
+ void implicitHeightChanged();
+
+protected:
+ virtual bool event(QEvent *);
+
+ bool isComponentComplete() const;
+ virtual void itemChange(ItemChange, const ItemChangeData &);
+
+ void setImplicitWidth(qreal);
+ bool widthValid() const; // ### better name?
+ void setImplicitHeight(qreal);
+ bool heightValid() const; // ### better name?
+
+ virtual void classBegin();
+ virtual void componentComplete();
+
+ virtual void keyPressEvent(QKeyEvent *event);
+ virtual void keyReleaseEvent(QKeyEvent *event);
+ virtual void inputMethodEvent(QInputMethodEvent *);
+ virtual void focusInEvent(QFocusEvent *);
+ virtual void focusOutEvent(QFocusEvent *);
+ virtual void mousePressEvent(QGraphicsSceneMouseEvent *event);
+ virtual void mouseMoveEvent(QGraphicsSceneMouseEvent *event);
+ virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *event);
+ virtual void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event);
+ virtual void mouseUngrabEvent(); // XXX todo - params?
+ virtual void wheelEvent(QGraphicsSceneWheelEvent *event);
+ virtual void touchEvent(QTouchEvent *event);
+ virtual void hoverEnterEvent(QGraphicsSceneHoverEvent *event);
+ virtual void hoverMoveEvent(QGraphicsSceneHoverEvent *event);
+ virtual void hoverLeaveEvent(QGraphicsSceneHoverEvent *event);
+ virtual bool childMouseEventFilter(QSGItem *, QEvent *);
+
+ virtual void geometryChanged(const QRectF &newGeometry,
+ const QRectF &oldGeometry);
+
+ virtual QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *);
+ virtual void updatePolish();
+
+protected:
+ QSGItem(QSGItemPrivate &dd, QSGItem *parent = 0);
+
+private:
+ friend class QSGCanvas;
+ friend class QSGCanvasPrivate;
+ friend class QSGRenderer;
+ Q_DISABLE_COPY(QSGItem)
+ Q_DECLARE_PRIVATE(QSGItem)
+};
+
+// XXX todo
+Q_DECLARE_OPERATORS_FOR_FLAGS(QSGItem::Flags)
+
+#ifndef QT_NO_DEBUG_STREAM
+QDebug Q_DECLARATIVE_EXPORT operator<<(QDebug debug, QSGItem *item);
+#endif
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QSGItem)
+QML_DECLARE_TYPE(QSGTransform)
+
+QT_END_HEADER
+
+#endif // QSGITEM_H
diff --git a/src/declarative/items/qsgitem_p.h b/src/declarative/items/qsgitem_p.h
new file mode 100644
index 0000000000..c76eceb674
--- /dev/null
+++ b/src/declarative/items/qsgitem_p.h
@@ -0,0 +1,712 @@
+// Commit: 5c783d0a9a912816813945387903857a314040b5
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGITEM_P_H
+#define QSGITEM_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 "qsgitem.h"
+
+#include "qsganchors_p.h"
+#include "qsganchors_p_p.h"
+#include "qsgitemchangelistener_p.h"
+
+#include "qsgcanvas_p.h"
+
+#include "qsgnode.h"
+#include "qsgclipnode_p.h"
+
+#include <private/qpodvector_p.h>
+#include <private/qdeclarativestate_p.h>
+#include <private/qdeclarativenullablevalue_p_p.h>
+#include <private/qdeclarativenotifier_p.h>
+#include <private/qdeclarativeglobal_p.h>
+
+#include <qdeclarative.h>
+#include <qdeclarativecontext.h>
+
+#include <QtCore/qlist.h>
+#include <QtCore/qdebug.h>
+#include <QtCore/qelapsedtimer.h>
+
+QT_BEGIN_NAMESPACE
+
+class QNetworkReply;
+class QSGItemKeyFilter;
+class QSGLayoutMirroringAttached;
+
+//### merge into private?
+class QSGContents : public QObject, public QSGItemChangeListener
+{
+ Q_OBJECT
+public:
+ QSGContents(QSGItem *item);
+ ~QSGContents();
+
+ QRectF rectF() const;
+
+ void childRemoved(QSGItem *item);
+ void childAdded(QSGItem *item);
+
+ void calcGeometry() { calcWidth(); calcHeight(); }
+ void complete();
+
+Q_SIGNALS:
+ void rectChanged(QRectF);
+
+protected:
+ void itemGeometryChanged(QSGItem *item, const QRectF &newGeometry, const QRectF &oldGeometry);
+ void itemDestroyed(QSGItem *item);
+ //void itemVisibilityChanged(QSGItem *item)
+
+private:
+ void calcHeight(QSGItem *changed = 0);
+ void calcWidth(QSGItem *changed = 0);
+
+ QSGItem *m_item;
+ qreal m_x;
+ qreal m_y;
+ qreal m_width;
+ qreal m_height;
+};
+
+class QSGTransformPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QSGTransform);
+public:
+ static QSGTransformPrivate* get(QSGTransform *transform) { return transform->d_func(); }
+
+ QSGTransformPrivate();
+
+ QList<QSGItem *> items;
+};
+
+class Q_DECLARATIVE_EXPORT QSGItemPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QSGItem)
+
+public:
+ static QSGItemPrivate* get(QSGItem *item) { return item->d_func(); }
+ static const QSGItemPrivate* get(const QSGItem *item) { return item->d_func(); }
+
+ QSGItemPrivate();
+ void init(QSGItem *parent);
+
+ QDeclarativeListProperty<QObject> data();
+ QDeclarativeListProperty<QObject> resources();
+ QDeclarativeListProperty<QSGItem> children();
+
+ QDeclarativeListProperty<QDeclarativeState> states();
+ QDeclarativeListProperty<QDeclarativeTransition> transitions();
+
+ QString state() const;
+ void setState(const QString &);
+
+ QSGAnchorLine left() const;
+ QSGAnchorLine right() const;
+ QSGAnchorLine horizontalCenter() const;
+ QSGAnchorLine top() const;
+ QSGAnchorLine bottom() const;
+ QSGAnchorLine verticalCenter() const;
+ QSGAnchorLine baseline() const;
+
+ // data property
+ static void data_append(QDeclarativeListProperty<QObject> *, QObject *);
+ static int data_count(QDeclarativeListProperty<QObject> *);
+ static QObject *data_at(QDeclarativeListProperty<QObject> *, int);
+ static void data_clear(QDeclarativeListProperty<QObject> *);
+
+ // resources property
+ static QObject *resources_at(QDeclarativeListProperty<QObject> *, int);
+ static void resources_append(QDeclarativeListProperty<QObject> *, QObject *);
+ static int resources_count(QDeclarativeListProperty<QObject> *);
+ static void resources_clear(QDeclarativeListProperty<QObject> *);
+
+ // children property
+ static void children_append(QDeclarativeListProperty<QSGItem> *, QSGItem *);
+ static int children_count(QDeclarativeListProperty<QSGItem> *);
+ static QSGItem *children_at(QDeclarativeListProperty<QSGItem> *, int);
+ static void children_clear(QDeclarativeListProperty<QSGItem> *);
+
+ // transform property
+ static int transform_count(QDeclarativeListProperty<QSGTransform> *list);
+ static void transform_append(QDeclarativeListProperty<QSGTransform> *list, QSGTransform *);
+ static QSGTransform *transform_at(QDeclarativeListProperty<QSGTransform> *list, int);
+ static void transform_clear(QDeclarativeListProperty<QSGTransform> *list);
+
+ QSGAnchors *anchors() const;
+ mutable QSGAnchors *_anchors;
+ QSGContents *_contents;
+
+ QDeclarativeNullableValue<qreal> baselineOffset;
+
+ struct AnchorLines {
+ AnchorLines(QSGItem *);
+ QSGAnchorLine left;
+ QSGAnchorLine right;
+ QSGAnchorLine hCenter;
+ QSGAnchorLine top;
+ QSGAnchorLine bottom;
+ QSGAnchorLine vCenter;
+ QSGAnchorLine baseline;
+ };
+ mutable AnchorLines *_anchorLines;
+ AnchorLines *anchorLines() const;
+
+ enum ChangeType {
+ Geometry = 0x01,
+ SiblingOrder = 0x02,
+ Visibility = 0x04,
+ Opacity = 0x08,
+ Destroyed = 0x10,
+ Parent = 0x20,
+ Children = 0x40,
+ Rotation = 0x80,
+ };
+
+ Q_DECLARE_FLAGS(ChangeTypes, ChangeType)
+
+ struct ChangeListener {
+ ChangeListener(QSGItemChangeListener *l, QSGItemPrivate::ChangeTypes t) : listener(l), types(t) {}
+ QSGItemChangeListener *listener;
+ QSGItemPrivate::ChangeTypes types;
+ bool operator==(const ChangeListener &other) const { return listener == other.listener && types == other.types; }
+ };
+
+ void addItemChangeListener(QSGItemChangeListener *listener, ChangeTypes types) {
+ changeListeners.append(ChangeListener(listener, types));
+ }
+ void removeItemChangeListener(QSGItemChangeListener *, ChangeTypes types);
+ QPODVector<ChangeListener,4> changeListeners;
+
+ QDeclarativeStateGroup *_states();
+ QDeclarativeStateGroup *_stateGroup;
+
+ QSGItem::TransformOrigin origin:5;
+ quint32 flags:4;
+ bool widthValid:1;
+ bool heightValid:1;
+ bool componentComplete:1;
+ bool keepMouse:1;
+ bool hoverEnabled:1;
+ bool smooth:1;
+ bool focus:1;
+ bool activeFocus:1;
+ bool notifiedFocus:1;
+ bool notifiedActiveFocus:1;
+ bool filtersChildMouseEvents:1;
+ bool explicitVisible:1;
+ bool effectiveVisible:1;
+ bool explicitEnable:1;
+ bool effectiveEnable:1;
+ bool polishScheduled:1;
+ bool inheritedLayoutMirror:1;
+ bool effectiveLayoutMirror:1;
+ bool isMirrorImplicit:1;
+ bool inheritMirrorFromParent:1;
+ bool inheritMirrorFromItem:1;
+ bool childrenDoNotOverlap:1;
+ quint32 dummy:1;
+
+ QSGCanvas *canvas;
+ QSGContext *sceneGraphContext() const { return static_cast<QSGCanvasPrivate *>(QObjectPrivate::get(canvas))->context; }
+
+ QSGItem *parentItem;
+ QList<QSGItem *> childItems;
+ QList<QSGItem *> paintOrderChildItems() const;
+ void addChild(QSGItem *);
+ void removeChild(QSGItem *);
+ void siblingOrderChanged();
+
+ class InitializationState {
+ public:
+ QSGItem *getFocusScope(QSGItem *item);
+ void clear();
+ void clear(QSGItem *focusScope);
+ private:
+ QSGItem *focusScope;
+ };
+ void initCanvas(InitializationState *, QSGCanvas *);
+
+ QSGItem *subFocusItem;
+
+ QTransform canvasToItemTransform() const;
+ QTransform itemToCanvasTransform() const;
+ void itemToParentTransform(QTransform &) const;
+
+ qreal x;
+ qreal y;
+ qreal width;
+ qreal height;
+ qreal implicitWidth;
+ qreal implicitHeight;
+
+ qreal z;
+ qreal scale;
+ qreal rotation;
+ qreal opacity;
+
+ QSGLayoutMirroringAttached* attachedLayoutDirection;
+
+ Qt::MouseButtons acceptedMouseButtons;
+ Qt::InputMethodHints imHints;
+
+ virtual qreal getImplicitWidth() const;
+ virtual qreal getImplicitHeight() const;
+ virtual void implicitWidthChanged();
+ virtual void implicitHeightChanged();
+
+ void resolveLayoutMirror();
+ void setImplicitLayoutMirror(bool mirror, bool inherit);
+ void setLayoutMirror(bool mirror);
+ bool isMirrored() const {
+ return effectiveLayoutMirror;
+ }
+
+ QPointF computeTransformOrigin() const;
+ QList<QSGTransform *> transforms;
+ virtual void transformChanged();
+
+ QSGItemKeyFilter *keyHandler;
+ void deliverKeyEvent(QKeyEvent *);
+ void deliverInputMethodEvent(QInputMethodEvent *);
+ void deliverFocusEvent(QFocusEvent *);
+ void deliverMouseEvent(QGraphicsSceneMouseEvent *);
+ void deliverWheelEvent(QGraphicsSceneWheelEvent *);
+ void deliverTouchEvent(QTouchEvent *);
+ void deliverHoverEvent(QGraphicsSceneHoverEvent *);
+
+ bool calcEffectiveVisible() const;
+ void setEffectiveVisibleRecur(bool);
+ bool calcEffectiveEnable() const;
+ void setEffectiveEnableRecur(bool);
+
+ // XXX todo
+ enum DirtyType {
+ TransformOrigin = 0x00000001,
+ Transform = 0x00000002,
+ BasicTransform = 0x00000004,
+ Position = 0x00000008,
+ Size = 0x00000010,
+
+ ZValue = 0x00000020,
+ Content = 0x00000040,
+ Smooth = 0x00000080,
+ OpacityValue = 0x00000100,
+ ChildrenChanged = 0x00000200,
+ ChildrenStackingChanged = 0x00000400,
+ ParentChanged = 0x00000800,
+
+ Clip = 0x00001000,
+ Canvas = 0x00002000,
+
+ EffectReference = 0x00008000,
+ Visible = 0x00010000,
+ HideReference = 0x00020000,
+ // When you add an attribute here, don't forget to update
+ // dirtyToString()
+
+ TransformUpdateMask = TransformOrigin | Transform | BasicTransform | Position | Size | Canvas,
+ ComplexTransformUpdateMask = Transform | Canvas,
+ ContentUpdateMask = Size | Content | Smooth | Canvas,
+ ChildrenUpdateMask = ChildrenChanged | ChildrenStackingChanged | EffectReference | Canvas,
+
+ };
+ quint32 dirtyAttributes;
+ QString dirtyToString() const;
+ void dirty(DirtyType);
+ void addToDirtyList();
+ void removeFromDirtyList();
+ QSGItem *nextDirtyItem;
+ QSGItem**prevDirtyItem;
+
+ inline QSGTransformNode *itemNode();
+ inline QSGNode *childContainerNode();
+
+ /*
+ QSGNode order is:
+ - itemNode
+ - (opacityNode)
+ - (clipNode)
+ - (effectNode)
+ - groupNode
+ */
+
+ QSGTransformNode *itemNodeInstance;
+ QSGOpacityNode *opacityNode;
+ QSGDefaultClipNode *clipNode;
+ QSGRootNode *rootNode;
+ QSGNode *groupNode;
+ QSGNode *paintNode;
+ int paintNodeIndex;
+
+ virtual QSGTransformNode *createTransformNode();
+
+ // A reference from an effect item means that this item is used by the effect, so
+ // it should insert a root node.
+ void refFromEffectItem(bool hide);
+ void derefFromEffectItem(bool unhide);
+ int effectRefCount;
+ int hideRefCount;
+
+ void itemChange(QSGItem::ItemChange, const QSGItem::ItemChangeData &);
+
+ virtual void mirrorChange() {}
+
+ static qint64 consistentTime;
+ static void setConsistentTime(qint64 t);
+ static void start(QElapsedTimer &);
+ static qint64 elapsed(QElapsedTimer &);
+ static qint64 restart(QElapsedTimer &);
+};
+
+/*
+ Key filters can be installed on a QSGItem, but not removed. Currently they
+ are only used by attached objects (which are only destroyed on Item
+ destruction), so this isn't a problem. If in future this becomes any form
+ of public API, they will have to support removal too.
+*/
+class QSGItemKeyFilter
+{
+public:
+ QSGItemKeyFilter(QSGItem * = 0);
+ virtual ~QSGItemKeyFilter();
+
+ virtual void keyPressed(QKeyEvent *event, bool post);
+ virtual void keyReleased(QKeyEvent *event, bool post);
+ virtual void inputMethodEvent(QInputMethodEvent *event, bool post);
+ virtual QVariant inputMethodQuery(Qt::InputMethodQuery query) const;
+ virtual void componentComplete();
+
+ bool m_processPost;
+
+private:
+ QSGItemKeyFilter *m_next;
+};
+
+class QSGKeyNavigationAttachedPrivate : public QObjectPrivate
+{
+public:
+ QSGKeyNavigationAttachedPrivate()
+ : QObjectPrivate(),
+ left(0), right(0), up(0), down(0), tab(0), backtab(0),
+ leftSet(false), rightSet(false), upSet(false), downSet(false),
+ tabSet(false), backtabSet(false) {}
+
+ QSGItem *left;
+ QSGItem *right;
+ QSGItem *up;
+ QSGItem *down;
+ QSGItem *tab;
+ QSGItem *backtab;
+ bool leftSet : 1;
+ bool rightSet : 1;
+ bool upSet : 1;
+ bool downSet : 1;
+ bool tabSet : 1;
+ bool backtabSet : 1;
+};
+
+class QSGKeyNavigationAttached : public QObject, public QSGItemKeyFilter
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QSGKeyNavigationAttached)
+
+ Q_PROPERTY(QSGItem *left READ left WRITE setLeft NOTIFY leftChanged)
+ Q_PROPERTY(QSGItem *right READ right WRITE setRight NOTIFY rightChanged)
+ Q_PROPERTY(QSGItem *up READ up WRITE setUp NOTIFY upChanged)
+ Q_PROPERTY(QSGItem *down READ down WRITE setDown NOTIFY downChanged)
+ Q_PROPERTY(QSGItem *tab READ tab WRITE setTab NOTIFY tabChanged)
+ Q_PROPERTY(QSGItem *backtab READ backtab WRITE setBacktab NOTIFY backtabChanged)
+ Q_PROPERTY(Priority priority READ priority WRITE setPriority NOTIFY priorityChanged)
+
+ Q_ENUMS(Priority)
+
+public:
+ QSGKeyNavigationAttached(QObject * = 0);
+
+ QSGItem *left() const;
+ void setLeft(QSGItem *);
+ QSGItem *right() const;
+ void setRight(QSGItem *);
+ QSGItem *up() const;
+ void setUp(QSGItem *);
+ QSGItem *down() const;
+ void setDown(QSGItem *);
+ QSGItem *tab() const;
+ void setTab(QSGItem *);
+ QSGItem *backtab() const;
+ void setBacktab(QSGItem *);
+
+ enum Priority { BeforeItem, AfterItem };
+ Priority priority() const;
+ void setPriority(Priority);
+
+ static QSGKeyNavigationAttached *qmlAttachedProperties(QObject *);
+
+Q_SIGNALS:
+ void leftChanged();
+ void rightChanged();
+ void upChanged();
+ void downChanged();
+ void tabChanged();
+ void backtabChanged();
+ void priorityChanged();
+
+private:
+ virtual void keyPressed(QKeyEvent *event, bool post);
+ virtual void keyReleased(QKeyEvent *event, bool post);
+ void setFocusNavigation(QSGItem *currentItem, const char *dir);
+};
+
+class QSGLayoutMirroringAttached : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(bool enabled READ enabled WRITE setEnabled RESET resetEnabled NOTIFY enabledChanged)
+ Q_PROPERTY(bool childrenInherit READ childrenInherit WRITE setChildrenInherit NOTIFY childrenInheritChanged)
+
+public:
+ explicit QSGLayoutMirroringAttached(QObject *parent = 0);
+
+ bool enabled() const;
+ void setEnabled(bool);
+ void resetEnabled();
+
+ bool childrenInherit() const;
+ void setChildrenInherit(bool);
+
+ static QSGLayoutMirroringAttached *qmlAttachedProperties(QObject *);
+Q_SIGNALS:
+ void enabledChanged();
+ void childrenInheritChanged();
+private:
+ friend class QSGItemPrivate;
+ QSGItemPrivate *itemPrivate;
+};
+
+class QSGKeysAttachedPrivate : public QObjectPrivate
+{
+public:
+ QSGKeysAttachedPrivate()
+ : QObjectPrivate(), inPress(false), inRelease(false)
+ , inIM(false), enabled(true), imeItem(0), item(0)
+ {}
+
+ bool isConnected(const char *signalName);
+
+ //loop detection
+ bool inPress:1;
+ bool inRelease:1;
+ bool inIM:1;
+
+ bool enabled : 1;
+
+ QSGItem *imeItem;
+ QList<QSGItem *> targets;
+ QSGItem *item;
+};
+
+class QSGKeysAttached : public QObject, public QSGItemKeyFilter
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QSGKeysAttached)
+
+ Q_PROPERTY(bool enabled READ enabled WRITE setEnabled NOTIFY enabledChanged)
+ Q_PROPERTY(QDeclarativeListProperty<QSGItem> forwardTo READ forwardTo)
+ Q_PROPERTY(Priority priority READ priority WRITE setPriority NOTIFY priorityChanged)
+
+ Q_ENUMS(Priority)
+
+public:
+ QSGKeysAttached(QObject *parent=0);
+ ~QSGKeysAttached();
+
+ bool enabled() const { Q_D(const QSGKeysAttached); return d->enabled; }
+ void setEnabled(bool enabled) {
+ Q_D(QSGKeysAttached);
+ if (enabled != d->enabled) {
+ d->enabled = enabled;
+ emit enabledChanged();
+ }
+ }
+
+ enum Priority { BeforeItem, AfterItem};
+ Priority priority() const;
+ void setPriority(Priority);
+
+ QDeclarativeListProperty<QSGItem> forwardTo() {
+ Q_D(QSGKeysAttached);
+ return QDeclarativeListProperty<QSGItem>(this, d->targets);
+ }
+
+ virtual void componentComplete();
+
+ static QSGKeysAttached *qmlAttachedProperties(QObject *);
+
+Q_SIGNALS:
+ void enabledChanged();
+ void priorityChanged();
+ void pressed(QSGKeyEvent *event);
+ void released(QSGKeyEvent *event);
+ void digit0Pressed(QSGKeyEvent *event);
+ void digit1Pressed(QSGKeyEvent *event);
+ void digit2Pressed(QSGKeyEvent *event);
+ void digit3Pressed(QSGKeyEvent *event);
+ void digit4Pressed(QSGKeyEvent *event);
+ void digit5Pressed(QSGKeyEvent *event);
+ void digit6Pressed(QSGKeyEvent *event);
+ void digit7Pressed(QSGKeyEvent *event);
+ void digit8Pressed(QSGKeyEvent *event);
+ void digit9Pressed(QSGKeyEvent *event);
+
+ void leftPressed(QSGKeyEvent *event);
+ void rightPressed(QSGKeyEvent *event);
+ void upPressed(QSGKeyEvent *event);
+ void downPressed(QSGKeyEvent *event);
+ void tabPressed(QSGKeyEvent *event);
+ void backtabPressed(QSGKeyEvent *event);
+
+ void asteriskPressed(QSGKeyEvent *event);
+ void numberSignPressed(QSGKeyEvent *event);
+ void escapePressed(QSGKeyEvent *event);
+ void returnPressed(QSGKeyEvent *event);
+ void enterPressed(QSGKeyEvent *event);
+ void deletePressed(QSGKeyEvent *event);
+ void spacePressed(QSGKeyEvent *event);
+ void backPressed(QSGKeyEvent *event);
+ void cancelPressed(QSGKeyEvent *event);
+ void selectPressed(QSGKeyEvent *event);
+ void yesPressed(QSGKeyEvent *event);
+ void noPressed(QSGKeyEvent *event);
+ void context1Pressed(QSGKeyEvent *event);
+ void context2Pressed(QSGKeyEvent *event);
+ void context3Pressed(QSGKeyEvent *event);
+ void context4Pressed(QSGKeyEvent *event);
+ void callPressed(QSGKeyEvent *event);
+ void hangupPressed(QSGKeyEvent *event);
+ void flipPressed(QSGKeyEvent *event);
+ void menuPressed(QSGKeyEvent *event);
+ void volumeUpPressed(QSGKeyEvent *event);
+ void volumeDownPressed(QSGKeyEvent *event);
+
+private:
+ virtual void keyPressed(QKeyEvent *event, bool post);
+ virtual void keyReleased(QKeyEvent *event, bool post);
+ virtual void inputMethodEvent(QInputMethodEvent *, bool post);
+ virtual QVariant inputMethodQuery(Qt::InputMethodQuery query) const;
+
+ const QByteArray keyToSignal(int key) {
+ QByteArray keySignal;
+ if (key >= Qt::Key_0 && key <= Qt::Key_9) {
+ keySignal = "digit0Pressed";
+ keySignal[5] = '0' + (key - Qt::Key_0);
+ } else {
+ int i = 0;
+ while (sigMap[i].key && sigMap[i].key != key)
+ ++i;
+ keySignal = sigMap[i].sig;
+ }
+ return keySignal;
+ }
+
+ struct SigMap {
+ int key;
+ const char *sig;
+ };
+
+ static const SigMap sigMap[];
+};
+
+QSGTransformNode *QSGItemPrivate::itemNode()
+{
+ if (!itemNodeInstance) {
+ itemNodeInstance = createTransformNode();
+#ifdef QML_RUNTIME_TESTING
+ Q_Q(QSGItem);
+ itemNodeInstance->description = QString::fromLatin1("QSGItem(%1)").arg(QString::fromLatin1(q->metaObject()->className()));
+#endif
+ }
+ return itemNodeInstance;
+}
+
+QSGNode *QSGItemPrivate::childContainerNode()
+{
+ if (!groupNode) {
+ groupNode = new QSGNode();
+ if (rootNode)
+ rootNode->appendChildNode(groupNode);
+ else if (clipNode)
+ clipNode->appendChildNode(groupNode);
+ else if (opacityNode)
+ opacityNode->appendChildNode(groupNode);
+ else
+ itemNode()->appendChildNode(groupNode);
+ groupNode->setFlag(QSGNode::ChildrenDoNotOverlap, childrenDoNotOverlap);
+#ifdef QML_RUNTIME_TESTING
+ groupNode->description = QLatin1String("group");
+#endif
+ }
+ return groupNode;
+}
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QSGItemPrivate::ChangeTypes);
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QSGKeysAttached)
+QML_DECLARE_TYPEINFO(QSGKeysAttached, QML_HAS_ATTACHED_PROPERTIES)
+QML_DECLARE_TYPE(QSGKeyNavigationAttached)
+QML_DECLARE_TYPEINFO(QSGKeyNavigationAttached, QML_HAS_ATTACHED_PROPERTIES)
+QML_DECLARE_TYPE(QSGLayoutMirroringAttached)
+QML_DECLARE_TYPEINFO(QSGLayoutMirroringAttached, QML_HAS_ATTACHED_PROPERTIES)
+
+#endif // QSGITEM_P_H
diff --git a/src/declarative/items/qsgitemchangelistener_p.h b/src/declarative/items/qsgitemchangelistener_p.h
new file mode 100644
index 0000000000..3b4018a772
--- /dev/null
+++ b/src/declarative/items/qsgitemchangelistener_p.h
@@ -0,0 +1,82 @@
+// Commit: ac5c099cc3c5b8c7eec7a49fdeb8a21037230350
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGITEMCHANGELISTENER_P_H
+#define QSGITEMCHANGELISTENER_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 QRectF;
+class QSGItem;
+class QSGAnchorsPrivate;
+class QSGItemChangeListener
+{
+public:
+ virtual void itemGeometryChanged(QSGItem *, const QRectF &, const QRectF &) {}
+ virtual void itemSiblingOrderChanged(QSGItem *) {}
+ virtual void itemVisibilityChanged(QSGItem *) {}
+ virtual void itemOpacityChanged(QSGItem *) {}
+ virtual void itemDestroyed(QSGItem *) {}
+ virtual void itemChildAdded(QSGItem *, QSGItem *) {}
+ virtual void itemChildRemoved(QSGItem *, QSGItem *) {}
+ virtual void itemParentChanged(QSGItem *, QSGItem *) {}
+ virtual void itemRotationChanged(QSGItem *) {}
+
+ virtual QSGAnchorsPrivate *anchorPrivate() { return 0; }
+};
+
+QT_END_NAMESPACE
+
+#endif // QSGITEMCHANGELISTENER_P_H
diff --git a/src/declarative/items/qsgitemsmodule.cpp b/src/declarative/items/qsgitemsmodule.cpp
new file mode 100644
index 0000000000..6ea20bb38b
--- /dev/null
+++ b/src/declarative/items/qsgitemsmodule.cpp
@@ -0,0 +1,212 @@
+// Commit: 2c7cab4172f1acc86fd49345a2847417e162f2c3
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgitemsmodule_p.h"
+
+#include "qsgitem.h"
+#include "qsgitem_p.h"
+#include "qsgevents_p_p.h"
+#include "qsgrectangle_p.h"
+#include "qsgfocusscope_p.h"
+#include "qsgtext_p.h"
+#include "qsgtextinput_p.h"
+#include "qsgtextedit_p.h"
+#include "qsgimage_p.h"
+#include "qsgborderimage_p.h"
+#include "qsgscalegrid_p_p.h"
+#include "qsgmousearea_p.h"
+#include "qsgpincharea_p.h"
+#include "qsgflickable_p.h"
+#include "qsgflickable_p_p.h"
+#include "qsglistview_p.h"
+#include "qsgvisualitemmodel_p.h"
+#include "qsggridview_p.h"
+#include "qsgpathview_p.h"
+#include <private/qdeclarativepath_p.h>
+#include "qsgpositioners_p.h"
+#include "qsgrepeater_p.h"
+#include "qsgloader_p.h"
+#include "qsganimatedimage_p.h"
+#include "qsgflipable_p.h"
+#include "qsgtranslate_p.h"
+#include "qsgstateoperations_p.h"
+#include "qsganimation_p.h"
+#include <private/qsgshadereffectitem_p.h>
+#include <private/qsgshadereffectsource_p.h>
+//#include "private/qsgpincharea_p.h"
+#include "qsgcanvasitem_p.h"
+#include "qsgcontext2d_p.h"
+
+static QDeclarativePrivate::AutoParentResult qsgitem_autoParent(QObject *obj, QObject *parent)
+{
+ QSGItem *item = qobject_cast<QSGItem *>(obj);
+ if (!item)
+ return QDeclarativePrivate::IncompatibleObject;
+
+ QSGItem *parentItem = qobject_cast<QSGItem *>(parent);
+ if (!parentItem)
+ return QDeclarativePrivate::IncompatibleParent;
+
+ item->setParentItem(parentItem);
+ return QDeclarativePrivate::Parented;
+}
+
+static void qt_sgitems_defineModule(const char *uri, int major, int minor)
+{
+ QDeclarativePrivate::RegisterAutoParent autoparent = { 0, &qsgitem_autoParent };
+ QDeclarativePrivate::qmlregister(QDeclarativePrivate::AutoParentRegistration, &autoparent);
+
+#ifdef QT_NO_MOVIE
+ qmlRegisterTypeNotAvailable(uri,major,minor,"AnimatedImage", qApp->translate("QSGAnimatedImage","Qt was built without support for QMovie"));
+#else
+ qmlRegisterType<QSGAnimatedImage>(uri,major,minor,"AnimatedImage");
+#endif
+ qmlRegisterType<QSGBorderImage>(uri,major,minor,"BorderImage");
+ qmlRegisterType<QSGColumn>(uri,major,minor,"Column");
+ qmlRegisterType<QSGDrag>(uri,major,minor,"Drag");
+ qmlRegisterType<QSGFlickable>(uri,major,minor,"Flickable");
+ qmlRegisterType<QSGFlipable>(uri,major,minor,"Flipable");
+ qmlRegisterType<QSGFlow>(uri,major,minor,"Flow");
+// qmlRegisterType<QDeclarativeFocusPanel>(uri,major,minor,"FocusPanel");
+ qmlRegisterType<QSGFocusScope>(uri,major,minor,"FocusScope");
+ qmlRegisterType<QSGGradient>(uri,major,minor,"Gradient");
+ qmlRegisterType<QSGGradientStop>(uri,major,minor,"GradientStop");
+ qmlRegisterType<QSGGrid>(uri,major,minor,"Grid");
+ qmlRegisterType<QSGGridView>(uri,major,minor,"GridView");
+ qmlRegisterType<QSGImage>(uri,major,minor,"Image");
+ qmlRegisterType<QSGItem>(uri,major,minor,"Item");
+ qmlRegisterType<QSGListView>(uri,major,minor,"ListView");
+ qmlRegisterType<QSGLoader>(uri,major,minor,"Loader");
+ qmlRegisterType<QSGMouseArea>(uri,major,minor,"MouseArea");
+ qmlRegisterType<QDeclarativePath>(uri,major,minor,"Path");
+ qmlRegisterType<QDeclarativePathAttribute>(uri,major,minor,"PathAttribute");
+ qmlRegisterType<QDeclarativePathCubic>(uri,major,minor,"PathCubic");
+ qmlRegisterType<QDeclarativePathLine>(uri,major,minor,"PathLine");
+ qmlRegisterType<QDeclarativePathPercent>(uri,major,minor,"PathPercent");
+ qmlRegisterType<QDeclarativePathQuad>(uri,major,minor,"PathQuad");
+ qmlRegisterType<QSGPathView>(uri,major,minor,"PathView");
+#ifndef QT_NO_VALIDATOR
+ qmlRegisterType<QIntValidator>(uri,major,minor,"IntValidator");
+ qmlRegisterType<QDoubleValidator>(uri,major,minor,"DoubleValidator");
+ qmlRegisterType<QRegExpValidator>(uri,major,minor,"RegExpValidator");
+#endif
+ qmlRegisterType<QSGRectangle>(uri,major,minor,"Rectangle");
+ qmlRegisterType<QSGRepeater>(uri,major,minor,"Repeater");
+ qmlRegisterType<QSGRow>(uri,major,minor,"Row");
+ qmlRegisterType<QSGTranslate>(uri,major,minor,"Translate");
+ qmlRegisterType<QSGRotation>(uri,major,minor,"Rotation");
+ qmlRegisterType<QSGScale>(uri,major,minor,"Scale");
+ qmlRegisterType<QSGText>(uri,major,minor,"Text");
+ qmlRegisterType<QSGTextEdit>(uri,major,minor,"TextEdit");
+ qmlRegisterType<QSGTextInput>(uri,major,minor,"TextInput");
+ qmlRegisterType<QSGViewSection>(uri,major,minor,"ViewSection");
+ qmlRegisterType<QSGVisualDataModel>(uri,major,minor,"VisualDataModel");
+ qmlRegisterType<QSGVisualItemModel>(uri,major,minor,"VisualItemModel");
+
+ qmlRegisterType<QSGAnchors>();
+ qmlRegisterType<QSGKeyEvent>();
+ qmlRegisterType<QSGMouseEvent>();
+ qmlRegisterType<QSGTransform>();
+ qmlRegisterType<QDeclarativePathElement>();
+ qmlRegisterType<QDeclarativeCurve>();
+ qmlRegisterType<QSGScaleGrid>();
+#ifndef QT_NO_VALIDATOR
+ qmlRegisterType<QValidator>();
+#endif
+ qmlRegisterType<QSGVisualModel>();
+#ifndef QT_NO_ACTION
+ qmlRegisterType<QAction>();
+#endif
+ qmlRegisterType<QSGPen>();
+ qmlRegisterType<QSGFlickableVisibleArea>();
+ qRegisterMetaType<QSGAnchorLine>("QSGAnchorLine");
+
+ qmlRegisterUncreatableType<QSGKeyNavigationAttached>(uri,major,minor,"KeyNavigation",QSGKeyNavigationAttached::tr("KeyNavigation is only available via attached properties"));
+ qmlRegisterUncreatableType<QSGKeysAttached>(uri,major,minor,"Keys",QSGKeysAttached::tr("Keys is only available via attached properties"));
+ qmlRegisterUncreatableType<QSGLayoutMirroringAttached>(uri,major,minor,"LayoutMirroring", QSGLayoutMirroringAttached::tr("LayoutMirroring is only available via attached properties"));
+
+ qmlRegisterType<QSGPinchArea>(uri,major,minor,"PinchArea");
+ qmlRegisterType<QSGPinch>(uri,major,minor,"Pinch");
+ qmlRegisterType<QSGPinchEvent>();
+
+ qmlRegisterType<QSGShaderEffectItem>("QtQuick", 2, 0, "ShaderEffectItem");
+ qmlRegisterType<QSGShaderEffectSource>("QtQuick", 2, 0, "ShaderEffectSource");
+ qmlRegisterUncreatableType<QSGShaderEffectMesh>("QtQuick", 2, 0, "ShaderEffectMesh", QSGShaderEffectMesh::tr("Cannot create instance of abstract class ShaderEffectMesh."));
+ qmlRegisterType<QSGGridMesh>("QtQuick", 2, 0, "GridMesh");
+
+ qmlRegisterUncreatableType<QSGPaintedItem>("QtQuick", 2, 0, "PaintedItem", QSGPaintedItem::tr("Cannot create instance of abstract class PaintedItem"));
+
+ qmlRegisterType<QSGCanvasItem>("QtQuick", 2, 0, "Canvas");
+ qmlRegisterType<QSGContext2D>();
+ qmlRegisterType<QSGCanvasGradient>();
+
+
+ qmlRegisterType<QSGParentChange>(uri, major, minor,"ParentChange");
+ qmlRegisterType<QSGAnchorChanges>(uri, major, minor,"AnchorChanges");
+ qmlRegisterType<QSGAnchorSet>();
+ qmlRegisterType<QSGAnchorAnimation>(uri, major, minor,"AnchorAnimation");
+ qmlRegisterType<QSGParentAnimation>(uri, major, minor,"ParentAnimation");
+}
+
+void QSGItemsModule::defineModule()
+{
+ static bool initialized = false;
+ if (initialized)
+ return;
+ initialized = true;
+
+ // XXX todo - Remove before final integration...
+ QByteArray mode = qgetenv("QMLSCENE_IMPORT_NAME");
+ QByteArray name = "QtQuick";
+ int majorVersion = 2;
+ int minorVersion = 0;
+ if (mode == "quick1") {
+ majorVersion = 1;
+ } else if (mode == "qt") {
+ name = "Qt";
+ majorVersion = 4;
+ minorVersion = 7;
+ }
+
+ qt_sgitems_defineModule(name, majorVersion, minorVersion);
+}
+
diff --git a/src/declarative/items/qsgitemsmodule_p.h b/src/declarative/items/qsgitemsmodule_p.h
new file mode 100644
index 0000000000..2d8a971c22
--- /dev/null
+++ b/src/declarative/items/qsgitemsmodule_p.h
@@ -0,0 +1,65 @@
+// Commit: ac5c099cc3c5b8c7eec7a49fdeb8a21037230350
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGITEMSMODULE_P_H
+#define QSGITEMSMODULE_P_H
+
+#include <qdeclarative.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QSGItemsModule
+{
+public:
+ static void defineModule();
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QSGITEMSMODULE_P_H
+
diff --git a/src/declarative/items/qsglistview.cpp b/src/declarative/items/qsglistview.cpp
new file mode 100644
index 0000000000..a61ca97256
--- /dev/null
+++ b/src/declarative/items/qsglistview.cpp
@@ -0,0 +1,3064 @@
+// Commit: 806f031efeda71d3f4d7d2f949b437493e79cf52
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsglistview_p.h"
+#include "qsgflickable_p_p.h"
+#include "qsgvisualitemmodel_p.h"
+
+#include <QtDeclarative/qdeclarativeexpression.h>
+#include <QtDeclarative/qdeclarativeengine.h>
+#include <QtDeclarative/qdeclarativeinfo.h>
+#include <QtGui/qevent.h>
+#include <QtCore/qmath.h>
+#include <QtCore/qcoreapplication.h>
+
+#include <private/qdeclarativesmoothedanimation_p_p.h>
+#include <private/qlistmodelinterface_p.h>
+
+QT_BEGIN_NAMESPACE
+
+void QSGViewSection::setProperty(const QString &property)
+{
+ if (property != m_property) {
+ m_property = property;
+ emit propertyChanged();
+ }
+}
+
+void QSGViewSection::setCriteria(QSGViewSection::SectionCriteria criteria)
+{
+ if (criteria != m_criteria) {
+ m_criteria = criteria;
+ emit criteriaChanged();
+ }
+}
+
+void QSGViewSection::setDelegate(QDeclarativeComponent *delegate)
+{
+ if (delegate != m_delegate) {
+ m_delegate = delegate;
+ emit delegateChanged();
+ }
+}
+
+QString QSGViewSection::sectionString(const QString &value)
+{
+ if (m_criteria == FirstCharacter)
+ return value.isEmpty() ? QString() : value.at(0);
+ else
+ return value;
+}
+
+//----------------------------------------------------------------------------
+
+class FxListItemSG
+{
+public:
+ FxListItemSG(QSGItem *i, QSGListView *v) : item(i), section(0), view(v) {
+ attached = static_cast<QSGListViewAttached*>(qmlAttachedPropertiesObject<QSGListView>(item));
+ if (attached)
+ attached->setView(view);
+ }
+ ~FxListItemSG() {}
+ qreal position() const {
+ if (section) {
+ if (view->orientation() == QSGListView::Vertical)
+ return section->y();
+ else
+ return (view->effectiveLayoutDirection() == Qt::RightToLeft ? -section->width()-section->x() : section->x());
+ } else {
+ return itemPosition();
+ }
+ }
+ qreal itemPosition() const {
+ if (view->orientation() == QSGListView::Vertical)
+ return item->y();
+ else
+ return (view->effectiveLayoutDirection() == Qt::RightToLeft ? -item->width()-item->x() : item->x());
+ }
+ qreal size() const {
+ if (section)
+ return (view->orientation() == QSGListView::Vertical ? item->height()+section->height() : item->width()+section->width());
+ else
+ return (view->orientation() == QSGListView::Vertical ? item->height() : item->width());
+ }
+ qreal itemSize() const {
+ return (view->orientation() == QSGListView::Vertical ? item->height() : item->width());
+ }
+ qreal sectionSize() const {
+ if (section)
+ return (view->orientation() == QSGListView::Vertical ? section->height() : section->width());
+ return 0.0;
+ }
+ qreal endPosition() const {
+ if (view->orientation() == QSGListView::Vertical) {
+ return item->y() + (item->height() >= 1.0 ? item->height() : 1) - 1;
+ } else {
+ return (view->effectiveLayoutDirection() == Qt::RightToLeft
+ ? -item->width()-item->x() + (item->width() >= 1.0 ? item->width() : 1)
+ : item->x() + (item->width() >= 1.0 ? item->width() : 1)) - 1;
+ }
+ }
+ void setPosition(qreal pos) {
+ if (view->orientation() == QSGListView::Vertical) {
+ if (section) {
+ section->setY(pos);
+ pos += section->height();
+ }
+ item->setY(pos);
+ } else {
+ if (view->effectiveLayoutDirection() == Qt::RightToLeft) {
+ if (section) {
+ section->setX(-section->width()-pos);
+ pos += section->width();
+ }
+ item->setX(-item->width()-pos);
+ } else {
+ if (section) {
+ section->setX(pos);
+ pos += section->width();
+ }
+ item->setX(pos);
+ }
+ }
+ }
+ void setSize(qreal size) {
+ if (view->orientation() == QSGListView::Vertical)
+ item->setHeight(size);
+ else
+ item->setWidth(size);
+ }
+ bool contains(qreal x, qreal y) const {
+ return (x >= item->x() && x < item->x() + item->width() &&
+ y >= item->y() && y < item->y() + item->height());
+ }
+
+ QSGItem *item;
+ QSGItem *section;
+ QSGListView *view;
+ QSGListViewAttached *attached;
+ int index;
+};
+
+//----------------------------------------------------------------------------
+
+class QSGListViewPrivate : public QSGFlickablePrivate
+{
+ Q_DECLARE_PUBLIC(QSGListView)
+
+public:
+ QSGListViewPrivate()
+ : currentItem(0), orient(QSGListView::Vertical), layoutDirection(Qt::LeftToRight)
+ , visiblePos(0), visibleIndex(0)
+ , averageSize(100.0), currentIndex(-1), requestedIndex(-1)
+ , itemCount(0), highlightRangeStart(0), highlightRangeEnd(0)
+ , highlightComponent(0), highlight(0), trackedItem(0)
+ , moveReason(Other), buffer(0), highlightPosAnimator(0), highlightSizeAnimator(0)
+ , sectionCriteria(0), spacing(0.0)
+ , highlightMoveSpeed(400), highlightMoveDuration(-1)
+ , highlightResizeSpeed(400), highlightResizeDuration(-1), highlightRange(QSGListView::NoHighlightRange)
+ , snapMode(QSGListView::NoSnap), overshootDist(0.0)
+ , footerComponent(0), footer(0), headerComponent(0), header(0)
+ , bufferMode(BufferBefore | BufferAfter)
+ , ownModel(false), wrap(false), autoHighlight(true), haveHighlightRange(false)
+ , correctFlick(false), inFlickCorrection(false), lazyRelease(false)
+ , deferredRelease(false), layoutScheduled(false), currentIndexCleared(false)
+ , inViewportMoved(false)
+ , highlightRangeStartValid(false), highlightRangeEndValid(false)
+ , minExtentDirty(true), maxExtentDirty(true)
+ {}
+
+ void init();
+ void clear();
+ FxListItemSG *createItem(int modelIndex);
+ void releaseItem(FxListItemSG *item);
+
+ FxListItemSG *visibleItem(int modelIndex) const {
+ if (modelIndex >= visibleIndex && modelIndex < visibleIndex + visibleItems.count()) {
+ for (int i = modelIndex - visibleIndex; i < visibleItems.count(); ++i) {
+ FxListItemSG *item = visibleItems.at(i);
+ if (item->index == modelIndex)
+ return item;
+ }
+ }
+ return 0;
+ }
+
+ FxListItemSG *firstVisibleItem() const {
+ const qreal pos = isRightToLeft() ? -position()-size() : position();
+ for (int i = 0; i < visibleItems.count(); ++i) {
+ FxListItemSG *item = visibleItems.at(i);
+ if (item->index != -1 && item->endPosition() > pos)
+ return item;
+ }
+ return visibleItems.count() ? visibleItems.first() : 0;
+ }
+
+ FxListItemSG *nextVisibleItem() const {
+ const qreal pos = isRightToLeft() ? -position()-size() : position();
+ bool foundFirst = false;
+ for (int i = 0; i < visibleItems.count(); ++i) {
+ FxListItemSG *item = visibleItems.at(i);
+ if (item->index != -1) {
+ if (foundFirst)
+ return item;
+ else if (item->position() < pos && item->endPosition() > pos)
+ foundFirst = true;
+ }
+ }
+ return 0;
+ }
+
+ // Returns the item before modelIndex, if created.
+ // May return an item marked for removal.
+ FxListItemSG *itemBefore(int modelIndex) const {
+ if (modelIndex < visibleIndex)
+ return 0;
+ int idx = 1;
+ int lastIndex = -1;
+ while (idx < visibleItems.count()) {
+ FxListItemSG *item = visibleItems.at(idx);
+ if (item->index != -1)
+ lastIndex = item->index;
+ if (item->index == modelIndex)
+ return visibleItems.at(idx-1);
+ ++idx;
+ }
+ if (lastIndex == modelIndex-1)
+ return visibleItems.last();
+ return 0;
+ }
+
+ void regenerate() {
+ Q_Q(QSGListView);
+ if (q->isComponentComplete()) {
+ if (header) {
+ // XXX todo - the original did scene()->removeItem(). Why?
+ header->item->setParentItem(0);
+ header->item->deleteLater();
+ delete header;
+ header = 0;
+ }
+ if (footer) {
+ // XXX todo - the original did scene()->removeItem(). Why?
+ footer->item->setParentItem(0);
+ footer->item->deleteLater();
+ delete footer;
+ footer = 0;
+ }
+ updateHeader();
+ updateFooter();
+ clear();
+ setPosition(0);
+ q->refill();
+ updateCurrent(currentIndex);
+ }
+ }
+
+ void mirrorChange() {
+ Q_Q(QSGListView);
+ regenerate();
+ emit q->effectiveLayoutDirectionChanged();
+ }
+
+ bool isRightToLeft() const {
+ Q_Q(const QSGListView);
+ return orient == QSGListView::Horizontal && q->effectiveLayoutDirection() == Qt::RightToLeft;
+ }
+
+ qreal position() const {
+ Q_Q(const QSGListView);
+ return orient == QSGListView::Vertical ? q->contentY() : q->contentX();
+ }
+ void setPosition(qreal pos) {
+ Q_Q(QSGListView);
+ if (orient == QSGListView::Vertical) {
+ q->QSGFlickable::setContentY(pos);
+ } else {
+ if (isRightToLeft())
+ q->QSGFlickable::setContentX(-pos-size());
+ else
+ q->QSGFlickable::setContentX(pos);
+ }
+ }
+ qreal size() const {
+ Q_Q(const QSGListView);
+ return orient == QSGListView::Vertical ? q->height() : q->width();
+ }
+
+ qreal originPosition() const {
+ qreal pos = 0;
+ if (!visibleItems.isEmpty()) {
+ pos = (*visibleItems.constBegin())->position();
+ if (visibleIndex > 0)
+ pos -= visibleIndex * (averageSize + spacing);
+ }
+ return pos;
+ }
+
+ qreal lastPosition() const {
+ qreal pos = 0;
+ if (!visibleItems.isEmpty()) {
+ int invisibleCount = visibleItems.count() - visibleIndex;
+ for (int i = visibleItems.count()-1; i >= 0; --i) {
+ if (visibleItems.at(i)->index != -1) {
+ invisibleCount = model->count() - visibleItems.at(i)->index - 1;
+ break;
+ }
+ }
+ pos = (*(--visibleItems.constEnd()))->endPosition() + invisibleCount * (averageSize + spacing);
+ } else if (model && model->count()) {
+ pos = model->count() * averageSize + (model->count()-1) * spacing;
+ }
+ return pos;
+ }
+
+ qreal startPosition() const {
+ return isRightToLeft() ? -lastPosition()-1 : originPosition();
+ }
+
+ qreal endPosition() const {
+ return isRightToLeft() ? -originPosition()-1 : lastPosition();
+ }
+
+ qreal positionAt(int modelIndex) const {
+ if (FxListItemSG *item = visibleItem(modelIndex))
+ return item->position();
+ if (!visibleItems.isEmpty()) {
+ if (modelIndex < visibleIndex) {
+ int count = visibleIndex - modelIndex;
+ qreal cs = 0;
+ if (modelIndex == currentIndex && currentItem) {
+ cs = currentItem->size() + spacing;
+ --count;
+ }
+ return (*visibleItems.constBegin())->position() - count * (averageSize + spacing) - cs;
+ } else {
+ int idx = visibleItems.count() - 1;
+ while (idx >= 0 && visibleItems.at(idx)->index == -1)
+ --idx;
+ if (idx < 0)
+ idx = visibleIndex;
+ else
+ idx = visibleItems.at(idx)->index;
+ int count = modelIndex - idx - 1;
+ return (*(--visibleItems.constEnd()))->endPosition() + spacing + count * (averageSize + spacing) + 1;
+ }
+ }
+ return 0;
+ }
+
+ qreal endPositionAt(int modelIndex) const {
+ if (FxListItemSG *item = visibleItem(modelIndex))
+ return item->endPosition();
+ if (!visibleItems.isEmpty()) {
+ if (modelIndex < visibleIndex) {
+ int count = visibleIndex - modelIndex;
+ return (*visibleItems.constBegin())->position() - (count - 1) * (averageSize + spacing) - spacing - 1;
+ } else {
+ int idx = visibleItems.count() - 1;
+ while (idx >= 0 && visibleItems.at(idx)->index == -1)
+ --idx;
+ if (idx < 0)
+ idx = visibleIndex;
+ else
+ idx = visibleItems.at(idx)->index;
+ int count = modelIndex - idx - 1;
+ return (*(--visibleItems.constEnd()))->endPosition() + count * (averageSize + spacing);
+ }
+ }
+ return 0;
+ }
+
+ QString sectionAt(int modelIndex) {
+ if (FxListItemSG *item = visibleItem(modelIndex))
+ return item->attached->section();
+
+ QString section;
+ if (sectionCriteria) {
+ QString propValue = model->stringValue(modelIndex, sectionCriteria->property());
+ section = sectionCriteria->sectionString(propValue);
+ }
+
+ return section;
+ }
+
+ bool isValid() const {
+ return model && model->count() && model->isValid();
+ }
+
+ qreal snapPosAt(qreal pos) {
+ if (FxListItemSG *snapItem = snapItemAt(pos))
+ return snapItem->position();
+ if (visibleItems.count()) {
+ qreal firstPos = visibleItems.first()->position();
+ qreal endPos = visibleItems.last()->position();
+ if (pos < firstPos) {
+ return firstPos - qRound((firstPos - pos) / averageSize) * averageSize;
+ } else if (pos > endPos)
+ return endPos + qRound((pos - endPos) / averageSize) * averageSize;
+ }
+ return qRound((pos - originPosition()) / averageSize) * averageSize + originPosition();
+ }
+
+ FxListItemSG *snapItemAt(qreal pos) {
+ FxListItemSG *snapItem = 0;
+ for (int i = 0; i < visibleItems.count(); ++i) {
+ FxListItemSG *item = visibleItems[i];
+ if (item->index == -1)
+ continue;
+ qreal itemTop = item->position();
+ if (highlight && itemTop >= pos && item->endPosition() <= pos + highlight->size() - 1)
+ return item;
+ if (itemTop+item->size()/2 >= pos && itemTop-item->size()/2 < pos)
+ snapItem = item;
+ }
+ return snapItem;
+ }
+
+ int lastVisibleIndex() const {
+ int lastIndex = -1;
+ for (int i = visibleItems.count()-1; i >= 0; --i) {
+ FxListItemSG *listItem = visibleItems.at(i);
+ if (listItem->index != -1) {
+ lastIndex = listItem->index;
+ break;
+ }
+ }
+ return lastIndex;
+ }
+
+ // map a model index to visibleItems index.
+ int mapFromModel(int modelIndex) const {
+ if (modelIndex < visibleIndex || modelIndex >= visibleIndex + visibleItems.count())
+ return -1;
+ for (int i = 0; i < visibleItems.count(); ++i) {
+ FxListItemSG *listItem = visibleItems.at(i);
+ if (listItem->index == modelIndex)
+ return i;
+ if (listItem->index > modelIndex)
+ return -1;
+ }
+ return -1; // Not in visibleList
+ }
+
+ void updateViewport() {
+ Q_Q(QSGListView);
+ if (orient == QSGListView::Vertical) {
+ q->setContentHeight(endPosition() - startPosition() + 1);
+ } else {
+ q->setContentWidth(endPosition() - startPosition() + 1);
+ }
+ }
+
+ void itemGeometryChanged(QSGItem *item, const QRectF &newGeometry, const QRectF &oldGeometry) {
+ Q_Q(QSGListView);
+ QSGFlickablePrivate::itemGeometryChanged(item, newGeometry, oldGeometry);
+ if (!q->isComponentComplete())
+ return;
+ if (item != contentItem && (!highlight || item != highlight->item)) {
+ if ((orient == QSGListView::Vertical && newGeometry.height() != oldGeometry.height())
+ || (orient == QSGListView::Horizontal && newGeometry.width() != oldGeometry.width())) {
+ scheduleLayout();
+ }
+ }
+ if ((header && header->item == item) || (footer && footer->item == item)) {
+ if (header)
+ updateHeader();
+ if (footer)
+ updateFooter();
+ }
+ if (currentItem && currentItem->item == item)
+ updateHighlight();
+ if (trackedItem && trackedItem->item == item)
+ q->trackedPositionChanged();
+ }
+
+ // for debugging only
+ void checkVisible() const {
+ int skip = 0;
+ for (int i = 0; i < visibleItems.count(); ++i) {
+ FxListItemSG *listItem = visibleItems.at(i);
+ if (listItem->index == -1) {
+ ++skip;
+ } else if (listItem->index != visibleIndex + i - skip) {
+ qFatal("index %d %d %d", visibleIndex, i, listItem->index);
+ }
+ }
+ }
+
+ void refill(qreal from, qreal to, bool doBuffer = false);
+ void scheduleLayout();
+ void layout();
+ void updateUnrequestedIndexes();
+ void updateUnrequestedPositions();
+ void updateTrackedItem();
+ void createHighlight();
+ void updateHighlight();
+ void createSection(FxListItemSG *);
+ void updateSections();
+ void updateCurrentSection();
+ void updateCurrent(int);
+ void updateAverage();
+ void updateHeader();
+ void updateFooter();
+ void fixupPosition();
+ void positionViewAtIndex(int index, int mode);
+ virtual void fixup(AxisData &data, qreal minExtent, qreal maxExtent);
+ virtual void flick(QSGFlickablePrivate::AxisData &data, qreal minExtent, qreal maxExtent, qreal vSize,
+ QDeclarativeTimeLineCallback::Callback fixupCallback, qreal velocity);
+
+ QDeclarativeGuard<QSGVisualModel> model;
+ QVariant modelVariant;
+ QList<FxListItemSG*> visibleItems;
+ QHash<QSGItem*,int> unrequestedItems;
+ FxListItemSG *currentItem;
+ QSGListView::Orientation orient;
+ Qt::LayoutDirection layoutDirection;
+ qreal visiblePos;
+ int visibleIndex;
+ qreal averageSize;
+ int currentIndex;
+ int requestedIndex;
+ int itemCount;
+ qreal highlightRangeStart;
+ qreal highlightRangeEnd;
+ QDeclarativeComponent *highlightComponent;
+ FxListItemSG *highlight;
+ FxListItemSG *trackedItem;
+ enum MovementReason { Other, SetIndex, Mouse };
+ MovementReason moveReason;
+ int buffer;
+ QSmoothedAnimation *highlightPosAnimator;
+ QSmoothedAnimation *highlightSizeAnimator;
+ QSGViewSection *sectionCriteria;
+ QString currentSection;
+ static const int sectionCacheSize = 4;
+ QSGItem *sectionCache[sectionCacheSize];
+ qreal spacing;
+ qreal highlightMoveSpeed;
+ int highlightMoveDuration;
+ qreal highlightResizeSpeed;
+ int highlightResizeDuration;
+ QSGListView::HighlightRangeMode highlightRange;
+ QSGListView::SnapMode snapMode;
+ qreal overshootDist;
+ QDeclarativeComponent *footerComponent;
+ FxListItemSG *footer;
+ QDeclarativeComponent *headerComponent;
+ FxListItemSG *header;
+ enum BufferMode { NoBuffer = 0x00, BufferBefore = 0x01, BufferAfter = 0x02 };
+ int bufferMode;
+ mutable qreal minExtent;
+ mutable qreal maxExtent;
+
+ bool ownModel : 1;
+ bool wrap : 1;
+ bool autoHighlight : 1;
+ bool haveHighlightRange : 1;
+ bool correctFlick : 1;
+ bool inFlickCorrection : 1;
+ bool lazyRelease : 1;
+ bool deferredRelease : 1;
+ bool layoutScheduled : 1;
+ bool currentIndexCleared : 1;
+ bool inViewportMoved : 1;
+ bool highlightRangeStartValid : 1;
+ bool highlightRangeEndValid : 1;
+ mutable bool minExtentDirty : 1;
+ mutable bool maxExtentDirty : 1;
+};
+
+void QSGListViewPrivate::init()
+{
+ Q_Q(QSGListView);
+ QSGItemPrivate::get(contentItem)->childrenDoNotOverlap = true;
+ q->setFlag(QSGItem::ItemIsFocusScope);
+ addItemChangeListener(this, Geometry);
+ QObject::connect(q, SIGNAL(movementEnded()), q, SLOT(animStopped()));
+ q->setFlickableDirection(QSGFlickable::VerticalFlick);
+ ::memset(sectionCache, 0, sizeof(QSGItem*) * sectionCacheSize);
+}
+
+void QSGListViewPrivate::clear()
+{
+ timeline.clear();
+ for (int i = 0; i < visibleItems.count(); ++i)
+ releaseItem(visibleItems.at(i));
+ visibleItems.clear();
+ for (int i = 0; i < sectionCacheSize; ++i) {
+ delete sectionCache[i];
+ sectionCache[i] = 0;
+ }
+ visiblePos = header ? header->size() : 0;
+ visibleIndex = 0;
+ releaseItem(currentItem);
+ currentItem = 0;
+ createHighlight();
+ trackedItem = 0;
+ minExtentDirty = true;
+ maxExtentDirty = true;
+ itemCount = 0;
+}
+
+FxListItemSG *QSGListViewPrivate::createItem(int modelIndex)
+{
+ Q_Q(QSGListView);
+ // create object
+ requestedIndex = modelIndex;
+ FxListItemSG *listItem = 0;
+ if (QSGItem *item = model->item(modelIndex, false)) {
+ listItem = new FxListItemSG(item, q);
+ listItem->index = modelIndex;
+ // initialise attached properties
+ if (sectionCriteria) {
+ QString propValue = model->stringValue(modelIndex, sectionCriteria->property());
+ listItem->attached->m_section = sectionCriteria->sectionString(propValue);
+ if (modelIndex > 0) {
+ if (FxListItemSG *item = itemBefore(modelIndex))
+ listItem->attached->m_prevSection = item->attached->section();
+ else
+ listItem->attached->m_prevSection = sectionAt(modelIndex-1);
+ }
+ if (modelIndex < model->count()-1) {
+ if (FxListItemSG *item = visibleItem(modelIndex+1))
+ listItem->attached->m_nextSection = item->attached->section();
+ else
+ listItem->attached->m_nextSection = sectionAt(modelIndex+1);
+ }
+ }
+ if (model->completePending()) {
+ // complete
+ listItem->item->setZ(1);
+ listItem->item->setParentItem(q->contentItem());
+ model->completeItem();
+ } else {
+ listItem->item->setParentItem(q->contentItem());
+ }
+ QSGItemPrivate *itemPrivate = QSGItemPrivate::get(item);
+ itemPrivate->addItemChangeListener(this, QSGItemPrivate::Geometry);
+ if (sectionCriteria && sectionCriteria->delegate()) {
+ if (listItem->attached->m_prevSection != listItem->attached->m_section)
+ createSection(listItem);
+ }
+ unrequestedItems.remove(listItem->item);
+ }
+ requestedIndex = -1;
+
+ return listItem;
+}
+
+void QSGListViewPrivate::releaseItem(FxListItemSG *item)
+{
+ Q_Q(QSGListView);
+ if (!item || !model)
+ return;
+ if (trackedItem == item)
+ trackedItem = 0;
+ QSGItemPrivate *itemPrivate = QSGItemPrivate::get(item->item);
+ itemPrivate->removeItemChangeListener(this, QSGItemPrivate::Geometry);
+ if (model->release(item->item) == 0) {
+ // item was not destroyed, and we no longer reference it.
+ unrequestedItems.insert(item->item, model->indexOf(item->item, q));
+ }
+ if (item->section) {
+ int i = 0;
+ do {
+ if (!sectionCache[i]) {
+ sectionCache[i] = item->section;
+ sectionCache[i]->setVisible(false);
+ item->section = 0;
+ break;
+ }
+ ++i;
+ } while (i < sectionCacheSize);
+ delete item->section;
+ }
+ delete item;
+}
+
+void QSGListViewPrivate::refill(qreal from, qreal to, bool doBuffer)
+{
+ Q_Q(QSGListView);
+ if (!isValid() || !q->isComponentComplete())
+ return;
+ itemCount = model->count();
+ qreal bufferFrom = from - buffer;
+ qreal bufferTo = to + buffer;
+ qreal fillFrom = from;
+ qreal fillTo = to;
+ if (doBuffer && (bufferMode & BufferAfter))
+ fillTo = bufferTo;
+ if (doBuffer && (bufferMode & BufferBefore))
+ fillFrom = bufferFrom;
+
+ bool haveValidItems = false;
+ int modelIndex = visibleIndex;
+ qreal itemEnd = visiblePos-1;
+ if (!visibleItems.isEmpty()) {
+ visiblePos = (*visibleItems.constBegin())->position();
+ itemEnd = (*(--visibleItems.constEnd()))->endPosition() + spacing;
+ int i = visibleItems.count() - 1;
+ while (i > 0 && visibleItems.at(i)->index == -1)
+ --i;
+ if (visibleItems.at(i)->index != -1) {
+ haveValidItems = true;
+ modelIndex = visibleItems.at(i)->index + 1;
+ }
+ }
+
+ if (haveValidItems && (fillFrom > itemEnd+averageSize+spacing
+ || fillTo < visiblePos - averageSize - spacing)) {
+ // We've jumped more than a page. Estimate which items are now
+ // visible and fill from there.
+ int count = (fillFrom - itemEnd) / (averageSize + spacing);
+ for (int i = 0; i < visibleItems.count(); ++i)
+ releaseItem(visibleItems.at(i));
+ visibleItems.clear();
+ modelIndex += count;
+ if (modelIndex >= model->count()) {
+ count -= modelIndex - model->count() + 1;
+ modelIndex = model->count() - 1;
+ } else if (modelIndex < 0) {
+ count -= modelIndex;
+ modelIndex = 0;
+ }
+ visibleIndex = modelIndex;
+ visiblePos = itemEnd + count * (averageSize + spacing) + 1;
+ itemEnd = visiblePos-1;
+ }
+
+ bool changed = false;
+ FxListItemSG *item = 0;
+ qreal pos = itemEnd + 1;
+ while (modelIndex < model->count() && pos <= fillTo) {
+// qDebug() << "refill: append item" << modelIndex << "pos" << pos;
+ if (!(item = createItem(modelIndex)))
+ break;
+ item->setPosition(pos);
+ pos += item->size() + spacing;
+ visibleItems.append(item);
+ ++modelIndex;
+ changed = true;
+ if (doBuffer) // never buffer more than one item per frame
+ break;
+ }
+ while (visibleIndex > 0 && visibleIndex <= model->count() && visiblePos-1 >= fillFrom) {
+// qDebug() << "refill: prepend item" << visibleIndex-1 << "current top pos" << visiblePos;
+ if (!(item = createItem(visibleIndex-1)))
+ break;
+ --visibleIndex;
+ visiblePos -= item->size() + spacing;
+ item->setPosition(visiblePos);
+ visibleItems.prepend(item);
+ changed = true;
+ if (doBuffer) // never buffer more than one item per frame
+ break;
+ }
+
+ if (!lazyRelease || !changed || deferredRelease) { // avoid destroying items in the same frame that we create
+ while (visibleItems.count() > 1 && (item = visibleItems.first()) && item->endPosition() < bufferFrom) {
+ if (item->attached->delayRemove())
+ break;
+// qDebug() << "refill: remove first" << visibleIndex << "top end pos" << item->endPosition();
+ if (item->index != -1)
+ visibleIndex++;
+ visibleItems.removeFirst();
+ releaseItem(item);
+ changed = true;
+ }
+ while (visibleItems.count() > 1 && (item = visibleItems.last()) && item->position() > bufferTo) {
+ if (item->attached->delayRemove())
+ break;
+// qDebug() << "refill: remove last" << visibleIndex+visibleItems.count()-1 << item->position();
+ visibleItems.removeLast();
+ releaseItem(item);
+ changed = true;
+ }
+ deferredRelease = false;
+ } else {
+ deferredRelease = true;
+ }
+ if (changed) {
+ minExtentDirty = true;
+ maxExtentDirty = true;
+ if (visibleItems.count())
+ visiblePos = (*visibleItems.constBegin())->position();
+ updateAverage();
+ if (currentIndex >= 0 && currentItem && !visibleItem(currentIndex)) {
+ currentItem->setPosition(positionAt(currentIndex));
+ updateHighlight();
+ }
+
+ if (sectionCriteria)
+ updateCurrentSection();
+ if (header)
+ updateHeader();
+ if (footer)
+ updateFooter();
+ updateViewport();
+ updateUnrequestedPositions();
+ } else if (!doBuffer && buffer && bufferMode != NoBuffer) {
+ refill(from, to, true);
+ }
+ lazyRelease = false;
+}
+
+void QSGListViewPrivate::scheduleLayout()
+{
+ Q_Q(QSGListView);
+ if (!layoutScheduled) {
+ layoutScheduled = true;
+ q->polish();
+ }
+}
+
+void QSGListViewPrivate::layout()
+{
+ Q_Q(QSGListView);
+ layoutScheduled = false;
+ if (!isValid() && !visibleItems.count()) {
+ clear();
+ setPosition(0);
+ return;
+ }
+ if (!visibleItems.isEmpty()) {
+ bool fixedCurrent = currentItem && visibleItems.first()->item == currentItem->item;
+ qreal sum = visibleItems.first()->size();
+ qreal pos = visibleItems.first()->position() + visibleItems.first()->size() + spacing;
+ for (int i=1; i < visibleItems.count(); ++i) {
+ FxListItemSG *item = visibleItems.at(i);
+ item->setPosition(pos);
+ pos += item->size() + spacing;
+ sum += item->size();
+ fixedCurrent = fixedCurrent || (currentItem && item->item == currentItem->item);
+ }
+ averageSize = qRound(sum / visibleItems.count());
+ // move current item if it is not a visible item.
+ if (currentIndex >= 0 && currentItem && !fixedCurrent)
+ currentItem->setPosition(positionAt(currentIndex));
+ }
+ q->refill();
+ minExtentDirty = true;
+ maxExtentDirty = true;
+ updateHighlight();
+ if (!q->isMoving() && !q->isFlicking()) {
+ fixupPosition();
+ q->refill();
+ }
+ if (header)
+ updateHeader();
+ if (footer)
+ updateFooter();
+ updateViewport();
+}
+
+void QSGListViewPrivate::updateUnrequestedIndexes()
+{
+ Q_Q(QSGListView);
+ QHash<QSGItem*,int>::iterator it;
+ for (it = unrequestedItems.begin(); it != unrequestedItems.end(); ++it)
+ *it = model->indexOf(it.key(), q);
+}
+
+void QSGListViewPrivate::updateUnrequestedPositions()
+{
+ Q_Q(QSGListView);
+ if (unrequestedItems.count()) {
+ qreal pos = position();
+ QHash<QSGItem*,int>::const_iterator it;
+ for (it = unrequestedItems.begin(); it != unrequestedItems.end(); ++it) {
+ QSGItem *item = it.key();
+ if (orient == QSGListView::Vertical) {
+ if (item->y() + item->height() > pos && item->y() < pos + q->height())
+ item->setY(positionAt(*it));
+ } else {
+ if (item->x() + item->width() > pos && item->x() < pos + q->width()) {
+ if (isRightToLeft())
+ item->setX(-positionAt(*it)-item->width());
+ else
+ item->setX(positionAt(*it));
+ }
+ }
+ }
+ }
+}
+
+void QSGListViewPrivate::updateTrackedItem()
+{
+ Q_Q(QSGListView);
+ FxListItemSG *item = currentItem;
+ if (highlight)
+ item = highlight;
+ trackedItem = item;
+ if (trackedItem)
+ q->trackedPositionChanged();
+}
+
+void QSGListViewPrivate::createHighlight()
+{
+ Q_Q(QSGListView);
+ bool changed = false;
+ if (highlight) {
+ if (trackedItem == highlight)
+ trackedItem = 0;
+ highlight->item->setParentItem(0);
+ highlight->item->deleteLater();
+ delete highlight;
+ highlight = 0;
+ delete highlightPosAnimator;
+ delete highlightSizeAnimator;
+ highlightPosAnimator = 0;
+ highlightSizeAnimator = 0;
+ changed = true;
+ }
+
+ if (currentItem) {
+ QSGItem *item = 0;
+ if (highlightComponent) {
+ QDeclarativeContext *highlightContext = new QDeclarativeContext(qmlContext(q));
+ QObject *nobj = highlightComponent->create(highlightContext);
+ if (nobj) {
+ QDeclarative_setParent_noEvent(highlightContext, nobj);
+ item = qobject_cast<QSGItem *>(nobj);
+ if (!item)
+ delete nobj;
+ } else {
+ delete highlightContext;
+ }
+ } else {
+ item = new QSGItem;
+ }
+ if (item) {
+ QDeclarative_setParent_noEvent(item, q->contentItem());
+ item->setParentItem(q->contentItem());
+ highlight = new FxListItemSG(item, q);
+ if (currentItem && autoHighlight) {
+ if (orient == QSGListView::Vertical) {
+ highlight->item->setHeight(currentItem->item->height());
+ } else {
+ highlight->item->setWidth(currentItem->item->width());
+ }
+ highlight->setPosition(currentItem->itemPosition());
+ }
+ QSGItemPrivate *itemPrivate = QSGItemPrivate::get(item);
+ itemPrivate->addItemChangeListener(this, QSGItemPrivate::Geometry);
+ const QLatin1String posProp(orient == QSGListView::Vertical ? "y" : "x");
+ highlightPosAnimator = new QSmoothedAnimation(q);
+ highlightPosAnimator->target = QDeclarativeProperty(highlight->item, posProp);
+ highlightPosAnimator->velocity = highlightMoveSpeed;
+ highlightPosAnimator->userDuration = highlightMoveDuration;
+ const QLatin1String sizeProp(orient == QSGListView::Vertical ? "height" : "width");
+ highlightSizeAnimator = new QSmoothedAnimation(q);
+ highlightSizeAnimator->velocity = highlightResizeSpeed;
+ highlightSizeAnimator->userDuration = highlightResizeDuration;
+ highlightSizeAnimator->target = QDeclarativeProperty(highlight->item, sizeProp);
+ if (autoHighlight) {
+ highlightPosAnimator->restart();
+ highlightSizeAnimator->restart();
+ }
+ changed = true;
+ }
+ }
+ if (changed)
+ emit q->highlightItemChanged();
+}
+
+void QSGListViewPrivate::updateHighlight()
+{
+ if ((!currentItem && highlight) || (currentItem && !highlight))
+ createHighlight();
+ if (currentItem && autoHighlight && highlight && !movingHorizontally && !movingVertically) {
+ // auto-update highlight
+ highlightPosAnimator->to = isRightToLeft()
+ ? -currentItem->itemPosition()-currentItem->itemSize()
+ : currentItem->itemPosition();
+ highlightSizeAnimator->to = currentItem->itemSize();
+ if (orient == QSGListView::Vertical) {
+ if (highlight->item->width() == 0)
+ highlight->item->setWidth(currentItem->item->width());
+ } else {
+ if (highlight->item->height() == 0)
+ highlight->item->setHeight(currentItem->item->height());
+ }
+ highlightPosAnimator->restart();
+ highlightSizeAnimator->restart();
+ }
+ updateTrackedItem();
+}
+
+void QSGListViewPrivate::createSection(FxListItemSG *listItem)
+{
+ Q_Q(QSGListView);
+ if (!sectionCriteria || !sectionCriteria->delegate())
+ return;
+ if (listItem->attached->m_prevSection != listItem->attached->m_section) {
+ if (!listItem->section) {
+ qreal pos = listItem->position();
+ int i = sectionCacheSize-1;
+ while (i >= 0 && !sectionCache[i])
+ --i;
+ if (i >= 0) {
+ listItem->section = sectionCache[i];
+ sectionCache[i] = 0;
+ listItem->section->setVisible(true);
+ QDeclarativeContext *context = QDeclarativeEngine::contextForObject(listItem->section)->parentContext();
+ context->setContextProperty(QLatin1String("section"), listItem->attached->m_section);
+ } else {
+ QDeclarativeContext *context = new QDeclarativeContext(qmlContext(q));
+ context->setContextProperty(QLatin1String("section"), listItem->attached->m_section);
+ QObject *nobj = sectionCriteria->delegate()->beginCreate(context);
+ if (nobj) {
+ QDeclarative_setParent_noEvent(context, nobj);
+ listItem->section = qobject_cast<QSGItem *>(nobj);
+ if (!listItem->section) {
+ delete nobj;
+ } else {
+ listItem->section->setZ(1);
+ QDeclarative_setParent_noEvent(listItem->section, q->contentItem());
+ listItem->section->setParentItem(q->contentItem());
+ }
+ } else {
+ delete context;
+ }
+ sectionCriteria->delegate()->completeCreate();
+ }
+ listItem->setPosition(pos);
+ } else {
+ QDeclarativeContext *context = QDeclarativeEngine::contextForObject(listItem->section)->parentContext();
+ context->setContextProperty(QLatin1String("section"), listItem->attached->m_section);
+ }
+ } else if (listItem->section) {
+ qreal pos = listItem->position();
+ int i = 0;
+ do {
+ if (!sectionCache[i]) {
+ sectionCache[i] = listItem->section;
+ sectionCache[i]->setVisible(false);
+ listItem->section = 0;
+ return;
+ }
+ ++i;
+ } while (i < sectionCacheSize);
+ delete listItem->section;
+ listItem->section = 0;
+ listItem->setPosition(pos);
+ }
+}
+
+void QSGListViewPrivate::updateSections()
+{
+ if (sectionCriteria && !visibleItems.isEmpty()) {
+ QString prevSection;
+ if (visibleIndex > 0)
+ prevSection = sectionAt(visibleIndex-1);
+ QSGListViewAttached *prevAtt = 0;
+ int idx = -1;
+ for (int i = 0; i < visibleItems.count(); ++i) {
+ QSGListViewAttached *attached = visibleItems.at(i)->attached;
+ attached->setPrevSection(prevSection);
+ if (visibleItems.at(i)->index != -1) {
+ QString propValue = model->stringValue(visibleItems.at(i)->index, sectionCriteria->property());
+ attached->setSection(sectionCriteria->sectionString(propValue));
+ idx = visibleItems.at(i)->index;
+ }
+ createSection(visibleItems.at(i));
+ if (prevAtt)
+ prevAtt->setNextSection(attached->section());
+ prevSection = attached->section();
+ prevAtt = attached;
+ }
+ if (prevAtt) {
+ if (idx > 0 && idx < model->count()-1)
+ prevAtt->setNextSection(sectionAt(idx+1));
+ else
+ prevAtt->setNextSection(QString());
+ }
+ }
+}
+
+void QSGListViewPrivate::updateCurrentSection()
+{
+ Q_Q(QSGListView);
+ if (!sectionCriteria || visibleItems.isEmpty()) {
+ if (!currentSection.isEmpty()) {
+ currentSection.clear();
+ emit q->currentSectionChanged();
+ }
+ return;
+ }
+ int index = 0;
+ while (index < visibleItems.count() && visibleItems.at(index)->endPosition() < position())
+ ++index;
+
+ QString newSection = currentSection;
+ if (index < visibleItems.count())
+ newSection = visibleItems.at(index)->attached->section();
+ else
+ newSection = visibleItems.first()->attached->section();
+ if (newSection != currentSection) {
+ currentSection = newSection;
+ emit q->currentSectionChanged();
+ }
+}
+
+void QSGListViewPrivate::updateCurrent(int modelIndex)
+{
+ Q_Q(QSGListView);
+ if (!q->isComponentComplete() || !isValid() || modelIndex < 0 || modelIndex >= model->count()) {
+ if (currentItem) {
+ currentItem->attached->setIsCurrentItem(false);
+ releaseItem(currentItem);
+ currentItem = 0;
+ currentIndex = modelIndex;
+ emit q->currentIndexChanged();
+ updateHighlight();
+ } else if (currentIndex != modelIndex) {
+ currentIndex = modelIndex;
+ emit q->currentIndexChanged();
+ }
+ return;
+ }
+
+ if (currentItem && currentIndex == modelIndex) {
+ updateHighlight();
+ return;
+ }
+ FxListItemSG *oldCurrentItem = currentItem;
+ currentIndex = modelIndex;
+ currentItem = createItem(modelIndex);
+ if (oldCurrentItem && (!currentItem || oldCurrentItem->item != currentItem->item))
+ oldCurrentItem->attached->setIsCurrentItem(false);
+ if (currentItem) {
+ if (modelIndex == visibleIndex - 1 && visibleItems.count()) {
+ // We can calculate exact postion in this case
+ currentItem->setPosition(visibleItems.first()->position() - currentItem->size() - spacing);
+ } else {
+ // Create current item now and position as best we can.
+ // Its position will be corrected when it becomes visible.
+ currentItem->setPosition(positionAt(modelIndex));
+ }
+ currentItem->item->setFocus(true);
+ currentItem->attached->setIsCurrentItem(true);
+ // Avoid showing section delegate twice. We still need the section heading so that
+ // currentItem positioning works correctly.
+ // This is slightly sub-optimal, but section heading caching minimizes the impact.
+ if (currentItem->section)
+ currentItem->section->setVisible(false);
+ if (visibleItems.isEmpty())
+ averageSize = currentItem->size();
+ }
+ updateHighlight();
+ emit q->currentIndexChanged();
+ // Release the old current item
+ releaseItem(oldCurrentItem);
+}
+
+void QSGListViewPrivate::updateAverage()
+{
+ if (!visibleItems.count())
+ return;
+ qreal sum = 0.0;
+ for (int i = 0; i < visibleItems.count(); ++i)
+ sum += visibleItems.at(i)->size();
+ averageSize = qRound(sum / visibleItems.count());
+}
+
+void QSGListViewPrivate::updateFooter()
+{
+ Q_Q(QSGListView);
+ if (!footer && footerComponent) {
+ QSGItem *item = 0;
+ QDeclarativeContext *context = new QDeclarativeContext(qmlContext(q));
+ QObject *nobj = footerComponent->create(context);
+ if (nobj) {
+ QDeclarative_setParent_noEvent(context, nobj);
+ item = qobject_cast<QSGItem *>(nobj);
+ if (!item)
+ delete nobj;
+ } else {
+ delete context;
+ }
+ if (item) {
+ QDeclarative_setParent_noEvent(item, q->contentItem());
+ item->setParentItem(q->contentItem());
+ item->setZ(1);
+ QSGItemPrivate *itemPrivate = QSGItemPrivate::get(item);
+ itemPrivate->addItemChangeListener(this, QSGItemPrivate::Geometry);
+ footer = new FxListItemSG(item, q);
+ }
+ }
+ if (footer) {
+ if (visibleItems.count()) {
+ qreal endPos = lastPosition() + 1;
+ if (lastVisibleIndex() == model->count()-1) {
+ footer->setPosition(endPos);
+ } else {
+ qreal visiblePos = position() + q->height();
+ if (endPos <= visiblePos || footer->position() < endPos)
+ footer->setPosition(endPos);
+ }
+ } else {
+ footer->setPosition(visiblePos);
+ }
+ }
+}
+
+void QSGListViewPrivate::updateHeader()
+{
+ Q_Q(QSGListView);
+ if (!header && headerComponent) {
+ QSGItem *item = 0;
+ QDeclarativeContext *context = new QDeclarativeContext(qmlContext(q));
+ QObject *nobj = headerComponent->create(context);
+ if (nobj) {
+ QDeclarative_setParent_noEvent(context, nobj);
+ item = qobject_cast<QSGItem *>(nobj);
+ if (!item)
+ delete nobj;
+ } else {
+ delete context;
+ }
+ if (item) {
+ QDeclarative_setParent_noEvent(item, q->contentItem());
+ item->setParentItem(q->contentItem());
+ item->setZ(1);
+ QSGItemPrivate *itemPrivate = QSGItemPrivate::get(item);
+ itemPrivate->addItemChangeListener(this, QSGItemPrivate::Geometry);
+ header = new FxListItemSG(item, q);
+ }
+ }
+ if (header) {
+ if (visibleItems.count()) {
+ qreal startPos = originPosition();
+ if (visibleIndex == 0) {
+ header->setPosition(startPos - header->size());
+ } else {
+ if (position() <= startPos || header->position() > startPos - header->size())
+ header->setPosition(startPos - header->size());
+ }
+ } else {
+ if (itemCount == 0)
+ visiblePos = header->size();
+ header->setPosition(0);
+ }
+ }
+}
+
+void QSGListViewPrivate::fixupPosition()
+{
+ if ((haveHighlightRange && highlightRange == QSGListView::StrictlyEnforceRange)
+ || snapMode != QSGListView::NoSnap)
+ moveReason = Other;
+ if (orient == QSGListView::Vertical)
+ fixupY();
+ else
+ fixupX();
+}
+
+void QSGListViewPrivate::fixup(AxisData &data, qreal minExtent, qreal maxExtent)
+{
+ if ((orient == QSGListView::Horizontal && &data == &vData)
+ || (orient == QSGListView::Vertical && &data == &hData))
+ return;
+
+ correctFlick = false;
+ fixupMode = moveReason == Mouse ? fixupMode : Immediate;
+
+ qreal highlightStart;
+ qreal highlightEnd;
+ qreal viewPos;
+ if (isRightToLeft()) {
+ // Handle Right-To-Left exceptions
+ viewPos = -position()-size();
+ highlightStart = highlightRangeStartValid ? size() - highlightRangeEnd : highlightRangeStart;
+ highlightEnd = highlightRangeEndValid ? size() - highlightRangeStart : highlightRangeEnd;
+ } else {
+ viewPos = position();
+ highlightStart = highlightRangeStart;
+ highlightEnd = highlightRangeEnd;
+ }
+
+ if (currentItem && haveHighlightRange && highlightRange == QSGListView::StrictlyEnforceRange
+ && moveReason != QSGListViewPrivate::SetIndex) {
+ updateHighlight();
+ qreal pos = currentItem->itemPosition();
+ if (viewPos < pos + currentItem->itemSize() - highlightEnd)
+ viewPos = pos + currentItem->itemSize() - highlightEnd;
+ if (viewPos > pos - highlightStart)
+ viewPos = pos - highlightStart;
+ if (isRightToLeft())
+ viewPos = -viewPos-size();
+
+ timeline.reset(data.move);
+ if (viewPos != position()) {
+ if (fixupMode != Immediate) {
+ timeline.move(data.move, -viewPos, QEasingCurve(QEasingCurve::InOutQuad), fixupDuration/2);
+ data.fixingUp = true;
+ } else {
+ timeline.set(data.move, -viewPos);
+ }
+ }
+ vTime = timeline.time();
+ } else if (snapMode != QSGListView::NoSnap && moveReason != QSGListViewPrivate::SetIndex) {
+ qreal tempPosition = isRightToLeft() ? -position()-size() : position();
+ FxListItemSG *topItem = snapItemAt(tempPosition+highlightStart);
+ FxListItemSG *bottomItem = snapItemAt(tempPosition+highlightEnd);
+ qreal pos;
+ bool isInBounds = -position() > maxExtent && -position() < minExtent;
+ if (topItem && isInBounds) {
+ if (topItem->index == 0 && header && tempPosition+highlightStart < header->position()+header->size()/2) {
+ pos = isRightToLeft() ? - header->position() + highlightStart - size() : header->position() - highlightStart;
+ } else {
+ if (isRightToLeft())
+ pos = qMax(qMin(-topItem->position() + highlightStart - size(), -maxExtent), -minExtent);
+ else
+ pos = qMax(qMin(topItem->position() - highlightStart, -maxExtent), -minExtent);
+ }
+ } else if (bottomItem && isInBounds) {
+ if (isRightToLeft())
+ pos = qMax(qMin(-bottomItem->position() + highlightStart - size(), -maxExtent), -minExtent);
+ else
+ pos = qMax(qMin(bottomItem->position() - highlightStart, -maxExtent), -minExtent);
+ } else {
+ QSGFlickablePrivate::fixup(data, minExtent, maxExtent);
+ return;
+ }
+
+ qreal dist = qAbs(data.move + pos);
+ if (dist > 0) {
+ timeline.reset(data.move);
+ if (fixupMode != Immediate) {
+ timeline.move(data.move, -pos, QEasingCurve(QEasingCurve::InOutQuad), fixupDuration/2);
+ data.fixingUp = true;
+ } else {
+ timeline.set(data.move, -pos);
+ }
+ vTime = timeline.time();
+ }
+ } else {
+ QSGFlickablePrivate::fixup(data, minExtent, maxExtent);
+ }
+ data.inOvershoot = false;
+ fixupMode = Normal;
+}
+
+void QSGListViewPrivate::flick(AxisData &data, qreal minExtent, qreal maxExtent, qreal vSize,
+ QDeclarativeTimeLineCallback::Callback fixupCallback, qreal velocity)
+{
+ Q_Q(QSGListView);
+
+ data.fixingUp = false;
+ moveReason = Mouse;
+ if ((!haveHighlightRange || highlightRange != QSGListView::StrictlyEnforceRange) && snapMode == QSGListView::NoSnap) {
+ correctFlick = true;
+ QSGFlickablePrivate::flick(data, minExtent, maxExtent, vSize, fixupCallback, velocity);
+ return;
+ }
+ qreal maxDistance = 0;
+ qreal dataValue = isRightToLeft() ? -data.move.value()+size() : data.move.value();
+ // -ve velocity means list is moving up/left
+ if (velocity > 0) {
+ if (data.move.value() < minExtent) {
+ if (snapMode == QSGListView::SnapOneItem) {
+ if (FxListItemSG *item = isRightToLeft() ? nextVisibleItem() : firstVisibleItem())
+ maxDistance = qAbs(item->position() + dataValue);
+ } else {
+ maxDistance = qAbs(minExtent - data.move.value());
+ }
+ }
+ if (snapMode == QSGListView::NoSnap && highlightRange != QSGListView::StrictlyEnforceRange)
+ data.flickTarget = minExtent;
+ } else {
+ if (data.move.value() > maxExtent) {
+ if (snapMode == QSGListView::SnapOneItem) {
+ if (FxListItemSG *item = isRightToLeft() ? firstVisibleItem() : nextVisibleItem())
+ maxDistance = qAbs(item->position() + dataValue);
+ } else {
+ maxDistance = qAbs(maxExtent - data.move.value());
+ }
+ }
+ if (snapMode == QSGListView::NoSnap && highlightRange != QSGListView::StrictlyEnforceRange)
+ data.flickTarget = maxExtent;
+ }
+ bool overShoot = boundsBehavior == QSGFlickable::DragAndOvershootBounds;
+ qreal highlightStart = isRightToLeft() && highlightRangeStartValid ? size()-highlightRangeEnd : highlightRangeStart;
+ if (maxDistance > 0 || overShoot) {
+ // These modes require the list to stop exactly on an item boundary.
+ // The initial flick will estimate the boundary to stop on.
+ // Since list items can have variable sizes, the boundary will be
+ // reevaluated and adjusted as we approach the boundary.
+ qreal v = velocity;
+ if (maxVelocity != -1 && maxVelocity < qAbs(v)) {
+ if (v < 0)
+ v = -maxVelocity;
+ else
+ v = maxVelocity;
+ }
+ if (!flickingHorizontally && !flickingVertically) {
+ // the initial flick - estimate boundary
+ qreal accel = deceleration;
+ qreal v2 = v * v;
+ overshootDist = 0.0;
+ // + averageSize/4 to encourage moving at least one item in the flick direction
+ qreal dist = v2 / (accel * 2.0) + averageSize/4;
+ if (maxDistance > 0)
+ dist = qMin(dist, maxDistance);
+ if (v > 0)
+ dist = -dist;
+ if ((maxDistance > 0.0 && v2 / (2.0f * maxDistance) < accel) || snapMode == QSGListView::SnapOneItem) {
+ qreal distTemp = isRightToLeft() ? -dist : dist;
+ data.flickTarget = -snapPosAt(-(dataValue - highlightStart) + distTemp) + highlightStart;
+ data.flickTarget = isRightToLeft() ? -data.flickTarget+size() : data.flickTarget;
+ if (overShoot) {
+ if (data.flickTarget >= minExtent) {
+ overshootDist = overShootDistance(vSize);
+ data.flickTarget += overshootDist;
+ } else if (data.flickTarget <= maxExtent) {
+ overshootDist = overShootDistance(vSize);
+ data.flickTarget -= overshootDist;
+ }
+ }
+ qreal adjDist = -data.flickTarget + data.move.value();
+ if (qAbs(adjDist) > qAbs(dist)) {
+ // Prevent painfully slow flicking - adjust velocity to suit flickDeceleration
+ qreal adjv2 = accel * 2.0f * qAbs(adjDist);
+ if (adjv2 > v2) {
+ v2 = adjv2;
+ v = qSqrt(v2);
+ if (dist > 0)
+ v = -v;
+ }
+ }
+ dist = adjDist;
+ accel = v2 / (2.0f * qAbs(dist));
+ } else if (overShoot) {
+ data.flickTarget = data.move.value() - dist;
+ if (data.flickTarget >= minExtent) {
+ overshootDist = overShootDistance(vSize);
+ data.flickTarget += overshootDist;
+ } else if (data.flickTarget <= maxExtent) {
+ overshootDist = overShootDistance(vSize);
+ data.flickTarget -= overshootDist;
+ }
+ }
+ timeline.reset(data.move);
+ timeline.accel(data.move, v, accel, maxDistance + overshootDist);
+ timeline.callback(QDeclarativeTimeLineCallback(&data.move, fixupCallback, this));
+ if (!flickingHorizontally && q->xflick()) {
+ flickingHorizontally = true;
+ emit q->flickingChanged();
+ emit q->flickingHorizontallyChanged();
+ emit q->flickStarted();
+ }
+ if (!flickingVertically && q->yflick()) {
+ flickingVertically = true;
+ emit q->flickingChanged();
+ emit q->flickingVerticallyChanged();
+ emit q->flickStarted();
+ }
+ correctFlick = true;
+ } else {
+ // reevaluate the target boundary.
+ qreal newtarget = data.flickTarget;
+ if (snapMode != QSGListView::NoSnap || highlightRange == QSGListView::StrictlyEnforceRange) {
+ qreal tempFlickTarget = isRightToLeft() ? -data.flickTarget+size() : data.flickTarget;
+ newtarget = -snapPosAt(-(tempFlickTarget - highlightStart)) + highlightStart;
+ newtarget = isRightToLeft() ? -newtarget+size() : newtarget;
+ }
+ if (velocity < 0 && newtarget <= maxExtent)
+ newtarget = maxExtent - overshootDist;
+ else if (velocity > 0 && newtarget >= minExtent)
+ newtarget = minExtent + overshootDist;
+ if (newtarget == data.flickTarget) { // boundary unchanged - nothing to do
+ if (qAbs(velocity) < MinimumFlickVelocity)
+ correctFlick = false;
+ return;
+ }
+ data.flickTarget = newtarget;
+ qreal dist = -newtarget + data.move.value();
+ if ((v < 0 && dist < 0) || (v > 0 && dist > 0)) {
+ correctFlick = false;
+ timeline.reset(data.move);
+ fixup(data, minExtent, maxExtent);
+ return;
+ }
+ timeline.reset(data.move);
+ timeline.accelDistance(data.move, v, -dist);
+ timeline.callback(QDeclarativeTimeLineCallback(&data.move, fixupCallback, this));
+ }
+ } else {
+ correctFlick = false;
+ timeline.reset(data.move);
+ fixup(data, minExtent, maxExtent);
+ }
+}
+
+//----------------------------------------------------------------------------
+
+QSGListView::QSGListView(QSGItem *parent)
+ : QSGFlickable(*(new QSGListViewPrivate), parent)
+{
+ Q_D(QSGListView);
+ d->init();
+}
+
+QSGListView::~QSGListView()
+{
+ Q_D(QSGListView);
+ d->clear();
+ if (d->ownModel)
+ delete d->model;
+ delete d->header;
+ delete d->footer;
+}
+
+QVariant QSGListView::model() const
+{
+ Q_D(const QSGListView);
+ return d->modelVariant;
+}
+
+void QSGListView::setModel(const QVariant &model)
+{
+ Q_D(QSGListView);
+ if (d->modelVariant == model)
+ return;
+ if (d->model) {
+ disconnect(d->model, SIGNAL(itemsInserted(int,int)), this, SLOT(itemsInserted(int,int)));
+ disconnect(d->model, SIGNAL(itemsRemoved(int,int)), this, SLOT(itemsRemoved(int,int)));
+ disconnect(d->model, SIGNAL(itemsMoved(int,int,int)), this, SLOT(itemsMoved(int,int,int)));
+ disconnect(d->model, SIGNAL(itemsChanged(int,int)), this, SLOT(itemsChanged(int,int)));
+ disconnect(d->model, SIGNAL(modelReset()), this, SLOT(modelReset()));
+ disconnect(d->model, SIGNAL(createdItem(int,QSGItem*)), this, SLOT(createdItem(int,QSGItem*)));
+ disconnect(d->model, SIGNAL(destroyingItem(QSGItem*)), this, SLOT(destroyingItem(QSGItem*)));
+ }
+ d->clear();
+ QSGVisualModel *oldModel = d->model;
+ d->model = 0;
+ d->setPosition(0);
+ d->modelVariant = model;
+ QObject *object = qvariant_cast<QObject*>(model);
+ QSGVisualModel *vim = 0;
+ if (object && (vim = qobject_cast<QSGVisualModel *>(object))) {
+ if (d->ownModel) {
+ delete oldModel;
+ d->ownModel = false;
+ }
+ d->model = vim;
+ } else {
+ if (!d->ownModel) {
+ d->model = new QSGVisualDataModel(qmlContext(this), this);
+ d->ownModel = true;
+ } else {
+ d->model = oldModel;
+ }
+ if (QSGVisualDataModel *dataModel = qobject_cast<QSGVisualDataModel*>(d->model))
+ dataModel->setModel(model);
+ }
+ if (d->model) {
+ d->bufferMode = QSGListViewPrivate::BufferBefore | QSGListViewPrivate::BufferAfter;
+ if (isComponentComplete()) {
+ updateSections();
+ refill();
+ if ((d->currentIndex >= d->model->count() || d->currentIndex < 0) && !d->currentIndexCleared) {
+ setCurrentIndex(0);
+ } else {
+ d->moveReason = QSGListViewPrivate::SetIndex;
+ d->updateCurrent(d->currentIndex);
+ if (d->highlight && d->currentItem) {
+ if (d->autoHighlight)
+ d->highlight->setPosition(d->currentItem->position());
+ d->updateTrackedItem();
+ }
+ }
+ d->updateViewport();
+ }
+ connect(d->model, SIGNAL(itemsInserted(int,int)), this, SLOT(itemsInserted(int,int)));
+ connect(d->model, SIGNAL(itemsRemoved(int,int)), this, SLOT(itemsRemoved(int,int)));
+ connect(d->model, SIGNAL(itemsMoved(int,int,int)), this, SLOT(itemsMoved(int,int,int)));
+ connect(d->model, SIGNAL(itemsChanged(int,int)), this, SLOT(itemsChanged(int,int)));
+ connect(d->model, SIGNAL(modelReset()), this, SLOT(modelReset()));
+ connect(d->model, SIGNAL(createdItem(int,QSGItem*)), this, SLOT(createdItem(int,QSGItem*)));
+ connect(d->model, SIGNAL(destroyingItem(QSGItem*)), this, SLOT(destroyingItem(QSGItem*)));
+ emit countChanged();
+ }
+ emit modelChanged();
+}
+
+QDeclarativeComponent *QSGListView::delegate() const
+{
+ Q_D(const QSGListView);
+ if (d->model) {
+ if (QSGVisualDataModel *dataModel = qobject_cast<QSGVisualDataModel*>(d->model))
+ return dataModel->delegate();
+ }
+
+ return 0;
+}
+
+void QSGListView::setDelegate(QDeclarativeComponent *delegate)
+{
+ Q_D(QSGListView);
+ if (delegate == this->delegate())
+ return;
+ if (!d->ownModel) {
+ d->model = new QSGVisualDataModel(qmlContext(this));
+ d->ownModel = true;
+ }
+ if (QSGVisualDataModel *dataModel = qobject_cast<QSGVisualDataModel*>(d->model)) {
+ int oldCount = dataModel->count();
+ dataModel->setDelegate(delegate);
+ if (isComponentComplete()) {
+ for (int i = 0; i < d->visibleItems.count(); ++i)
+ d->releaseItem(d->visibleItems.at(i));
+ d->visibleItems.clear();
+ d->releaseItem(d->currentItem);
+ d->currentItem = 0;
+ updateSections();
+ refill();
+ d->moveReason = QSGListViewPrivate::SetIndex;
+ d->updateCurrent(d->currentIndex);
+ if (d->highlight && d->currentItem) {
+ if (d->autoHighlight)
+ d->highlight->setPosition(d->currentItem->position());
+ d->updateTrackedItem();
+ }
+ d->updateViewport();
+ }
+ if (oldCount != dataModel->count())
+ emit countChanged();
+ }
+ emit delegateChanged();
+}
+
+int QSGListView::currentIndex() const
+{
+ Q_D(const QSGListView);
+ return d->currentIndex;
+}
+
+void QSGListView::setCurrentIndex(int index)
+{
+ Q_D(QSGListView);
+ if (d->requestedIndex >= 0) // currently creating item
+ return;
+ d->currentIndexCleared = (index == -1);
+ if (index == d->currentIndex)
+ return;
+ if (isComponentComplete() && d->isValid()) {
+ d->moveReason = QSGListViewPrivate::SetIndex;
+ d->updateCurrent(index);
+ } else if (d->currentIndex != index) {
+ d->currentIndex = index;
+ emit currentIndexChanged();
+ }
+}
+
+QSGItem *QSGListView::currentItem()
+{
+ Q_D(QSGListView);
+ if (!d->currentItem)
+ return 0;
+ return d->currentItem->item;
+}
+
+QSGItem *QSGListView::highlightItem()
+{
+ Q_D(QSGListView);
+ if (!d->highlight)
+ return 0;
+ return d->highlight->item;
+}
+
+int QSGListView::count() const
+{
+ Q_D(const QSGListView);
+ if (d->model)
+ return d->model->count();
+ return 0;
+}
+
+QDeclarativeComponent *QSGListView::highlight() const
+{
+ Q_D(const QSGListView);
+ return d->highlightComponent;
+}
+
+void QSGListView::setHighlight(QDeclarativeComponent *highlight)
+{
+ Q_D(QSGListView);
+ if (highlight != d->highlightComponent) {
+ d->highlightComponent = highlight;
+ d->createHighlight();
+ if (d->currentItem)
+ d->updateHighlight();
+ emit highlightChanged();
+ }
+}
+
+bool QSGListView::highlightFollowsCurrentItem() const
+{
+ Q_D(const QSGListView);
+ return d->autoHighlight;
+}
+
+void QSGListView::setHighlightFollowsCurrentItem(bool autoHighlight)
+{
+ Q_D(QSGListView);
+ if (d->autoHighlight != autoHighlight) {
+ d->autoHighlight = autoHighlight;
+ if (autoHighlight) {
+ d->updateHighlight();
+ } else {
+ if (d->highlightPosAnimator)
+ d->highlightPosAnimator->stop();
+ if (d->highlightSizeAnimator)
+ d->highlightSizeAnimator->stop();
+ }
+ emit highlightFollowsCurrentItemChanged();
+ }
+}
+
+//###Possibly rename these properties, since they are very useful even without a highlight?
+qreal QSGListView::preferredHighlightBegin() const
+{
+ Q_D(const QSGListView);
+ return d->highlightRangeStart;
+}
+
+void QSGListView::setPreferredHighlightBegin(qreal start)
+{
+ Q_D(QSGListView);
+ d->highlightRangeStartValid = true;
+ if (d->highlightRangeStart == start)
+ return;
+ d->highlightRangeStart = start;
+ d->haveHighlightRange = d->highlightRange != NoHighlightRange && d->highlightRangeStart <= d->highlightRangeEnd;
+ emit preferredHighlightBeginChanged();
+}
+
+void QSGListView::resetPreferredHighlightBegin()
+{
+ Q_D(QSGListView);
+ d->highlightRangeStartValid = false;
+ if (d->highlightRangeStart == 0)
+ return;
+ d->highlightRangeStart = 0;
+ emit preferredHighlightBeginChanged();
+}
+
+qreal QSGListView::preferredHighlightEnd() const
+{
+ Q_D(const QSGListView);
+ return d->highlightRangeEnd;
+}
+
+void QSGListView::setPreferredHighlightEnd(qreal end)
+{
+ Q_D(QSGListView);
+ d->highlightRangeEndValid = true;
+ if (d->highlightRangeEnd == end)
+ return;
+ d->highlightRangeEnd = end;
+ d->haveHighlightRange = d->highlightRange != NoHighlightRange && d->highlightRangeStart <= d->highlightRangeEnd;
+ emit preferredHighlightEndChanged();
+}
+
+void QSGListView::resetPreferredHighlightEnd()
+{
+ Q_D(QSGListView);
+ d->highlightRangeEndValid = false;
+ if (d->highlightRangeEnd == 0)
+ return;
+ d->highlightRangeEnd = 0;
+ emit preferredHighlightEndChanged();
+}
+
+QSGListView::HighlightRangeMode QSGListView::highlightRangeMode() const
+{
+ Q_D(const QSGListView);
+ return d->highlightRange;
+}
+
+void QSGListView::setHighlightRangeMode(HighlightRangeMode mode)
+{
+ Q_D(QSGListView);
+ if (d->highlightRange == mode)
+ return;
+ d->highlightRange = mode;
+ d->haveHighlightRange = d->highlightRange != NoHighlightRange && d->highlightRangeStart <= d->highlightRangeEnd;
+ emit highlightRangeModeChanged();
+}
+
+qreal QSGListView::spacing() const
+{
+ Q_D(const QSGListView);
+ return d->spacing;
+}
+
+void QSGListView::setSpacing(qreal spacing)
+{
+ Q_D(QSGListView);
+ if (spacing != d->spacing) {
+ d->spacing = spacing;
+ d->layout();
+ emit spacingChanged();
+ }
+}
+
+QSGListView::Orientation QSGListView::orientation() const
+{
+ Q_D(const QSGListView);
+ return d->orient;
+}
+
+void QSGListView::setOrientation(QSGListView::Orientation orientation)
+{
+ Q_D(QSGListView);
+ if (d->orient != orientation) {
+ d->orient = orientation;
+ if (d->orient == QSGListView::Vertical) {
+ setContentWidth(-1);
+ setFlickableDirection(VerticalFlick);
+ setContentX(0);
+ } else {
+ setContentHeight(-1);
+ setFlickableDirection(HorizontalFlick);
+ setContentY(0);
+ }
+ d->regenerate();
+ emit orientationChanged();
+ }
+}
+
+Qt::LayoutDirection QSGListView::layoutDirection() const
+{
+ Q_D(const QSGListView);
+ return d->layoutDirection;
+}
+
+void QSGListView::setLayoutDirection(Qt::LayoutDirection layoutDirection)
+{
+ Q_D(QSGListView);
+ if (d->layoutDirection != layoutDirection) {
+ d->layoutDirection = layoutDirection;
+ d->regenerate();
+ emit layoutDirectionChanged();
+ emit effectiveLayoutDirectionChanged();
+ }
+}
+
+Qt::LayoutDirection QSGListView::effectiveLayoutDirection() const
+{
+ Q_D(const QSGListView);
+ if (d->effectiveLayoutMirror)
+ return d->layoutDirection == Qt::RightToLeft ? Qt::LeftToRight : Qt::RightToLeft;
+ else
+ return d->layoutDirection;
+}
+
+bool QSGListView::isWrapEnabled() const
+{
+ Q_D(const QSGListView);
+ return d->wrap;
+}
+
+void QSGListView::setWrapEnabled(bool wrap)
+{
+ Q_D(QSGListView);
+ if (d->wrap == wrap)
+ return;
+ d->wrap = wrap;
+ emit keyNavigationWrapsChanged();
+}
+
+int QSGListView::cacheBuffer() const
+{
+ Q_D(const QSGListView);
+ return d->buffer;
+}
+
+void QSGListView::setCacheBuffer(int b)
+{
+ Q_D(QSGListView);
+ if (d->buffer != b) {
+ d->buffer = b;
+ if (isComponentComplete()) {
+ d->bufferMode = QSGListViewPrivate::BufferBefore | QSGListViewPrivate::BufferAfter;
+ refill();
+ }
+ emit cacheBufferChanged();
+ }
+}
+
+QSGViewSection *QSGListView::sectionCriteria()
+{
+ Q_D(QSGListView);
+ if (!d->sectionCriteria) {
+ d->sectionCriteria = new QSGViewSection(this);
+ connect(d->sectionCriteria, SIGNAL(propertyChanged()), this, SLOT(updateSections()));
+ }
+ return d->sectionCriteria;
+}
+
+QString QSGListView::currentSection() const
+{
+ Q_D(const QSGListView);
+ return d->currentSection;
+}
+
+qreal QSGListView::highlightMoveSpeed() const
+{
+ Q_D(const QSGListView);\
+ return d->highlightMoveSpeed;
+}
+
+void QSGListView::setHighlightMoveSpeed(qreal speed)
+{
+ Q_D(QSGListView);\
+ if (d->highlightMoveSpeed != speed) {
+ d->highlightMoveSpeed = speed;
+ if (d->highlightPosAnimator)
+ d->highlightPosAnimator->velocity = d->highlightMoveSpeed;
+ emit highlightMoveSpeedChanged();
+ }
+}
+
+int QSGListView::highlightMoveDuration() const
+{
+ Q_D(const QSGListView);
+ return d->highlightMoveDuration;
+}
+
+void QSGListView::setHighlightMoveDuration(int duration)
+{
+ Q_D(QSGListView);\
+ if (d->highlightMoveDuration != duration) {
+ d->highlightMoveDuration = duration;
+ if (d->highlightPosAnimator)
+ d->highlightPosAnimator->userDuration = d->highlightMoveDuration;
+ emit highlightMoveDurationChanged();
+ }
+}
+
+qreal QSGListView::highlightResizeSpeed() const
+{
+ Q_D(const QSGListView);\
+ return d->highlightResizeSpeed;
+}
+
+void QSGListView::setHighlightResizeSpeed(qreal speed)
+{
+ Q_D(QSGListView);\
+ if (d->highlightResizeSpeed != speed) {
+ d->highlightResizeSpeed = speed;
+ if (d->highlightSizeAnimator)
+ d->highlightSizeAnimator->velocity = d->highlightResizeSpeed;
+ emit highlightResizeSpeedChanged();
+ }
+}
+
+int QSGListView::highlightResizeDuration() const
+{
+ Q_D(const QSGListView);
+ return d->highlightResizeDuration;
+}
+
+void QSGListView::setHighlightResizeDuration(int duration)
+{
+ Q_D(QSGListView);\
+ if (d->highlightResizeDuration != duration) {
+ d->highlightResizeDuration = duration;
+ if (d->highlightSizeAnimator)
+ d->highlightSizeAnimator->userDuration = d->highlightResizeDuration;
+ emit highlightResizeDurationChanged();
+ }
+}
+
+QSGListView::SnapMode QSGListView::snapMode() const
+{
+ Q_D(const QSGListView);
+ return d->snapMode;
+}
+
+void QSGListView::setSnapMode(SnapMode mode)
+{
+ Q_D(QSGListView);
+ if (d->snapMode != mode) {
+ d->snapMode = mode;
+ emit snapModeChanged();
+ }
+}
+
+QDeclarativeComponent *QSGListView::footer() const
+{
+ Q_D(const QSGListView);
+ return d->footerComponent;
+}
+
+void QSGListView::setFooter(QDeclarativeComponent *footer)
+{
+ Q_D(QSGListView);
+ if (d->footerComponent != footer) {
+ if (d->footer) {
+ // XXX todo - the original did scene()->removeItem(). Why?
+ d->footer->item->setParentItem(0);
+ d->footer->item->deleteLater();
+ delete d->footer;
+ d->footer = 0;
+ }
+ d->footerComponent = footer;
+ d->minExtentDirty = true;
+ d->maxExtentDirty = true;
+ if (isComponentComplete()) {
+ d->updateFooter();
+ d->updateViewport();
+ d->fixupPosition();
+ }
+ emit footerChanged();
+ }
+}
+
+QDeclarativeComponent *QSGListView::header() const
+{
+ Q_D(const QSGListView);
+ return d->headerComponent;
+}
+
+void QSGListView::setHeader(QDeclarativeComponent *header)
+{
+ Q_D(QSGListView);
+ if (d->headerComponent != header) {
+ if (d->header) {
+ // XXX todo - the original did scene()->removeItem(). Why?
+ d->header->item->setParentItem(0);
+ d->header->item->deleteLater();
+ delete d->header;
+ d->header = 0;
+ }
+ d->headerComponent = header;
+ d->minExtentDirty = true;
+ d->maxExtentDirty = true;
+ if (isComponentComplete()) {
+ d->updateHeader();
+ d->updateFooter();
+ d->updateViewport();
+ d->fixupPosition();
+ }
+ emit headerChanged();
+ }
+}
+
+void QSGListView::setContentX(qreal pos)
+{
+ Q_D(QSGListView);
+ // Positioning the view manually should override any current movement state
+ d->moveReason = QSGListViewPrivate::Other;
+ QSGFlickable::setContentX(pos);
+}
+
+void QSGListView::setContentY(qreal pos)
+{
+ Q_D(QSGListView);
+ // Positioning the view manually should override any current movement state
+ d->moveReason = QSGListViewPrivate::Other;
+ QSGFlickable::setContentY(pos);
+}
+
+void QSGListView::updatePolish()
+{
+ Q_D(QSGListView);
+ QSGFlickable::updatePolish();
+ d->layout();
+}
+
+void QSGListView::viewportMoved()
+{
+ Q_D(QSGListView);
+ QSGFlickable::viewportMoved();
+ if (!d->itemCount)
+ return;
+ // Recursion can occur due to refill changing the content size.
+ if (d->inViewportMoved)
+ return;
+ d->inViewportMoved = true;
+ d->lazyRelease = true;
+ refill();
+ if (d->flickingHorizontally || d->flickingVertically || d->movingHorizontally || d->movingVertically)
+ d->moveReason = QSGListViewPrivate::Mouse;
+ if (d->moveReason != QSGListViewPrivate::SetIndex) {
+ if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange && d->highlight) {
+ // reposition highlight
+ qreal pos = d->highlight->position();
+ qreal viewPos;
+ qreal highlightStart;
+ qreal highlightEnd;
+ if (d->isRightToLeft()) {
+ // Handle Right-To-Left exceptions
+ viewPos = -d->position()-d->size();
+ highlightStart = d->highlightRangeStartValid ? d->size()-d->highlightRangeEnd : d->highlightRangeStart;
+ highlightEnd = d->highlightRangeEndValid ? d->size()-d->highlightRangeStart : d->highlightRangeEnd;
+ } else {
+ viewPos = d->position();
+ highlightStart = d->highlightRangeStart;
+ highlightEnd = d->highlightRangeEnd;
+ }
+ if (pos > viewPos + highlightEnd - d->highlight->size())
+ pos = viewPos + highlightEnd - d->highlight->size();
+ if (pos < viewPos + highlightStart)
+ pos = viewPos + highlightStart;
+ d->highlightPosAnimator->stop();
+ d->highlight->setPosition(qRound(pos));
+
+ // update current index
+ if (FxListItemSG *snapItem = d->snapItemAt(d->highlight->position())) {
+ if (snapItem->index >= 0 && snapItem->index != d->currentIndex)
+ d->updateCurrent(snapItem->index);
+ }
+ }
+ }
+
+ if ((d->flickingHorizontally || d->flickingVertically) && d->correctFlick && !d->inFlickCorrection) {
+ d->inFlickCorrection = true;
+ // Near an end and it seems that the extent has changed?
+ // Recalculate the flick so that we don't end up in an odd position.
+ if (yflick() && !d->vData.inOvershoot) {
+ if (d->vData.velocity > 0) {
+ const qreal minY = minYExtent();
+ if ((minY - d->vData.move.value() < height()/2 || d->vData.flickTarget - d->vData.move.value() < height()/2)
+ && minY != d->vData.flickTarget)
+ d->flickY(-d->vData.smoothVelocity.value());
+ d->bufferMode = QSGListViewPrivate::BufferBefore;
+ } else if (d->vData.velocity < 0) {
+ const qreal maxY = maxYExtent();
+ if ((d->vData.move.value() - maxY < height()/2 || d->vData.move.value() - d->vData.flickTarget < height()/2)
+ && maxY != d->vData.flickTarget)
+ d->flickY(-d->vData.smoothVelocity.value());
+ d->bufferMode = QSGListViewPrivate::BufferAfter;
+ }
+ }
+
+ if (xflick() && !d->hData.inOvershoot) {
+ if (d->hData.velocity > 0) {
+ const qreal minX = minXExtent();
+ if ((minX - d->hData.move.value() < width()/2 || d->hData.flickTarget - d->hData.move.value() < width()/2)
+ && minX != d->hData.flickTarget)
+ d->flickX(-d->hData.smoothVelocity.value());
+ d->bufferMode = d->isRightToLeft() ? QSGListViewPrivate::BufferAfter : QSGListViewPrivate::BufferBefore;
+ } else if (d->hData.velocity < 0) {
+ const qreal maxX = maxXExtent();
+ if ((d->hData.move.value() - maxX < width()/2 || d->hData.move.value() - d->hData.flickTarget < width()/2)
+ && maxX != d->hData.flickTarget)
+ d->flickX(-d->hData.smoothVelocity.value());
+ d->bufferMode = d->isRightToLeft() ? QSGListViewPrivate::BufferBefore : QSGListViewPrivate::BufferAfter;
+ }
+ }
+ d->inFlickCorrection = false;
+ }
+ d->inViewportMoved = false;
+}
+
+qreal QSGListView::minYExtent() const
+{
+ Q_D(const QSGListView);
+ if (d->orient == QSGListView::Horizontal)
+ return QSGFlickable::minYExtent();
+ if (d->minExtentDirty) {
+ d->minExtent = -d->startPosition();
+ if (d->header && d->visibleItems.count())
+ d->minExtent += d->header->size();
+ if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange) {
+ d->minExtent += d->highlightRangeStart;
+ if (d->sectionCriteria) {
+ if (d->visibleItem(0))
+ d->minExtent -= d->visibleItem(0)->sectionSize();
+ }
+ d->minExtent = qMax(d->minExtent, -(d->endPositionAt(0) - d->highlightRangeEnd + 1));
+ }
+ d->minExtentDirty = false;
+ }
+
+ return d->minExtent;
+}
+
+qreal QSGListView::maxYExtent() const
+{
+ Q_D(const QSGListView);
+ if (d->orient == QSGListView::Horizontal)
+ return height();
+ if (d->maxExtentDirty) {
+ if (!d->model || !d->model->count()) {
+ d->maxExtent = d->header ? -d->header->size() : 0;
+ d->maxExtent += height();
+ } else if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange) {
+ d->maxExtent = -(d->positionAt(d->model->count()-1) - d->highlightRangeStart);
+ if (d->highlightRangeEnd != d->highlightRangeStart)
+ d->maxExtent = qMin(d->maxExtent, -(d->endPosition() - d->highlightRangeEnd + 1));
+ } else {
+ d->maxExtent = -(d->endPosition() - height() + 1);
+ }
+ if (d->footer)
+ d->maxExtent -= d->footer->size();
+ qreal minY = minYExtent();
+ if (d->maxExtent > minY)
+ d->maxExtent = minY;
+ d->maxExtentDirty = false;
+ }
+ return d->maxExtent;
+}
+
+qreal QSGListView::minXExtent() const
+{
+ Q_D(const QSGListView);
+ if (d->orient == QSGListView::Vertical)
+ return QSGFlickable::minXExtent();
+ if (d->minExtentDirty) {
+ d->minExtent = -d->startPosition();
+ qreal highlightStart;
+ qreal highlightEnd;
+ qreal endPositionFirstItem = 0;
+ if (d->isRightToLeft()) {
+ if (d->model && d->model->count())
+ endPositionFirstItem = d->positionAt(d->model->count()-1);
+ else if (d->header)
+ d->minExtent += d->header->size();
+ highlightStart = d->highlightRangeStartValid
+ ? d->highlightRangeStart - (d->lastPosition()-endPositionFirstItem)
+ : d->size() - (d->lastPosition()-endPositionFirstItem);
+ highlightEnd = d->highlightRangeEndValid ? d->highlightRangeEnd : d->size();
+ if (d->footer)
+ d->minExtent += d->footer->size();
+ qreal maxX = maxXExtent();
+ if (d->minExtent < maxX)
+ d->minExtent = maxX;
+ } else {
+ endPositionFirstItem = d->endPositionAt(0);
+ highlightStart = d->highlightRangeStart;
+ highlightEnd = d->highlightRangeEnd;
+ if (d->header && d->visibleItems.count())
+ d->minExtent += d->header->size();
+ }
+ if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange) {
+ d->minExtent += highlightStart;
+ d->minExtent = qMax(d->minExtent, -(endPositionFirstItem - highlightEnd + 1));
+ }
+ d->minExtentDirty = false;
+ }
+
+ return d->minExtent;
+}
+
+qreal QSGListView::maxXExtent() const
+{
+ Q_D(const QSGListView);
+ if (d->orient == QSGListView::Vertical)
+ return width();
+ if (d->maxExtentDirty) {
+ qreal highlightStart;
+ qreal highlightEnd;
+ qreal lastItemPosition = 0;
+ d->maxExtent = 0;
+ if (d->isRightToLeft()) {
+ highlightStart = d->highlightRangeStartValid ? d->highlightRangeEnd : d->size();
+ highlightEnd = d->highlightRangeEndValid ? d->highlightRangeStart : d->size();
+ lastItemPosition = d->endPosition();
+ } else {
+ highlightStart = d->highlightRangeStart;
+ highlightEnd = d->highlightRangeEnd;
+ if (d->model && d->model->count())
+ lastItemPosition = d->positionAt(d->model->count()-1);
+ }
+ if (!d->model || !d->model->count()) {
+ if (!d->isRightToLeft())
+ d->maxExtent = d->header ? -d->header->size() : 0;
+ d->maxExtent += width();
+ } else if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange) {
+ d->maxExtent = -(lastItemPosition - highlightStart);
+ if (highlightEnd != highlightStart) {
+ d->maxExtent = d->isRightToLeft()
+ ? qMax(d->maxExtent, -(d->endPosition() - highlightEnd + 1))
+ : qMin(d->maxExtent, -(d->endPosition() - highlightEnd + 1));
+ }
+ } else {
+ d->maxExtent = -(d->endPosition() - width() + 1);
+ }
+ if (d->isRightToLeft()) {
+ if (d->header && d->visibleItems.count())
+ d->maxExtent -= d->header->size();
+ } else {
+ if (d->footer)
+ d->maxExtent -= d->footer->size();
+ qreal minX = minXExtent();
+ if (d->maxExtent > minX)
+ d->maxExtent = minX;
+ }
+ d->maxExtentDirty = false;
+ }
+
+ return d->maxExtent;
+}
+
+void QSGListView::keyPressEvent(QKeyEvent *event)
+{
+ Q_D(QSGListView);
+ if (d->model && d->model->count() && d->interactive) {
+ if ((d->orient == QSGListView::Horizontal && !d->isRightToLeft() && event->key() == Qt::Key_Left)
+ || (d->orient == QSGListView::Horizontal && d->isRightToLeft() && event->key() == Qt::Key_Right)
+ || (d->orient == QSGListView::Vertical && event->key() == Qt::Key_Up)) {
+ if (currentIndex() > 0 || (d->wrap && !event->isAutoRepeat())) {
+ decrementCurrentIndex();
+ event->accept();
+ return;
+ } else if (d->wrap) {
+ event->accept();
+ return;
+ }
+ } else if ((d->orient == QSGListView::Horizontal && !d->isRightToLeft() && event->key() == Qt::Key_Right)
+ || (d->orient == QSGListView::Horizontal && d->isRightToLeft() && event->key() == Qt::Key_Left)
+ || (d->orient == QSGListView::Vertical && event->key() == Qt::Key_Down)) {
+ if (currentIndex() < d->model->count() - 1 || (d->wrap && !event->isAutoRepeat())) {
+ incrementCurrentIndex();
+ event->accept();
+ return;
+ } else if (d->wrap) {
+ event->accept();
+ return;
+ }
+ }
+ }
+ event->ignore();
+ QSGFlickable::keyPressEvent(event);
+}
+
+void QSGListView::geometryChanged(const QRectF &newGeometry,
+ const QRectF &oldGeometry)
+{
+ Q_D(QSGListView);
+ d->maxExtentDirty = true;
+ d->minExtentDirty = true;
+ if (d->isRightToLeft() && d->orient == QSGListView::Horizontal) {
+ // maintain position relative to the right edge
+ int dx = newGeometry.width() - oldGeometry.width();
+ setContentX(contentX() - dx);
+ }
+ QSGFlickable::geometryChanged(newGeometry, oldGeometry);
+}
+
+
+void QSGListView::incrementCurrentIndex()
+{
+ Q_D(QSGListView);
+ int count = d->model ? d->model->count() : 0;
+ if (count && (currentIndex() < count - 1 || d->wrap)) {
+ d->moveReason = QSGListViewPrivate::SetIndex;
+ int index = currentIndex()+1;
+ setCurrentIndex((index >= 0 && index < count) ? index : 0);
+ }
+}
+
+void QSGListView::decrementCurrentIndex()
+{
+ Q_D(QSGListView);
+ int count = d->model ? d->model->count() : 0;
+ if (count && (currentIndex() > 0 || d->wrap)) {
+ d->moveReason = QSGListViewPrivate::SetIndex;
+ int index = currentIndex()-1;
+ setCurrentIndex((index >= 0 && index < count) ? index : count-1);
+ }
+}
+
+void QSGListViewPrivate::positionViewAtIndex(int index, int mode)
+{
+ Q_Q(QSGListView);
+ if (!isValid())
+ return;
+ if (mode < QSGListView::Beginning || mode > QSGListView::Contain)
+ return;
+ int idx = qMax(qMin(index, model->count()-1), 0);
+
+ if (layoutScheduled)
+ layout();
+ qreal pos = isRightToLeft() ? -position() - size() : position();
+ FxListItemSG *item = visibleItem(idx);
+ qreal maxExtent;
+ if (orient == QSGListView::Vertical)
+ maxExtent = -q->maxYExtent();
+ else
+ maxExtent = isRightToLeft() ? q->minXExtent()-size(): -q->maxXExtent();
+ if (!item) {
+ int itemPos = positionAt(idx);
+ // save the currently visible items in case any of them end up visible again
+ QList<FxListItemSG*> oldVisible = visibleItems;
+ visibleItems.clear();
+ visiblePos = itemPos;
+ visibleIndex = idx;
+ setPosition(qMin(qreal(itemPos), maxExtent));
+ // now release the reference to all the old visible items.
+ for (int i = 0; i < oldVisible.count(); ++i)
+ releaseItem(oldVisible.at(i));
+ item = visibleItem(idx);
+ }
+ if (item) {
+ const qreal itemPos = item->position();
+ switch (mode) {
+ case QSGListView::Beginning:
+ pos = itemPos;
+ if (index < 0 && header)
+ pos -= header->size();
+ break;
+ case QSGListView::Center:
+ pos = itemPos - (size() - item->size())/2;
+ break;
+ case QSGListView::End:
+ pos = itemPos - size() + item->size();
+ if (index >= model->count() && footer)
+ pos += footer->size();
+ break;
+ case QSGListView::Visible:
+ if (itemPos > pos + size())
+ pos = itemPos - size() + item->size();
+ else if (item->endPosition() < pos)
+ pos = itemPos;
+ break;
+ case QSGListView::Contain:
+ if (item->endPosition() > pos + size())
+ pos = itemPos - size() + item->size();
+ if (itemPos < pos)
+ pos = itemPos;
+ }
+ pos = qMin(pos, maxExtent);
+ qreal minExtent;
+ if (orient == QSGListView::Vertical) {
+ minExtent = -q->minYExtent();
+ } else {
+ minExtent = isRightToLeft() ? q->maxXExtent()-size(): -q->minXExtent();
+ }
+ pos = qMax(pos, minExtent);
+ moveReason = QSGListViewPrivate::Other;
+ q->cancelFlick();
+ setPosition(pos);
+ if (highlight) {
+ if (autoHighlight) {
+ highlight->setPosition(currentItem->itemPosition());
+ highlight->setSize(currentItem->itemSize());
+ }
+ updateHighlight();
+ }
+ }
+ fixupPosition();
+}
+
+void QSGListView::positionViewAtIndex(int index, int mode)
+{
+ Q_D(QSGListView);
+ if (!d->isValid() || index < 0 || index >= d->model->count())
+ return;
+ d->positionViewAtIndex(index, mode);
+}
+
+void QSGListView::positionViewAtBeginning()
+{
+ Q_D(QSGListView);
+ if (!d->isValid())
+ return;
+ d->positionViewAtIndex(-1, Beginning);
+}
+
+void QSGListView::positionViewAtEnd()
+{
+ Q_D(QSGListView);
+ if (!d->isValid())
+ return;
+ d->positionViewAtIndex(d->model->count(), End);
+}
+
+int QSGListView::indexAt(qreal x, qreal y) const
+{
+ Q_D(const QSGListView);
+ for (int i = 0; i < d->visibleItems.count(); ++i) {
+ const FxListItemSG *listItem = d->visibleItems.at(i);
+ if(listItem->contains(x, y))
+ return listItem->index;
+ }
+
+ return -1;
+}
+
+void QSGListView::componentComplete()
+{
+ Q_D(QSGListView);
+ QSGFlickable::componentComplete();
+ updateSections();
+ d->updateHeader();
+ d->updateFooter();
+ if (d->isValid()) {
+ refill();
+ d->moveReason = QSGListViewPrivate::SetIndex;
+ if (d->currentIndex < 0 && !d->currentIndexCleared)
+ d->updateCurrent(0);
+ else
+ d->updateCurrent(d->currentIndex);
+ if (d->highlight && d->currentItem) {
+ if (d->autoHighlight)
+ d->highlight->setPosition(d->currentItem->position());
+ d->updateTrackedItem();
+ }
+ d->moveReason = QSGListViewPrivate::Other;
+ d->fixupPosition();
+ }
+}
+
+void QSGListView::updateSections()
+{
+ Q_D(QSGListView);
+ if (isComponentComplete() && d->model) {
+ QList<QByteArray> roles;
+ if (d->sectionCriteria && !d->sectionCriteria->property().isEmpty())
+ roles << d->sectionCriteria->property().toUtf8();
+ d->model->setWatchedRoles(roles);
+ d->updateSections();
+ if (d->itemCount)
+ d->layout();
+ }
+}
+
+void QSGListView::refill()
+{
+ Q_D(QSGListView);
+ if (d->isRightToLeft())
+ d->refill(-d->position()-d->size()+1, -d->position());
+ else
+ d->refill(d->position(), d->position()+d->size()-1);
+}
+
+void QSGListView::trackedPositionChanged()
+{
+ Q_D(QSGListView);
+ if (!d->trackedItem || !d->currentItem)
+ return;
+ if (d->moveReason == QSGListViewPrivate::SetIndex) {
+ qreal trackedPos = qCeil(d->trackedItem->position());
+ qreal trackedSize = d->trackedItem->size();
+ if (d->trackedItem != d->currentItem) {
+ trackedPos -= d->currentItem->sectionSize();
+ trackedSize += d->currentItem->sectionSize();
+ }
+ qreal viewPos;
+ qreal highlightStart;
+ qreal highlightEnd;
+ if (d->isRightToLeft()) {
+ viewPos = -d->position()-d->size();
+ highlightStart = d->highlightRangeStartValid ? d->size()-d->highlightRangeEnd : d->highlightRangeStart;
+ highlightEnd = d->highlightRangeEndValid ? d->size()-d->highlightRangeStart : d->highlightRangeEnd;
+ } else {
+ viewPos = d->position();
+ highlightStart = d->highlightRangeStart;
+ highlightEnd = d->highlightRangeEnd;
+ }
+ qreal pos = viewPos;
+ if (d->haveHighlightRange) {
+ if (d->highlightRange == StrictlyEnforceRange) {
+ if (trackedPos > pos + highlightEnd - d->trackedItem->size())
+ pos = trackedPos - highlightEnd + d->trackedItem->size();
+ if (trackedPos < pos + highlightStart)
+ pos = trackedPos - highlightStart;
+ } else {
+ if (trackedPos < d->startPosition() + highlightStart) {
+ pos = d->startPosition();
+ } else if (d->trackedItem->endPosition() > d->endPosition() - d->size() + highlightEnd) {
+ pos = d->endPosition() - d->size() + 1;
+ if (pos < d->startPosition())
+ pos = d->startPosition();
+ } else {
+ if (trackedPos < viewPos + highlightStart) {
+ pos = trackedPos - highlightStart;
+ } else if (trackedPos > viewPos + highlightEnd - trackedSize) {
+ pos = trackedPos - highlightEnd + trackedSize;
+ }
+ }
+ }
+ } else {
+ if (trackedPos < viewPos && d->currentItem->position() < viewPos) {
+ pos = d->currentItem->position() < trackedPos ? trackedPos : d->currentItem->position();
+ } else if (d->trackedItem->endPosition() >= viewPos + d->size()
+ && d->currentItem->endPosition() >= viewPos + d->size()) {
+ if (d->trackedItem->endPosition() <= d->currentItem->endPosition()) {
+ pos = d->trackedItem->endPosition() - d->size() + 1;
+ if (trackedSize > d->size())
+ pos = trackedPos;
+ } else {
+ pos = d->currentItem->endPosition() - d->size() + 1;
+ if (d->currentItem->size() > d->size())
+ pos = d->currentItem->position();
+ }
+ }
+ }
+ if (viewPos != pos) {
+ cancelFlick();
+ d->calcVelocity = true;
+ d->setPosition(pos);
+ d->calcVelocity = false;
+ }
+ }
+}
+
+void QSGListView::itemsInserted(int modelIndex, int count)
+{
+ Q_D(QSGListView);
+ if (!isComponentComplete())
+ return;
+ d->updateUnrequestedIndexes();
+ d->moveReason = QSGListViewPrivate::Other;
+
+ qreal tempPos = d->isRightToLeft() ? -d->position()-d->size() : d->position();
+ int index = d->visibleItems.count() ? d->mapFromModel(modelIndex) : 0;
+ if (index < 0) {
+ int i = d->visibleItems.count() - 1;
+ while (i > 0 && d->visibleItems.at(i)->index == -1)
+ --i;
+ if (i == 0 && d->visibleItems.first()->index == -1) {
+ // there are no visible items except items marked for removal
+ index = d->visibleItems.count();
+ } else if (d->visibleItems.at(i)->index + 1 == modelIndex
+ && d->visibleItems.at(i)->endPosition() < d->buffer+tempPos+d->size()-1) {
+ // Special case of appending an item to the model.
+ index = d->visibleItems.count();
+ } else {
+ if (modelIndex < d->visibleIndex) {
+ // Insert before visible items
+ d->visibleIndex += count;
+ for (int i = 0; i < d->visibleItems.count(); ++i) {
+ FxListItemSG *listItem = d->visibleItems.at(i);
+ if (listItem->index != -1 && listItem->index >= modelIndex)
+ listItem->index += count;
+ }
+ }
+ if (d->currentIndex >= modelIndex) {
+ // adjust current item index
+ d->currentIndex += count;
+ if (d->currentItem)
+ d->currentItem->index = d->currentIndex;
+ emit currentIndexChanged();
+ }
+ d->scheduleLayout();
+ d->itemCount += count;
+ emit countChanged();
+ return;
+ }
+ }
+
+ // index can be the next item past the end of the visible items list (i.e. appended)
+ int pos = 0;
+ if (d->visibleItems.count()) {
+ pos = index < d->visibleItems.count() ? d->visibleItems.at(index)->position()
+ : d->visibleItems.last()->endPosition()+d->spacing+1;
+ } else if (d->itemCount == 0 && d->header) {
+ pos = d->header->size();
+ }
+
+ int initialPos = pos;
+ int diff = 0;
+ QList<FxListItemSG*> added;
+ bool addedVisible = false;
+ FxListItemSG *firstVisible = d->firstVisibleItem();
+ if (firstVisible && pos < firstVisible->position()) {
+ // Insert items before the visible item.
+ int insertionIdx = index;
+ int i = 0;
+ int from = tempPos - d->buffer;
+ for (i = count-1; i >= 0 && pos > from; --i) {
+ if (!addedVisible) {
+ d->scheduleLayout();
+ addedVisible = true;
+ }
+ FxListItemSG *item = d->createItem(modelIndex + i);
+ d->visibleItems.insert(insertionIdx, item);
+ pos -= item->size() + d->spacing;
+ item->setPosition(pos);
+ index++;
+ }
+ if (i >= 0) {
+ // If we didn't insert all our new items - anything
+ // before the current index is not visible - remove it.
+ while (insertionIdx--) {
+ FxListItemSG *item = d->visibleItems.takeFirst();
+ if (item->index != -1)
+ d->visibleIndex++;
+ d->releaseItem(item);
+ }
+ } else {
+ // adjust pos of items before inserted items.
+ for (int i = insertionIdx-1; i >= 0; i--) {
+ FxListItemSG *listItem = d->visibleItems.at(i);
+ listItem->setPosition(listItem->position() - (initialPos - pos));
+ }
+ }
+ } else {
+ int i = 0;
+ int to = d->buffer+tempPos+d->size()-1;
+ for (i = 0; i < count && pos <= to; ++i) {
+ if (!addedVisible) {
+ d->scheduleLayout();
+ addedVisible = true;
+ }
+ FxListItemSG *item = d->createItem(modelIndex + i);
+ d->visibleItems.insert(index, item);
+ item->setPosition(pos);
+ added.append(item);
+ pos += item->size() + d->spacing;
+ ++index;
+ }
+ if (i != count) {
+ // We didn't insert all our new items, which means anything
+ // beyond the current index is not visible - remove it.
+ while (d->visibleItems.count() > index)
+ d->releaseItem(d->visibleItems.takeLast());
+ }
+ diff = pos - initialPos;
+ }
+ if (d->itemCount && d->currentIndex >= modelIndex) {
+ // adjust current item index
+ d->currentIndex += count;
+ if (d->currentItem) {
+ d->currentItem->index = d->currentIndex;
+ d->currentItem->setPosition(d->currentItem->position() + diff);
+ }
+ emit currentIndexChanged();
+ } else if (!d->itemCount && (!d->currentIndex || (d->currentIndex < 0 && !d->currentIndexCleared))) {
+ d->updateCurrent(0);
+ }
+ // Update the indexes of the following visible items.
+ for (; index < d->visibleItems.count(); ++index) {
+ FxListItemSG *listItem = d->visibleItems.at(index);
+ if (d->currentItem && listItem->item != d->currentItem->item)
+ listItem->setPosition(listItem->position() + diff);
+ if (listItem->index != -1)
+ listItem->index += count;
+ }
+ // everything is in order now - emit add() signal
+ for (int j = 0; j < added.count(); ++j)
+ added.at(j)->attached->emitAdd();
+
+ d->updateSections();
+ d->itemCount += count;
+ emit countChanged();
+}
+
+void QSGListView::itemsRemoved(int modelIndex, int count)
+{
+ Q_D(QSGListView);
+ if (!isComponentComplete())
+ return;
+ d->moveReason = QSGListViewPrivate::Other;
+ d->updateUnrequestedIndexes();
+ d->itemCount -= count;
+
+ FxListItemSG *firstVisible = d->firstVisibleItem();
+ int preRemovedSize = 0;
+ bool removedVisible = false;
+ // Remove the items from the visible list, skipping anything already marked for removal
+ QList<FxListItemSG*>::Iterator it = d->visibleItems.begin();
+ while (it != d->visibleItems.end()) {
+ FxListItemSG *item = *it;
+ if (item->index == -1 || item->index < modelIndex) {
+ // already removed, or before removed items
+ ++it;
+ } else if (item->index >= modelIndex + count) {
+ // after removed items
+ item->index -= count;
+ ++it;
+ } else {
+ // removed item
+ if (!removedVisible) {
+ d->scheduleLayout();
+ removedVisible = true;
+ }
+ item->attached->emitRemove();
+ if (item->attached->delayRemove()) {
+ item->index = -1;
+ connect(item->attached, SIGNAL(delayRemoveChanged()), this, SLOT(destroyRemoved()), Qt::QueuedConnection);
+ ++it;
+ } else {
+ if (item == firstVisible)
+ firstVisible = 0;
+ if (firstVisible && item->position() < firstVisible->position())
+ preRemovedSize += item->size();
+ it = d->visibleItems.erase(it);
+ d->releaseItem(item);
+ }
+ }
+ }
+
+ if (firstVisible && d->visibleItems.first() != firstVisible)
+ d->visibleItems.first()->setPosition(d->visibleItems.first()->position() + preRemovedSize);
+
+ // fix current
+ if (d->currentIndex >= modelIndex + count) {
+ d->currentIndex -= count;
+ if (d->currentItem)
+ d->currentItem->index -= count;
+ emit currentIndexChanged();
+ } else if (d->currentIndex >= modelIndex && d->currentIndex < modelIndex + count) {
+ // current item has been removed.
+ if (d->currentItem) {
+ d->currentItem->attached->setIsCurrentItem(false);
+ d->releaseItem(d->currentItem);
+ d->currentItem = 0;
+ }
+ d->currentIndex = -1;
+ if (d->itemCount)
+ d->updateCurrent(qMin(modelIndex, d->itemCount-1));
+ else
+ emit currentIndexChanged();
+ }
+
+ // update visibleIndex
+ bool haveVisibleIndex = false;
+ for (it = d->visibleItems.begin(); it != d->visibleItems.end(); ++it) {
+ if ((*it)->index != -1) {
+ d->visibleIndex = (*it)->index;
+ haveVisibleIndex = true;
+ break;
+ }
+ }
+
+ if (!haveVisibleIndex) {
+ d->timeline.clear();
+ if (removedVisible && d->itemCount == 0) {
+ d->visibleIndex = 0;
+ d->visiblePos = d->header ? d->header->size() : 0;
+ d->setPosition(0);
+ d->updateHeader();
+ d->updateFooter();
+ } else {
+ if (modelIndex < d->visibleIndex)
+ d->visibleIndex = modelIndex+1;
+ d->visibleIndex = qMax(qMin(d->visibleIndex, d->itemCount-1), 0);
+ }
+ }
+
+ d->updateSections();
+ emit countChanged();
+}
+
+void QSGListView::destroyRemoved()
+{
+ Q_D(QSGListView);
+ for (QList<FxListItemSG*>::Iterator it = d->visibleItems.begin();
+ it != d->visibleItems.end();) {
+ FxListItemSG *listItem = *it;
+ if (listItem->index == -1 && listItem->attached->delayRemove() == false) {
+ d->releaseItem(listItem);
+ it = d->visibleItems.erase(it);
+ } else {
+ ++it;
+ }
+ }
+
+ // Correct the positioning of the items
+ d->updateSections();
+ d->layout();
+}
+
+void QSGListView::itemsMoved(int from, int to, int count)
+{
+ Q_D(QSGListView);
+ if (!isComponentComplete())
+ return;
+ d->updateUnrequestedIndexes();
+
+ if (d->visibleItems.isEmpty()) {
+ refill();
+ return;
+ }
+
+ d->moveReason = QSGListViewPrivate::Other;
+ FxListItemSG *firstVisible = d->firstVisibleItem();
+ qreal firstItemPos = firstVisible->position();
+ QHash<int,FxListItemSG*> moved;
+ int moveBy = 0;
+
+ QList<FxListItemSG*>::Iterator it = d->visibleItems.begin();
+ while (it != d->visibleItems.end()) {
+ FxListItemSG *item = *it;
+ if (item->index >= from && item->index < from + count) {
+ // take the items that are moving
+ item->index += (to-from);
+ moved.insert(item->index, item);
+ if (item->position() < firstItemPos)
+ moveBy += item->size();
+ it = d->visibleItems.erase(it);
+ } else {
+ // move everything after the moved items.
+ if (item->index > from && item->index != -1)
+ item->index -= count;
+ ++it;
+ }
+ }
+
+ int remaining = count;
+ int endIndex = d->visibleIndex;
+ it = d->visibleItems.begin();
+ while (it != d->visibleItems.end()) {
+ FxListItemSG *item = *it;
+ if (remaining && item->index >= to && item->index < to + count) {
+ // place items in the target position, reusing any existing items
+ FxListItemSG *movedItem = moved.take(item->index);
+ if (!movedItem)
+ movedItem = d->createItem(item->index);
+ if (item->index <= firstVisible->index)
+ moveBy -= movedItem->size();
+ it = d->visibleItems.insert(it, movedItem);
+ ++it;
+ --remaining;
+ } else {
+ if (item->index != -1) {
+ if (item->index >= to) {
+ // update everything after the moved items.
+ item->index += count;
+ }
+ endIndex = item->index;
+ }
+ ++it;
+ }
+ }
+
+ // If we have moved items to the end of the visible items
+ // then add any existing moved items that we have
+ while (FxListItemSG *item = moved.take(endIndex+1)) {
+ d->visibleItems.append(item);
+ ++endIndex;
+ }
+
+ // update visibleIndex
+ for (it = d->visibleItems.begin(); it != d->visibleItems.end(); ++it) {
+ if ((*it)->index != -1) {
+ d->visibleIndex = (*it)->index;
+ break;
+ }
+ }
+
+ // Fix current index
+ if (d->currentIndex >= 0 && d->currentItem) {
+ int oldCurrent = d->currentIndex;
+ d->currentIndex = d->model->indexOf(d->currentItem->item, this);
+ if (oldCurrent != d->currentIndex) {
+ d->currentItem->index = d->currentIndex;
+ emit currentIndexChanged();
+ }
+ }
+
+ // Whatever moved items remain are no longer visible items.
+ while (moved.count()) {
+ int idx = moved.begin().key();
+ FxListItemSG *item = moved.take(idx);
+ if (d->currentItem && item->item == d->currentItem->item)
+ item->setPosition(d->positionAt(idx));
+ d->releaseItem(item);
+ }
+
+ // Ensure we don't cause an ugly list scroll.
+ d->visibleItems.first()->setPosition(d->visibleItems.first()->position() + moveBy);
+
+ d->updateSections();
+ d->layout();
+}
+
+void QSGListView::itemsChanged(int, int)
+{
+ Q_D(QSGListView);
+ d->updateSections();
+ d->layout();
+}
+
+void QSGListView::modelReset()
+{
+ Q_D(QSGListView);
+ d->moveReason = QSGListViewPrivate::SetIndex;
+ d->regenerate();
+ if (d->highlight && d->currentItem) {
+ if (d->autoHighlight)
+ d->highlight->setPosition(d->currentItem->position());
+ d->updateTrackedItem();
+ }
+ d->moveReason = QSGListViewPrivate::Other;
+ emit countChanged();
+}
+
+void QSGListView::createdItem(int index, QSGItem *item)
+{
+ Q_D(QSGListView);
+ if (d->requestedIndex != index) {
+ item->setParentItem(contentItem());
+ d->unrequestedItems.insert(item, index);
+ if (d->orient == QSGListView::Vertical) {
+ item->setY(d->positionAt(index));
+ } else {
+ if (d->isRightToLeft())
+ item->setX(-d->positionAt(index)-item->width());
+ else
+ item->setX(d->positionAt(index));
+ }
+ }
+}
+
+void QSGListView::destroyingItem(QSGItem *item)
+{
+ Q_D(QSGListView);
+ d->unrequestedItems.remove(item);
+}
+
+void QSGListView::animStopped()
+{
+ Q_D(QSGListView);
+ d->bufferMode = QSGListViewPrivate::NoBuffer;
+ if (d->haveHighlightRange && d->highlightRange == QSGListView::StrictlyEnforceRange)
+ d->updateHighlight();
+}
+
+QSGListViewAttached *QSGListView::qmlAttachedProperties(QObject *obj)
+{
+ return new QSGListViewAttached(obj);
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/items/qsglistview_p.h b/src/declarative/items/qsglistview_p.h
new file mode 100644
index 0000000000..2e3df2020f
--- /dev/null
+++ b/src/declarative/items/qsglistview_p.h
@@ -0,0 +1,374 @@
+// Commit: 95814418f9d6adeba365c795462e8afb00138211
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGLISTVIEW_P_H
+#define QSGLISTVIEW_P_H
+
+#include "qsgflickable_p.h"
+
+#include <private/qdeclarativeguard_p.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class Q_AUTOTEST_EXPORT QSGViewSection : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QString property READ property WRITE setProperty NOTIFY propertyChanged)
+ Q_PROPERTY(SectionCriteria criteria READ criteria WRITE setCriteria NOTIFY criteriaChanged)
+ Q_PROPERTY(QDeclarativeComponent *delegate READ delegate WRITE setDelegate NOTIFY delegateChanged)
+ Q_ENUMS(SectionCriteria)
+public:
+ QSGViewSection(QObject *parent=0) : QObject(parent), m_criteria(FullString), m_delegate(0) {}
+
+ QString property() const { return m_property; }
+ void setProperty(const QString &);
+
+ enum SectionCriteria { FullString, FirstCharacter };
+ SectionCriteria criteria() const { return m_criteria; }
+ void setCriteria(SectionCriteria);
+
+ QDeclarativeComponent *delegate() const { return m_delegate; }
+ void setDelegate(QDeclarativeComponent *delegate);
+
+ QString sectionString(const QString &value);
+
+Q_SIGNALS:
+ void propertyChanged();
+ void criteriaChanged();
+ void delegateChanged();
+
+private:
+ QString m_property;
+ SectionCriteria m_criteria;
+ QDeclarativeComponent *m_delegate;
+};
+
+
+class QSGVisualModel;
+class QSGListViewAttached;
+class QSGListViewPrivate;
+class Q_AUTOTEST_EXPORT QSGListView : public QSGFlickable
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QSGListView)
+
+ Q_PROPERTY(QVariant model READ model WRITE setModel NOTIFY modelChanged)
+ Q_PROPERTY(QDeclarativeComponent *delegate READ delegate WRITE setDelegate NOTIFY delegateChanged)
+ Q_PROPERTY(int currentIndex READ currentIndex WRITE setCurrentIndex NOTIFY currentIndexChanged)
+ Q_PROPERTY(QSGItem *currentItem READ currentItem NOTIFY currentIndexChanged)
+ Q_PROPERTY(int count READ count NOTIFY countChanged)
+
+ Q_PROPERTY(QDeclarativeComponent *highlight READ highlight WRITE setHighlight NOTIFY highlightChanged)
+ Q_PROPERTY(QSGItem *highlightItem READ highlightItem NOTIFY highlightItemChanged)
+ Q_PROPERTY(bool highlightFollowsCurrentItem READ highlightFollowsCurrentItem WRITE setHighlightFollowsCurrentItem NOTIFY highlightFollowsCurrentItemChanged)
+ Q_PROPERTY(qreal highlightMoveSpeed READ highlightMoveSpeed WRITE setHighlightMoveSpeed NOTIFY highlightMoveSpeedChanged)
+ Q_PROPERTY(int highlightMoveDuration READ highlightMoveDuration WRITE setHighlightMoveDuration NOTIFY highlightMoveDurationChanged)
+ Q_PROPERTY(qreal highlightResizeSpeed READ highlightResizeSpeed WRITE setHighlightResizeSpeed NOTIFY highlightResizeSpeedChanged)
+ Q_PROPERTY(int highlightResizeDuration READ highlightResizeDuration WRITE setHighlightResizeDuration NOTIFY highlightResizeDurationChanged)
+
+ Q_PROPERTY(qreal preferredHighlightBegin READ preferredHighlightBegin WRITE setPreferredHighlightBegin NOTIFY preferredHighlightBeginChanged RESET resetPreferredHighlightBegin)
+ Q_PROPERTY(qreal preferredHighlightEnd READ preferredHighlightEnd WRITE setPreferredHighlightEnd NOTIFY preferredHighlightEndChanged RESET resetPreferredHighlightEnd)
+ Q_PROPERTY(HighlightRangeMode highlightRangeMode READ highlightRangeMode WRITE setHighlightRangeMode NOTIFY highlightRangeModeChanged)
+
+ Q_PROPERTY(qreal spacing READ spacing WRITE setSpacing NOTIFY spacingChanged)
+ Q_PROPERTY(Orientation orientation READ orientation WRITE setOrientation NOTIFY orientationChanged)
+ Q_PROPERTY(Qt::LayoutDirection layoutDirection READ layoutDirection WRITE setLayoutDirection NOTIFY layoutDirectionChanged)
+ Q_PROPERTY(Qt::LayoutDirection effectiveLayoutDirection READ effectiveLayoutDirection NOTIFY effectiveLayoutDirectionChanged)
+ Q_PROPERTY(bool keyNavigationWraps READ isWrapEnabled WRITE setWrapEnabled NOTIFY keyNavigationWrapsChanged)
+ Q_PROPERTY(int cacheBuffer READ cacheBuffer WRITE setCacheBuffer NOTIFY cacheBufferChanged)
+ Q_PROPERTY(QSGViewSection *section READ sectionCriteria CONSTANT)
+ Q_PROPERTY(QString currentSection READ currentSection NOTIFY currentSectionChanged)
+
+ Q_PROPERTY(SnapMode snapMode READ snapMode WRITE setSnapMode NOTIFY snapModeChanged)
+
+ Q_PROPERTY(QDeclarativeComponent *header READ header WRITE setHeader NOTIFY headerChanged)
+ Q_PROPERTY(QDeclarativeComponent *footer READ footer WRITE setFooter NOTIFY footerChanged)
+
+ Q_ENUMS(HighlightRangeMode)
+ Q_ENUMS(Orientation)
+ Q_ENUMS(SnapMode)
+ Q_ENUMS(PositionMode)
+ Q_CLASSINFO("DefaultProperty", "data")
+
+public:
+ QSGListView(QSGItem *parent=0);
+ ~QSGListView();
+
+ QVariant model() const;
+ void setModel(const QVariant &);
+
+ QDeclarativeComponent *delegate() const;
+ void setDelegate(QDeclarativeComponent *);
+
+ int currentIndex() const;
+ void setCurrentIndex(int idx);
+
+ QSGItem *currentItem();
+ QSGItem *highlightItem();
+ int count() const;
+
+ QDeclarativeComponent *highlight() const;
+ void setHighlight(QDeclarativeComponent *highlight);
+
+ bool highlightFollowsCurrentItem() const;
+ void setHighlightFollowsCurrentItem(bool);
+
+ enum HighlightRangeMode { NoHighlightRange, ApplyRange, StrictlyEnforceRange };
+ HighlightRangeMode highlightRangeMode() const;
+ void setHighlightRangeMode(HighlightRangeMode mode);
+
+ qreal preferredHighlightBegin() const;
+ void setPreferredHighlightBegin(qreal);
+ void resetPreferredHighlightBegin();
+
+ qreal preferredHighlightEnd() const;
+ void setPreferredHighlightEnd(qreal);
+ void resetPreferredHighlightEnd();
+
+ qreal spacing() const;
+ void setSpacing(qreal spacing);
+
+ enum Orientation { Horizontal = Qt::Horizontal, Vertical = Qt::Vertical };
+ Orientation orientation() const;
+ void setOrientation(Orientation);
+
+ Qt::LayoutDirection layoutDirection() const;
+ void setLayoutDirection(Qt::LayoutDirection);
+ Qt::LayoutDirection effectiveLayoutDirection() const;
+
+ bool isWrapEnabled() const;
+ void setWrapEnabled(bool);
+
+ int cacheBuffer() const;
+ void setCacheBuffer(int);
+
+ QSGViewSection *sectionCriteria();
+ QString currentSection() const;
+
+ qreal highlightMoveSpeed() const;
+ void setHighlightMoveSpeed(qreal);
+
+ int highlightMoveDuration() const;
+ void setHighlightMoveDuration(int);
+
+ qreal highlightResizeSpeed() const;
+ void setHighlightResizeSpeed(qreal);
+
+ int highlightResizeDuration() const;
+ void setHighlightResizeDuration(int);
+
+ enum SnapMode { NoSnap, SnapToItem, SnapOneItem };
+ SnapMode snapMode() const;
+ void setSnapMode(SnapMode mode);
+
+ QDeclarativeComponent *footer() const;
+ void setFooter(QDeclarativeComponent *);
+
+ QDeclarativeComponent *header() const;
+ void setHeader(QDeclarativeComponent *);
+
+ virtual void setContentX(qreal pos);
+ virtual void setContentY(qreal pos);
+
+ static QSGListViewAttached *qmlAttachedProperties(QObject *);
+
+ enum PositionMode { Beginning, Center, End, Visible, Contain };
+
+ Q_INVOKABLE void positionViewAtIndex(int index, int mode);
+ Q_INVOKABLE int indexAt(qreal x, qreal y) const;
+ Q_INVOKABLE void positionViewAtBeginning();
+ Q_INVOKABLE void positionViewAtEnd();
+
+public Q_SLOTS:
+ void incrementCurrentIndex();
+ void decrementCurrentIndex();
+
+Q_SIGNALS:
+ void countChanged();
+ void spacingChanged();
+ void orientationChanged();
+ void layoutDirectionChanged();
+ void effectiveLayoutDirectionChanged();
+ void currentIndexChanged();
+ void currentSectionChanged();
+ void highlightMoveSpeedChanged();
+ void highlightMoveDurationChanged();
+ void highlightResizeSpeedChanged();
+ void highlightResizeDurationChanged();
+ void highlightChanged();
+ void highlightItemChanged();
+ void modelChanged();
+ void delegateChanged();
+ void highlightFollowsCurrentItemChanged();
+ void preferredHighlightBeginChanged();
+ void preferredHighlightEndChanged();
+ void highlightRangeModeChanged();
+ void keyNavigationWrapsChanged();
+ void cacheBufferChanged();
+ void snapModeChanged();
+ void headerChanged();
+ void footerChanged();
+
+protected:
+ virtual void updatePolish();
+ virtual void viewportMoved();
+ virtual qreal minYExtent() const;
+ virtual qreal maxYExtent() const;
+ virtual qreal minXExtent() const;
+ virtual qreal maxXExtent() const;
+ virtual void keyPressEvent(QKeyEvent *);
+ virtual void geometryChanged(const QRectF &newGeometry,const QRectF &oldGeometry);
+ virtual void componentComplete();
+
+private Q_SLOTS:
+ void updateSections();
+ void refill();
+ void trackedPositionChanged();
+ 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);
+ void modelReset();
+ void destroyRemoved();
+ void createdItem(int index, QSGItem *item);
+ void destroyingItem(QSGItem *item);
+ void animStopped();
+};
+
+class QSGListViewAttached : public QObject
+{
+ Q_OBJECT
+public:
+ QSGListViewAttached(QObject *parent)
+ : QObject(parent), m_view(0), m_isCurrent(false), m_delayRemove(false) {}
+ ~QSGListViewAttached() {}
+
+ Q_PROPERTY(QSGListView *view READ view NOTIFY viewChanged)
+ QSGListView *view() { return m_view; }
+ void setView(QSGListView *view) {
+ if (view != m_view) {
+ m_view = view;
+ emit viewChanged();
+ }
+ }
+
+ Q_PROPERTY(bool isCurrentItem READ isCurrentItem NOTIFY currentItemChanged)
+ bool isCurrentItem() const { return m_isCurrent; }
+ void setIsCurrentItem(bool c) {
+ if (m_isCurrent != c) {
+ m_isCurrent = c;
+ emit currentItemChanged();
+ }
+ }
+
+ Q_PROPERTY(QString previousSection READ prevSection NOTIFY prevSectionChanged)
+ QString prevSection() const { return m_prevSection; }
+ void setPrevSection(const QString &sect) {
+ if (m_prevSection != sect) {
+ m_prevSection = sect;
+ emit prevSectionChanged();
+ }
+ }
+
+ Q_PROPERTY(QString nextSection READ nextSection NOTIFY nextSectionChanged)
+ QString nextSection() const { return m_nextSection; }
+ void setNextSection(const QString &sect) {
+ if (m_nextSection != sect) {
+ m_nextSection = sect;
+ emit nextSectionChanged();
+ }
+ }
+
+ Q_PROPERTY(QString section READ section NOTIFY sectionChanged)
+ QString section() const { return m_section; }
+ void setSection(const QString &sect) {
+ if (m_section != sect) {
+ m_section = sect;
+ emit sectionChanged();
+ }
+ }
+
+ Q_PROPERTY(bool delayRemove READ delayRemove WRITE setDelayRemove NOTIFY delayRemoveChanged)
+ bool delayRemove() const { return m_delayRemove; }
+ void setDelayRemove(bool delay) {
+ if (m_delayRemove != delay) {
+ m_delayRemove = delay;
+ emit delayRemoveChanged();
+ }
+ }
+
+ void emitAdd() { emit add(); }
+ void emitRemove() { emit remove(); }
+
+Q_SIGNALS:
+ void currentItemChanged();
+ void sectionChanged();
+ void prevSectionChanged();
+ void nextSectionChanged();
+ void delayRemoveChanged();
+ void add();
+ void remove();
+ void viewChanged();
+
+public:
+ QDeclarativeGuard<QSGListView> m_view;
+ mutable QString m_section;
+ QString m_prevSection;
+ QString m_nextSection;
+ bool m_isCurrent : 1;
+ bool m_delayRemove : 1;
+};
+
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPEINFO(QSGListView, QML_HAS_ATTACHED_PROPERTIES)
+QML_DECLARE_TYPE(QSGListView)
+QML_DECLARE_TYPE(QSGViewSection)
+
+QT_END_HEADER
+
+#endif // QSGLISTVIEW_P_H
diff --git a/src/declarative/items/qsgloader.cpp b/src/declarative/items/qsgloader.cpp
new file mode 100644
index 0000000000..6717098506
--- /dev/null
+++ b/src/declarative/items/qsgloader.cpp
@@ -0,0 +1,340 @@
+// Commit: 501180c6fbed0857126da2bb0ff1f17ee35472c6
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgloader_p_p.h"
+
+#include <QtDeclarative/qdeclarativeinfo.h>
+
+#include <private/qdeclarativeengine_p.h>
+#include <private/qdeclarativeglobal_p.h>
+
+QT_BEGIN_NAMESPACE
+
+QSGLoaderPrivate::QSGLoaderPrivate()
+ : item(0), component(0), ownComponent(false), updatingSize(false),
+ itemWidthValid(false), itemHeightValid(false)
+{
+}
+
+QSGLoaderPrivate::~QSGLoaderPrivate()
+{
+}
+
+void QSGLoaderPrivate::itemGeometryChanged(QSGItem *resizeItem, const QRectF &newGeometry, const QRectF &oldGeometry)
+{
+ if (resizeItem == item) {
+ if (!updatingSize && newGeometry.width() != oldGeometry.width())
+ itemWidthValid = true;
+ if (!updatingSize && newGeometry.height() != oldGeometry.height())
+ itemHeightValid = true;
+ _q_updateSize(false);
+ }
+ QSGItemChangeListener::itemGeometryChanged(resizeItem, newGeometry, oldGeometry);
+}
+
+void QSGLoaderPrivate::clear()
+{
+ if (ownComponent) {
+ component->deleteLater();
+ component = 0;
+ ownComponent = false;
+ }
+ source = QUrl();
+
+ if (item) {
+ QSGItemPrivate *p = QSGItemPrivate::get(item);
+ p->removeItemChangeListener(this, QSGItemPrivate::Geometry);
+
+ // We can't delete immediately because our item may have triggered
+ // the Loader to load a different item.
+ item->setParentItem(0);
+ item->setVisible(false);
+ item->deleteLater();
+ item = 0;
+ }
+}
+
+void QSGLoaderPrivate::initResize()
+{
+ QSGItemPrivate *p = QSGItemPrivate::get(item);
+ p->addItemChangeListener(this, QSGItemPrivate::Geometry);
+ // We may override the item's size, so we need to remember
+ // whether the item provided its own valid size.
+ itemWidthValid = p->widthValid;
+ itemHeightValid = p->heightValid;
+ _q_updateSize();
+}
+
+QSGLoader::QSGLoader(QSGItem *parent)
+ : QSGImplicitSizeItem(*(new QSGLoaderPrivate), parent)
+{
+ setFlag(ItemIsFocusScope);
+}
+
+QSGLoader::~QSGLoader()
+{
+ Q_D(QSGLoader);
+ if (d->item) {
+ QSGItemPrivate *p = QSGItemPrivate::get(d->item);
+ p->removeItemChangeListener(d, QSGItemPrivate::Geometry);
+ }
+}
+
+QUrl QSGLoader::source() const
+{
+ Q_D(const QSGLoader);
+ return d->source;
+}
+
+void QSGLoader::setSource(const QUrl &url)
+{
+ Q_D(QSGLoader);
+ if (d->source == url)
+ return;
+
+ d->clear();
+
+ d->source = url;
+ if (d->source.isEmpty()) {
+ emit sourceChanged();
+ emit statusChanged();
+ emit progressChanged();
+ emit itemChanged();
+ return;
+ }
+
+ d->component = new QDeclarativeComponent(qmlEngine(this), d->source, this);
+ d->ownComponent = true;
+
+ if (isComponentComplete())
+ d->load();
+}
+
+QDeclarativeComponent *QSGLoader::sourceComponent() const
+{
+ Q_D(const QSGLoader);
+ return d->component;
+}
+
+void QSGLoader::setSourceComponent(QDeclarativeComponent *comp)
+{
+ Q_D(QSGLoader);
+ if (comp == d->component)
+ return;
+
+ d->clear();
+
+ d->component = comp;
+ d->ownComponent = false;
+ if (!d->component) {
+ emit sourceChanged();
+ emit statusChanged();
+ emit progressChanged();
+ emit itemChanged();
+ return;
+ }
+
+ if (isComponentComplete())
+ d->load();
+}
+
+void QSGLoader::resetSourceComponent()
+{
+ setSourceComponent(0);
+}
+
+void QSGLoaderPrivate::load()
+{
+ Q_Q(QSGLoader);
+
+ if (!q->isComponentComplete() || !component)
+ return;
+
+ if (!component->isLoading()) {
+ _q_sourceLoaded();
+ } else {
+ QObject::connect(component, SIGNAL(statusChanged(QDeclarativeComponent::Status)),
+ q, SLOT(_q_sourceLoaded()));
+ QObject::connect(component, SIGNAL(progressChanged(qreal)),
+ q, SIGNAL(progressChanged()));
+ emit q->statusChanged();
+ emit q->progressChanged();
+ emit q->sourceChanged();
+ emit q->itemChanged();
+ }
+}
+
+void QSGLoaderPrivate::_q_sourceLoaded()
+{
+ Q_Q(QSGLoader);
+
+ if (component) {
+ if (!component->errors().isEmpty()) {
+ QDeclarativeEnginePrivate::warning(qmlEngine(q), component->errors());
+ emit q->sourceChanged();
+ emit q->statusChanged();
+ emit q->progressChanged();
+ return;
+ }
+
+ QDeclarativeContext *creationContext = component->creationContext();
+ if (!creationContext) creationContext = qmlContext(q);
+ QDeclarativeContext *ctxt = new QDeclarativeContext(creationContext);
+ ctxt->setContextObject(q);
+
+ QDeclarativeGuard<QDeclarativeComponent> c = component;
+ QObject *obj = component->beginCreate(ctxt);
+ if (component != c) {
+ // component->create could trigger a change in source that causes
+ // component to be set to something else. In that case we just
+ // need to cleanup.
+ if (c)
+ c->completeCreate();
+ delete obj;
+ delete ctxt;
+ return;
+ }
+ if (obj) {
+ item = qobject_cast<QSGItem *>(obj);
+ if (item) {
+ QDeclarative_setParent_noEvent(ctxt, obj);
+ QDeclarative_setParent_noEvent(item, q);
+ item->setParentItem(q);
+// item->setFocus(true);
+ initResize();
+ } else {
+ qmlInfo(q) << QSGLoader::tr("Loader does not support loading non-visual elements.");
+ delete obj;
+ delete ctxt;
+ }
+ } else {
+ if (!component->errors().isEmpty())
+ QDeclarativeEnginePrivate::warning(qmlEngine(q), component->errors());
+ delete obj;
+ delete ctxt;
+ source = QUrl();
+ }
+ component->completeCreate();
+ emit q->sourceChanged();
+ emit q->statusChanged();
+ emit q->progressChanged();
+ emit q->itemChanged();
+ emit q->loaded();
+ }
+}
+
+QSGLoader::Status QSGLoader::status() const
+{
+ Q_D(const QSGLoader);
+
+ if (d->component)
+ return static_cast<QSGLoader::Status>(d->component->status());
+
+ if (d->item)
+ return Ready;
+
+ return d->source.isEmpty() ? Null : Error;
+}
+
+void QSGLoader::componentComplete()
+{
+ Q_D(QSGLoader);
+ QSGItem::componentComplete();
+ d->load();
+}
+
+qreal QSGLoader::progress() const
+{
+ Q_D(const QSGLoader);
+
+ if (d->item)
+ return 1.0;
+
+ if (d->component)
+ return d->component->progress();
+
+ return 0.0;
+}
+
+void QSGLoaderPrivate::_q_updateSize(bool loaderGeometryChanged)
+{
+ Q_Q(QSGLoader);
+ if (!item || updatingSize)
+ return;
+
+ updatingSize = true;
+
+ if (!itemWidthValid)
+ q->setImplicitWidth(item->implicitWidth());
+ else
+ q->setImplicitWidth(item->width());
+ if (loaderGeometryChanged && q->widthValid())
+ item->setWidth(q->width());
+
+ if (!itemHeightValid)
+ q->setImplicitHeight(item->implicitHeight());
+ else
+ q->setImplicitHeight(item->height());
+ if (loaderGeometryChanged && q->heightValid())
+ item->setHeight(q->height());
+
+ updatingSize = false;
+}
+
+QSGItem *QSGLoader::item() const
+{
+ Q_D(const QSGLoader);
+ return d->item;
+}
+
+void QSGLoader::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
+{
+ Q_D(QSGLoader);
+ if (newGeometry != oldGeometry) {
+ d->_q_updateSize();
+ }
+ QSGItem::geometryChanged(newGeometry, oldGeometry);
+}
+
+#include <moc_qsgloader_p.cpp>
+
+QT_END_NAMESPACE
diff --git a/src/declarative/items/qsgloader_p.h b/src/declarative/items/qsgloader_p.h
new file mode 100644
index 0000000000..689971792c
--- /dev/null
+++ b/src/declarative/items/qsgloader_p.h
@@ -0,0 +1,107 @@
+// Commit: 6f78a6080b84cc3ef96b73a4ff58d1b5a72f08f4
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGLOADER_P_H
+#define QSGLOADER_P_H
+
+#include "qsgimplicitsizeitem_p.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QSGLoaderPrivate;
+class Q_AUTOTEST_EXPORT QSGLoader : public QSGImplicitSizeItem
+{
+ Q_OBJECT
+ Q_ENUMS(Status)
+
+ Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged)
+ Q_PROPERTY(QDeclarativeComponent *sourceComponent READ sourceComponent WRITE setSourceComponent RESET resetSourceComponent NOTIFY sourceChanged)
+ Q_PROPERTY(QSGItem *item READ item NOTIFY itemChanged)
+ Q_PROPERTY(Status status READ status NOTIFY statusChanged)
+ Q_PROPERTY(qreal progress READ progress NOTIFY progressChanged)
+
+public:
+ QSGLoader(QSGItem *parent=0);
+ virtual ~QSGLoader();
+
+ QUrl source() const;
+ void setSource(const QUrl &);
+
+ QDeclarativeComponent *sourceComponent() const;
+ void setSourceComponent(QDeclarativeComponent *);
+ void resetSourceComponent();
+
+ enum Status { Null, Ready, Loading, Error };
+ Status status() const;
+ qreal progress() const;
+
+ QSGItem *item() const;
+
+Q_SIGNALS:
+ void itemChanged();
+ void sourceChanged();
+ void statusChanged();
+ void progressChanged();
+ void loaded();
+
+protected:
+ void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry);
+ void componentComplete();
+
+private:
+ Q_DISABLE_COPY(QSGLoader)
+ Q_DECLARE_PRIVATE(QSGLoader)
+ Q_PRIVATE_SLOT(d_func(), void _q_sourceLoaded())
+ Q_PRIVATE_SLOT(d_func(), void _q_updateSize())
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QSGLoader)
+
+QT_END_HEADER
+
+#endif // QSGLOADER_P_H
diff --git a/src/declarative/items/qsgloader_p_p.h b/src/declarative/items/qsgloader_p_p.h
new file mode 100644
index 0000000000..63da789dce
--- /dev/null
+++ b/src/declarative/items/qsgloader_p_p.h
@@ -0,0 +1,91 @@
+// Commit: 5d2817cd668a705729df1727de49adf00713ac97
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGLOADER_P_P_H
+#define QSGLOADER_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 "qsgloader_p.h"
+#include "qsgimplicitsizeitem_p_p.h"
+#include "qsgitemchangelistener_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativeContext;
+class QSGLoaderPrivate : public QSGImplicitSizeItemPrivate, public QSGItemChangeListener
+{
+ Q_DECLARE_PUBLIC(QSGLoader)
+
+public:
+ QSGLoaderPrivate();
+ ~QSGLoaderPrivate();
+
+ void itemGeometryChanged(QSGItem *item, const QRectF &newGeometry, const QRectF &oldGeometry);
+ void clear();
+ void initResize();
+ void load();
+
+ QUrl source;
+ QSGItem *item;
+ QDeclarativeComponent *component;
+ bool ownComponent : 1;
+ bool updatingSize: 1;
+ bool itemWidthValid : 1;
+ bool itemHeightValid : 1;
+
+ void _q_sourceLoaded();
+ void _q_updateSize(bool loaderGeometryChanged = true);
+};
+
+QT_END_NAMESPACE
+
+#endif // QSGLOADER_P_P_H
diff --git a/src/declarative/items/qsgmousearea.cpp b/src/declarative/items/qsgmousearea.cpp
new file mode 100644
index 0000000000..887d78a64d
--- /dev/null
+++ b/src/declarative/items/qsgmousearea.cpp
@@ -0,0 +1,800 @@
+// Commit: e1ffbc04131dc6f76fa76821c297d08162e4b1ee
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgmousearea_p.h"
+#include "qsgmousearea_p_p.h"
+#include "qsgcanvas.h"
+#include "qsgevents_p_p.h"
+
+#include <QtGui/qgraphicssceneevent.h>
+#include <QtGui/qapplication.h>
+
+#include <float.h>
+
+QT_BEGIN_NAMESPACE
+static const int PressAndHoldDelay = 800;
+
+QSGDrag::QSGDrag(QObject *parent)
+: QObject(parent), _target(0), _axis(XandYAxis), _xmin(-FLT_MAX), _xmax(FLT_MAX), _ymin(-FLT_MAX), _ymax(FLT_MAX),
+_active(false), _filterChildren(false)
+{
+}
+
+QSGDrag::~QSGDrag()
+{
+}
+
+QSGItem *QSGDrag::target() const
+{
+ return _target;
+}
+
+void QSGDrag::setTarget(QSGItem *t)
+{
+ if (_target == t)
+ return;
+ _target = t;
+ emit targetChanged();
+}
+
+void QSGDrag::resetTarget()
+{
+ if (!_target)
+ return;
+ _target = 0;
+ emit targetChanged();
+}
+
+QSGDrag::Axis QSGDrag::axis() const
+{
+ return _axis;
+}
+
+void QSGDrag::setAxis(QSGDrag::Axis a)
+{
+ if (_axis == a)
+ return;
+ _axis = a;
+ emit axisChanged();
+}
+
+qreal QSGDrag::xmin() const
+{
+ return _xmin;
+}
+
+void QSGDrag::setXmin(qreal m)
+{
+ if (_xmin == m)
+ return;
+ _xmin = m;
+ emit minimumXChanged();
+}
+
+qreal QSGDrag::xmax() const
+{
+ return _xmax;
+}
+
+void QSGDrag::setXmax(qreal m)
+{
+ if (_xmax == m)
+ return;
+ _xmax = m;
+ emit maximumXChanged();
+}
+
+qreal QSGDrag::ymin() const
+{
+ return _ymin;
+}
+
+void QSGDrag::setYmin(qreal m)
+{
+ if (_ymin == m)
+ return;
+ _ymin = m;
+ emit minimumYChanged();
+}
+
+qreal QSGDrag::ymax() const
+{
+ return _ymax;
+}
+
+void QSGDrag::setYmax(qreal m)
+{
+ if (_ymax == m)
+ return;
+ _ymax = m;
+ emit maximumYChanged();
+}
+
+bool QSGDrag::active() const
+{
+ return _active;
+}
+
+void QSGDrag::setActive(bool drag)
+{
+ if (_active == drag)
+ return;
+ _active = drag;
+ emit activeChanged();
+}
+
+bool QSGDrag::filterChildren() const
+{
+ return _filterChildren;
+}
+
+void QSGDrag::setFilterChildren(bool filter)
+{
+ if (_filterChildren == filter)
+ return;
+ _filterChildren = filter;
+ emit filterChildrenChanged();
+}
+
+QSGMouseAreaPrivate::QSGMouseAreaPrivate()
+: absorb(true), hovered(false), pressed(false), longPress(false),
+ moved(false), stealMouse(false), doubleClick(false), preventStealing(false), drag(0)
+{
+ Q_Q(QSGMouseArea);
+ forwardTo = QDeclarativeListProperty<QSGItem>(q, forwardToList);
+}
+
+QSGMouseAreaPrivate::~QSGMouseAreaPrivate()
+{
+ delete drag;
+}
+
+void QSGMouseAreaPrivate::init()
+{
+ Q_Q(QSGMouseArea);
+ q->setAcceptedMouseButtons(Qt::LeftButton);
+ q->setFiltersChildMouseEvents(true);
+}
+
+void QSGMouseAreaPrivate::saveEvent(QGraphicsSceneMouseEvent *event)
+{
+ lastPos = event->pos();
+ lastScenePos = event->scenePos();
+ lastButton = event->button();
+ lastButtons = event->buttons();
+ lastModifiers = event->modifiers();
+}
+
+void QSGMouseAreaPrivate::forwardEvent(QGraphicsSceneMouseEvent* event)
+{
+ Q_Q(QSGMouseArea);
+ for(int i=0; i < forwardToList.count(); i++){
+ event->setPos(forwardToList[i]->mapFromScene(event->scenePos()));
+ forwardToList[i]->canvas()->sendEvent(forwardToList[i], event);
+ if(event->isAccepted())
+ break;
+ }
+ event->setPos(q->mapFromScene(event->scenePos()));
+}
+
+bool QSGMouseAreaPrivate::isPressAndHoldConnected()
+{
+ Q_Q(QSGMouseArea);
+ static int idx = QObjectPrivate::get(q)->signalIndex("pressAndHold(QSGMouseEvent*)");
+ return QObjectPrivate::get(q)->isSignalConnected(idx);
+}
+
+bool QSGMouseAreaPrivate::isDoubleClickConnected()
+{
+ Q_Q(QSGMouseArea);
+ static int idx = QObjectPrivate::get(q)->signalIndex("doubleClicked(QSGMouseEvent*)");
+ return QObjectPrivate::get(q)->isSignalConnected(idx);
+}
+
+bool QSGMouseAreaPrivate::isClickConnected()
+{
+ Q_Q(QSGMouseArea);
+ static int idx = QObjectPrivate::get(q)->signalIndex("clicked(QSGMouseEvent*)");
+ return QObjectPrivate::get(q)->isSignalConnected(idx);
+}
+
+void QSGMouseAreaPrivate::propagate(QSGMouseEvent* event, PropagateType t)
+{
+ Q_Q(QSGMouseArea);
+ QPointF scenePos = q->mapToScene(QPointF(event->x(), event->y()));
+ propagateHelper(event, canvas->rootItem(), scenePos, t);
+}
+
+bool QSGMouseAreaPrivate::propagateHelper(QSGMouseEvent *ev, QSGItem *item,const QPointF &sp, PropagateType sig)
+{
+ //Based off of QSGCanvas::deliverInitialMousePressEvent
+ //But specific to MouseArea, so doesn't belong in canvas
+ Q_Q(const QSGMouseArea);
+ QSGItemPrivate *itemPrivate = QSGItemPrivate::get(item);
+ if (itemPrivate->opacity == 0.0)
+ return false;
+
+ if (itemPrivate->flags & QSGItem::ItemClipsChildrenToShape) {
+ QPointF p = item->mapFromScene(sp);
+ if (!QRectF(0, 0, item->width(), item->height()).contains(p))
+ return false;
+ }
+
+ QList<QSGItem *> children = itemPrivate->paintOrderChildItems();
+ for (int ii = children.count() - 1; ii >= 0; --ii) {
+ QSGItem *child = children.at(ii);
+ if (!child->isVisible() || !child->isEnabled())
+ continue;
+ if (propagateHelper(ev, child, sp, sig))
+ return true;
+ }
+
+ QSGMouseArea* ma = qobject_cast<QSGMouseArea*>(item);
+ if (ma && ma != q && itemPrivate->acceptedMouseButtons & ev->button()) {
+ switch(sig){
+ case Click:
+ if (!ma->d_func()->isClickConnected())
+ return false;
+ break;
+ case DoubleClick:
+ if (!ma->d_func()->isDoubleClickConnected())
+ return false;
+ break;
+ case PressAndHold:
+ if (!ma->d_func()->isPressAndHoldConnected())
+ return false;
+ break;
+ }
+ QPointF p = item->mapFromScene(sp);
+ if (QRectF(0, 0, item->width(), item->height()).contains(p)) {
+ ev->setX(p.x());
+ ev->setY(p.y());
+ ev->setAccepted(true);//It is connected, they have to explicitly ignore to let it slide
+ switch(sig){
+ case Click: emit ma->clicked(ev); break;
+ case DoubleClick: emit ma->doubleClicked(ev); break;
+ case PressAndHold: emit ma->pressAndHold(ev); break;
+ }
+ if (ev->isAccepted())
+ return true;
+ }
+ }
+ return false;
+
+}
+
+/*
+ Behavioral Change in QtQuick 2.0
+
+ From QtQuick 2.0, the signals clicked, doubleClicked and pressAndHold have a different interaction
+ model with regards to the delivery of events to multiple overlapping MouseAreas. These signals will now propagate
+ to all MouseAreas in the area, in painting order, until accepted by one of them. A signal is accepted by
+ default if there is a signal handler for it, use mouse.accepted = false; to ignore. This propagation
+ can send the signal to MouseAreas other than the one which accepted the press event, although that MouseArea
+ will receive the signal first.
+
+ Note that to get the same behavior as a QtQuick 1.0 MouseArea{} with regard to absorbing all mouse events, you will
+ now need to add empty signal handlers for these three signals.
+ */
+QSGMouseArea::QSGMouseArea(QSGItem *parent)
+ : QSGItem(*(new QSGMouseAreaPrivate), parent)
+{
+ Q_D(QSGMouseArea);
+ d->init();
+}
+
+QSGMouseArea::~QSGMouseArea()
+{
+}
+
+qreal QSGMouseArea::mouseX() const
+{
+ Q_D(const QSGMouseArea);
+ return d->lastPos.x();
+}
+
+qreal QSGMouseArea::mouseY() const
+{
+ Q_D(const QSGMouseArea);
+ return d->lastPos.y();
+}
+
+bool QSGMouseArea::isEnabled() const
+{
+ Q_D(const QSGMouseArea);
+ return d->absorb;
+}
+
+void QSGMouseArea::setEnabled(bool a)
+{
+ Q_D(QSGMouseArea);
+ if (a != d->absorb) {
+ d->absorb = a;
+ emit enabledChanged();
+ }
+}
+
+bool QSGMouseArea::preventStealing() const
+{
+ Q_D(const QSGMouseArea);
+ return d->preventStealing;
+}
+
+void QSGMouseArea::setPreventStealing(bool prevent)
+{
+ Q_D(QSGMouseArea);
+ if (prevent != d->preventStealing) {
+ d->preventStealing = prevent;
+ setKeepMouseGrab(d->preventStealing && d->absorb);
+ emit preventStealingChanged();
+ }
+}
+
+Qt::MouseButtons QSGMouseArea::pressedButtons() const
+{
+ Q_D(const QSGMouseArea);
+ return d->lastButtons;
+}
+
+void QSGMouseArea::mousePressEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(QSGMouseArea);
+ d->moved = false;
+ d->stealMouse = d->preventStealing;
+ if (!d->absorb)
+ QSGItem::mousePressEvent(event);
+ else {
+ d->longPress = false;
+ d->saveEvent(event);
+ if (d->drag) {
+ d->dragX = drag()->axis() & QSGDrag::XAxis;
+ d->dragY = drag()->axis() & QSGDrag::YAxis;
+ }
+ if (d->drag)
+ d->drag->setActive(false);
+ setHovered(true);
+ d->startScene = event->scenePos();
+ d->pressAndHoldTimer.start(PressAndHoldDelay, this);
+ setKeepMouseGrab(d->stealMouse);
+ event->setAccepted(setPressed(true));
+
+ if(!event->isAccepted() && d->forwardToList.count())
+ d->forwardEvent(event);
+ }
+}
+
+void QSGMouseArea::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(QSGMouseArea);
+ if (!d->absorb) {
+ QSGItem::mouseMoveEvent(event);
+ return;
+ }
+
+ d->saveEvent(event);
+
+ // ### we should skip this if these signals aren't used
+ // ### can GV handle this for us?
+ bool contains = boundingRect().contains(d->lastPos);
+ if (d->hovered && !contains)
+ setHovered(false);
+ else if (!d->hovered && contains)
+ setHovered(true);
+
+ if (d->drag && d->drag->target()) {
+ if (!d->moved) {
+ d->startX = drag()->target()->x();
+ d->startY = drag()->target()->y();
+ }
+
+ QPointF startLocalPos;
+ QPointF curLocalPos;
+ if (drag()->target()->parentItem()) {
+ startLocalPos = drag()->target()->parentItem()->mapFromScene(d->startScene);
+ curLocalPos = drag()->target()->parentItem()->mapFromScene(event->scenePos());
+ } else {
+ startLocalPos = d->startScene;
+ curLocalPos = event->scenePos();
+ }
+
+ const int dragThreshold = QApplication::startDragDistance();
+ qreal dx = qAbs(curLocalPos.x() - startLocalPos.x());
+ qreal dy = qAbs(curLocalPos.y() - startLocalPos.y());
+
+ if (keepMouseGrab() && d->stealMouse)
+ d->drag->setActive(true);
+
+ if (d->dragX && d->drag->active()) {
+ qreal x = (curLocalPos.x() - startLocalPos.x()) + d->startX;
+ if (x < drag()->xmin())
+ x = drag()->xmin();
+ else if (x > drag()->xmax())
+ x = drag()->xmax();
+ drag()->target()->setX(x);
+ }
+ if (d->dragY && d->drag->active()) {
+ qreal y = (curLocalPos.y() - startLocalPos.y()) + d->startY;
+ if (y < drag()->ymin())
+ y = drag()->ymin();
+ else if (y > drag()->ymax())
+ y = drag()->ymax();
+ drag()->target()->setY(y);
+ }
+
+ if (!keepMouseGrab()) {
+ if ((!d->dragY && dy < dragThreshold && d->dragX && dx > dragThreshold)
+ || (!d->dragX && dx < dragThreshold && d->dragY && dy > dragThreshold)
+ || (d->dragX && d->dragY && (dx > dragThreshold || dy > dragThreshold))) {
+ setKeepMouseGrab(true);
+ d->stealMouse = true;
+ }
+ }
+
+ d->moved = true;
+ }
+ QSGMouseEvent me(d->lastPos.x(), d->lastPos.y(), d->lastButton, d->lastButtons, d->lastModifiers, false, d->longPress);
+ emit mousePositionChanged(&me);
+ me.setX(d->lastPos.x());
+ me.setY(d->lastPos.y());
+ emit positionChanged(&me);
+
+ if(!event->isAccepted() && d->forwardToList.count())
+ d->forwardEvent(event);
+}
+
+void QSGMouseArea::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(QSGMouseArea);
+ d->stealMouse = false;
+ if (!d->absorb) {
+ QSGItem::mouseReleaseEvent(event);
+ } else {
+ d->saveEvent(event);
+ setPressed(false);
+ if (d->drag)
+ d->drag->setActive(false);
+ // If we don't accept hover, we need to reset containsMouse.
+ if (!acceptHoverEvents())
+ setHovered(false);
+ QSGCanvas *c = canvas();
+ if (c && c->mouseGrabberItem() == this)
+ ungrabMouse();
+ setKeepMouseGrab(false);
+
+ if(!event->isAccepted() && d->forwardToList.count())
+ d->forwardEvent(event);
+ }
+ d->doubleClick = false;
+}
+
+void QSGMouseArea::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(QSGMouseArea);
+ if (!d->absorb) {
+ QSGItem::mouseDoubleClickEvent(event);
+ } else {
+ d->saveEvent(event);
+ QSGMouseEvent me(d->lastPos.x(), d->lastPos.y(), d->lastButton, d->lastButtons, d->lastModifiers, true, false);
+ me.setAccepted(d->isDoubleClickConnected());
+ emit this->doubleClicked(&me);
+ if (!me.isAccepted())
+ d->propagate(&me, QSGMouseAreaPrivate::DoubleClick);
+ d->doubleClick = d->isDoubleClickConnected() || me.isAccepted();
+ QSGItem::mouseDoubleClickEvent(event);
+ }
+}
+
+void QSGMouseArea::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
+{
+ Q_D(QSGMouseArea);
+ if (!d->absorb) {
+ QSGItem::hoverEnterEvent(event);
+ } else {
+ d->lastPos = event->pos();
+ setHovered(true);
+ QSGMouseEvent me(d->lastPos.x(), d->lastPos.y(), Qt::NoButton, Qt::NoButton, event->modifiers(), false, false);
+ emit mousePositionChanged(&me);
+ }
+}
+
+void QSGMouseArea::hoverMoveEvent(QGraphicsSceneHoverEvent *event)
+{
+ Q_D(QSGMouseArea);
+ if (!d->absorb) {
+ QSGItem::hoverMoveEvent(event);
+ } else {
+ d->lastPos = event->pos();
+ QSGMouseEvent me(d->lastPos.x(), d->lastPos.y(), Qt::NoButton, Qt::NoButton, event->modifiers(), false, false);
+ emit mousePositionChanged(&me);
+ me.setX(d->lastPos.x());
+ me.setY(d->lastPos.y());
+ emit positionChanged(&me);
+ }
+}
+
+void QSGMouseArea::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
+{
+ Q_D(QSGMouseArea);
+ if (!d->absorb)
+ QSGItem::hoverLeaveEvent(event);
+ else
+ setHovered(false);
+}
+
+void QSGMouseArea::mouseUngrabEvent()
+{
+ Q_D(QSGMouseArea);
+ if (d->pressed) {
+ // if our mouse grab has been removed (probably by Flickable), fix our
+ // state
+ d->pressed = false;
+ d->stealMouse = false;
+ setKeepMouseGrab(false);
+ emit canceled();
+ emit pressedChanged();
+ if (d->hovered) {
+ d->hovered = false;
+ emit hoveredChanged();
+ }
+ }
+}
+
+bool QSGMouseArea::sendMouseEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(QSGMouseArea);
+ QGraphicsSceneMouseEvent mouseEvent(event->type());
+ QRectF myRect = mapRectToScene(QRectF(0, 0, width(), height()));
+
+ QSGCanvas *c = canvas();
+ QSGItem *grabber = c ? c->mouseGrabberItem() : 0;
+ bool stealThisEvent = d->stealMouse;
+ if ((stealThisEvent || myRect.contains(event->scenePos().toPoint())) && (!grabber || !grabber->keepMouseGrab())) {
+ mouseEvent.setAccepted(false);
+ for (int i = 0x1; i <= 0x10; i <<= 1) {
+ if (event->buttons() & i) {
+ Qt::MouseButton button = Qt::MouseButton(i);
+ mouseEvent.setButtonDownPos(button, mapFromScene(event->buttonDownPos(button)));
+ }
+ }
+ mouseEvent.setScenePos(event->scenePos());
+ mouseEvent.setLastScenePos(event->lastScenePos());
+ mouseEvent.setPos(mapFromScene(event->scenePos()));
+ mouseEvent.setLastPos(mapFromScene(event->lastScenePos()));
+
+ switch(mouseEvent.type()) {
+ case QEvent::GraphicsSceneMouseMove:
+ mouseMoveEvent(&mouseEvent);
+ break;
+ case QEvent::GraphicsSceneMousePress:
+ mousePressEvent(&mouseEvent);
+ break;
+ case QEvent::GraphicsSceneMouseRelease:
+ mouseReleaseEvent(&mouseEvent);
+ break;
+ default:
+ break;
+ }
+ grabber = c->mouseGrabberItem();
+ if (grabber && stealThisEvent && !grabber->keepMouseGrab() && grabber != this)
+ grabMouse();
+
+ return stealThisEvent;
+ }
+ if (mouseEvent.type() == QEvent::GraphicsSceneMouseRelease) {
+ if (d->pressed) {
+ d->pressed = false;
+ d->stealMouse = false;
+ if (c && c->mouseGrabberItem() == this)
+ ungrabMouse();
+ emit canceled();
+ emit pressedChanged();
+ if (d->hovered) {
+ d->hovered = false;
+ emit hoveredChanged();
+ }
+ }
+ }
+ return false;
+}
+
+bool QSGMouseArea::childMouseEventFilter(QSGItem *i, QEvent *e)
+{
+ Q_D(QSGMouseArea);
+ if (!d->absorb || !isVisible() || !d->drag || !d->drag->filterChildren())
+ return QSGItem::childMouseEventFilter(i, e);
+ switch (e->type()) {
+ case QEvent::GraphicsSceneMousePress:
+ case QEvent::GraphicsSceneMouseMove:
+ case QEvent::GraphicsSceneMouseRelease:
+ return sendMouseEvent(static_cast<QGraphicsSceneMouseEvent *>(e));
+ default:
+ break;
+ }
+
+ return QSGItem::childMouseEventFilter(i, e);
+}
+
+void QSGMouseArea::timerEvent(QTimerEvent *event)
+{
+ Q_D(QSGMouseArea);
+ if (event->timerId() == d->pressAndHoldTimer.timerId()) {
+ d->pressAndHoldTimer.stop();
+ bool dragged = d->drag && d->drag->active();
+ if (d->pressed && dragged == false && d->hovered == true) {
+ d->longPress = true;
+ QSGMouseEvent me(d->lastPos.x(), d->lastPos.y(), d->lastButton, d->lastButtons, d->lastModifiers, false, d->longPress);
+ me.setAccepted(d->isPressAndHoldConnected());
+ emit pressAndHold(&me);
+ if (!me.isAccepted())
+ d->propagate(&me, QSGMouseAreaPrivate::PressAndHold);
+ }
+ }
+}
+
+void QSGMouseArea::geometryChanged(const QRectF &newGeometry,
+ const QRectF &oldGeometry)
+{
+ Q_D(QSGMouseArea);
+ QSGItem::geometryChanged(newGeometry, oldGeometry);
+
+ if (d->lastScenePos.isNull)
+ d->lastScenePos = mapToScene(d->lastPos);
+ else if (newGeometry.x() != oldGeometry.x() || newGeometry.y() != oldGeometry.y())
+ d->lastPos = mapFromScene(d->lastScenePos);
+}
+
+void QSGMouseArea::itemChange(ItemChange change, const ItemChangeData &value)
+{
+ Q_D(QSGMouseArea);
+ switch (change) {
+ case ItemVisibleHasChanged:
+ if (acceptHoverEvents() && d->hovered != (isVisible() && isUnderMouse()))
+ setHovered(!d->hovered);
+ break;
+ default:
+ break;
+ }
+
+ QSGItem::itemChange(change, value);
+}
+
+bool QSGMouseArea::hoverEnabled() const
+{
+ return acceptHoverEvents();
+}
+
+void QSGMouseArea::setHoverEnabled(bool h)
+{
+ Q_D(QSGMouseArea);
+ if (h == acceptHoverEvents())
+ return;
+
+ setAcceptHoverEvents(h);
+ emit hoverEnabledChanged();
+ if (d->hovered != isUnderMouse())
+ setHovered(!d->hovered);
+}
+
+bool QSGMouseArea::hovered() const
+{
+ Q_D(const QSGMouseArea);
+ return d->hovered;
+}
+
+bool QSGMouseArea::pressed() const
+{
+ Q_D(const QSGMouseArea);
+ return d->pressed;
+}
+
+void QSGMouseArea::setHovered(bool h)
+{
+ Q_D(QSGMouseArea);
+ if (d->hovered != h) {
+ d->hovered = h;
+ emit hoveredChanged();
+ d->hovered ? emit entered() : emit exited();
+ }
+}
+
+Qt::MouseButtons QSGMouseArea::acceptedButtons() const
+{
+ return acceptedMouseButtons();
+}
+
+void QSGMouseArea::setAcceptedButtons(Qt::MouseButtons buttons)
+{
+ if (buttons != acceptedMouseButtons()) {
+ setAcceptedMouseButtons(buttons);
+ emit acceptedButtonsChanged();
+ }
+}
+
+bool QSGMouseArea::setPressed(bool p)
+{
+ Q_D(QSGMouseArea);
+ bool dragged = d->drag && d->drag->active();
+ bool isclick = d->pressed == true && p == false && dragged == false && d->hovered == true;
+
+ if (d->pressed != p) {
+ d->pressed = p;
+ QSGMouseEvent me(d->lastPos.x(), d->lastPos.y(), d->lastButton, d->lastButtons, d->lastModifiers, isclick, d->longPress);
+ if (d->pressed) {
+ if (!d->doubleClick)
+ emit pressed(&me);
+ me.setX(d->lastPos.x());
+ me.setY(d->lastPos.y());
+ emit mousePositionChanged(&me);
+ emit pressedChanged();
+ } else {
+ emit released(&me);
+ me.setX(d->lastPos.x());
+ me.setY(d->lastPos.y());
+ emit pressedChanged();
+ if (isclick && !d->longPress && !d->doubleClick){
+ me.setAccepted(d->isClickConnected());
+ emit clicked(&me);
+ if (!me.isAccepted())
+ d->propagate(&me, QSGMouseAreaPrivate::Click);
+ }
+ }
+
+ return me.isAccepted();
+ }
+ return false;
+}
+
+QSGDrag *QSGMouseArea::drag()
+{
+ Q_D(QSGMouseArea);
+ if (!d->drag)
+ d->drag = new QSGDrag;
+ return d->drag;
+}
+
+QDeclarativeListProperty<QSGItem> QSGMouseArea::forwardTo()
+{
+ Q_D(QSGMouseArea);
+ return d->forwardTo;
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/items/qsgmousearea_p.h b/src/declarative/items/qsgmousearea_p.h
new file mode 100644
index 0000000000..469b9f7168
--- /dev/null
+++ b/src/declarative/items/qsgmousearea_p.h
@@ -0,0 +1,219 @@
+// Commit: c6e6a35aeb8794d68a3ca0c4e27a3a1181c066b5
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGMOUSEAREA_P_H
+#define QSGMOUSEAREA_P_H
+
+#include "qsgitem.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class Q_AUTOTEST_EXPORT QSGDrag : public QObject
+{
+ Q_OBJECT
+
+ Q_ENUMS(Axis)
+ Q_PROPERTY(QSGItem *target READ target WRITE setTarget NOTIFY targetChanged RESET resetTarget)
+ Q_PROPERTY(Axis axis READ axis WRITE setAxis NOTIFY axisChanged)
+ Q_PROPERTY(qreal minimumX READ xmin WRITE setXmin NOTIFY minimumXChanged)
+ Q_PROPERTY(qreal maximumX READ xmax WRITE setXmax NOTIFY maximumXChanged)
+ Q_PROPERTY(qreal minimumY READ ymin WRITE setYmin NOTIFY minimumYChanged)
+ Q_PROPERTY(qreal maximumY READ ymax WRITE setYmax NOTIFY maximumYChanged)
+ Q_PROPERTY(bool active READ active NOTIFY activeChanged)
+ Q_PROPERTY(bool filterChildren READ filterChildren WRITE setFilterChildren NOTIFY filterChildrenChanged)
+ //### consider drag and drop
+
+public:
+ QSGDrag(QObject *parent=0);
+ ~QSGDrag();
+
+ QSGItem *target() const;
+ void setTarget(QSGItem *);
+ void resetTarget();
+
+ enum Axis { XAxis=0x01, YAxis=0x02, XandYAxis=0x03 };
+ Axis axis() const;
+ void setAxis(Axis);
+
+ qreal xmin() const;
+ void setXmin(qreal);
+ qreal xmax() const;
+ void setXmax(qreal);
+ qreal ymin() const;
+ void setYmin(qreal);
+ qreal ymax() const;
+ void setYmax(qreal);
+
+ bool active() const;
+ void setActive(bool);
+
+ bool filterChildren() const;
+ void setFilterChildren(bool);
+
+Q_SIGNALS:
+ void targetChanged();
+ void axisChanged();
+ void minimumXChanged();
+ void maximumXChanged();
+ void minimumYChanged();
+ void maximumYChanged();
+ void activeChanged();
+ void filterChildrenChanged();
+
+private:
+ QSGItem *_target;
+ Axis _axis;
+ qreal _xmin;
+ qreal _xmax;
+ qreal _ymin;
+ qreal _ymax;
+ bool _active : 1;
+ bool _filterChildren: 1;
+ Q_DISABLE_COPY(QSGDrag)
+};
+
+class QSGMouseEvent;
+class QSGMouseAreaPrivate;
+class Q_AUTOTEST_EXPORT QSGMouseArea : public QSGItem
+{
+ Q_OBJECT
+
+ Q_PROPERTY(qreal mouseX READ mouseX NOTIFY mousePositionChanged)
+ Q_PROPERTY(qreal mouseY READ mouseY NOTIFY mousePositionChanged)
+ Q_PROPERTY(bool containsMouse READ hovered NOTIFY hoveredChanged)
+ Q_PROPERTY(bool pressed READ pressed NOTIFY pressedChanged)
+ Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled NOTIFY enabledChanged)
+ Q_PROPERTY(Qt::MouseButtons pressedButtons READ pressedButtons NOTIFY pressedChanged)
+ Q_PROPERTY(Qt::MouseButtons acceptedButtons READ acceptedButtons WRITE setAcceptedButtons NOTIFY acceptedButtonsChanged)
+ Q_PROPERTY(bool hoverEnabled READ hoverEnabled WRITE setHoverEnabled NOTIFY hoverEnabledChanged)
+ Q_PROPERTY(QSGDrag *drag READ drag CONSTANT) //### add flicking to QSGDrag or add a QDeclarativeFlick ???
+ Q_PROPERTY(bool preventStealing READ preventStealing WRITE setPreventStealing NOTIFY preventStealingChanged)
+ Q_PROPERTY(QDeclarativeListProperty<QSGItem> forwardTo READ forwardTo);
+
+public:
+ QSGMouseArea(QSGItem *parent=0);
+ ~QSGMouseArea();
+
+ qreal mouseX() const;
+ qreal mouseY() const;
+
+ bool isEnabled() const;
+ void setEnabled(bool);
+
+ bool hovered() const;
+ bool pressed() const;
+
+ Qt::MouseButtons pressedButtons() const;
+
+ Qt::MouseButtons acceptedButtons() const;
+ void setAcceptedButtons(Qt::MouseButtons buttons);
+
+ bool hoverEnabled() const;
+ void setHoverEnabled(bool h);
+
+ QSGDrag *drag();
+
+ bool preventStealing() const;
+ void setPreventStealing(bool prevent);
+
+ QDeclarativeListProperty<QSGItem> forwardTo();
+
+Q_SIGNALS:
+ void hoveredChanged();
+ void pressedChanged();
+ void enabledChanged();
+ void acceptedButtonsChanged();
+ void hoverEnabledChanged();
+ void positionChanged(QSGMouseEvent *mouse);
+ void mousePositionChanged(QSGMouseEvent *mouse);
+ void preventStealingChanged();
+
+ void pressed(QSGMouseEvent *mouse);
+ void pressAndHold(QSGMouseEvent *mouse);
+ void released(QSGMouseEvent *mouse);
+ void clicked(QSGMouseEvent *mouse);
+ void doubleClicked(QSGMouseEvent *mouse);
+ void entered();
+ void exited();
+ void canceled();
+
+protected:
+ void setHovered(bool);
+ bool setPressed(bool);
+ bool sendMouseEvent(QGraphicsSceneMouseEvent *event);
+
+ virtual void mousePressEvent(QGraphicsSceneMouseEvent *event);
+ virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *event);
+ virtual void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event);
+ virtual void mouseMoveEvent(QGraphicsSceneMouseEvent *event);
+ virtual void mouseUngrabEvent();
+ virtual void hoverEnterEvent(QGraphicsSceneHoverEvent *event);
+ virtual void hoverMoveEvent(QGraphicsSceneHoverEvent *event);
+ virtual void hoverLeaveEvent(QGraphicsSceneHoverEvent *event);
+ virtual bool childMouseEventFilter(QSGItem *i, QEvent *e);
+ virtual void timerEvent(QTimerEvent *event);
+
+ virtual void geometryChanged(const QRectF &newGeometry,
+ const QRectF &oldGeometry);
+ virtual void itemChange(ItemChange change, const ItemChangeData& value);
+
+private:
+ void handlePress();
+ void handleRelease();
+
+private:
+ Q_DISABLE_COPY(QSGMouseArea)
+ Q_DECLARE_PRIVATE(QSGMouseArea)
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QSGDrag)
+QML_DECLARE_TYPE(QSGMouseArea)
+
+QT_END_HEADER
+
+#endif // QSGMOUSEAREA_P_H
diff --git a/src/declarative/items/qsgmousearea_p_p.h b/src/declarative/items/qsgmousearea_p_p.h
new file mode 100644
index 0000000000..e736c059a2
--- /dev/null
+++ b/src/declarative/items/qsgmousearea_p_p.h
@@ -0,0 +1,115 @@
+// Commit: c6e6a35aeb8794d68a3ca0c4e27a3a1181c066b5
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGMOUSEAREA_P_P_H
+#define QSGMOUSEAREA_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 "qsgitem_p.h"
+
+#include <QtGui/qgraphicssceneevent.h>
+#include <QtCore/qbasictimer.h>
+
+QT_BEGIN_NAMESPACE
+
+class QSGMouseEvent;
+class QSGMouseArea;
+class QSGMouseAreaPrivate : public QSGItemPrivate
+{
+ Q_DECLARE_PUBLIC(QSGMouseArea)
+
+public:
+ QSGMouseAreaPrivate();
+ ~QSGMouseAreaPrivate();
+ void init();
+
+ void saveEvent(QGraphicsSceneMouseEvent *event);
+ enum PropagateType{
+ Click,
+ DoubleClick,
+ PressAndHold
+ };
+ void propagate(QSGMouseEvent* event, PropagateType);
+ bool propagateHelper(QSGMouseEvent*, QSGItem*,const QPointF &, PropagateType);
+ void forwardEvent(QGraphicsSceneMouseEvent* event);
+
+ bool isPressAndHoldConnected();
+ bool isDoubleClickConnected();
+ bool isClickConnected();
+
+ bool absorb : 1;
+ bool hovered : 1;
+ bool pressed : 1;
+ bool longPress : 1;
+ bool moved : 1;
+ bool dragX : 1;
+ bool dragY : 1;
+ bool stealMouse : 1;
+ bool doubleClick : 1;
+ bool preventStealing : 1;
+ QSGDrag *drag;
+ QPointF startScene;
+ qreal startX;
+ qreal startY;
+ QPointF lastPos;
+ QDeclarativeNullableValue<QPointF> lastScenePos;
+ Qt::MouseButton lastButton;
+ Qt::MouseButtons lastButtons;
+ Qt::KeyboardModifiers lastModifiers;
+ QBasicTimer pressAndHoldTimer;
+ QDeclarativeListProperty<QSGItem> forwardTo;
+ QList<QSGItem*> forwardToList;
+};
+
+QT_END_NAMESPACE
+
+#endif // QSGMOUSEAREA_P_P_H
diff --git a/src/declarative/items/qsgninepatchnode.cpp b/src/declarative/items/qsgninepatchnode.cpp
new file mode 100644
index 0000000000..eaa97178f4
--- /dev/null
+++ b/src/declarative/items/qsgninepatchnode.cpp
@@ -0,0 +1,292 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgninepatchnode_p.h"
+#include <private/qsgadaptationlayer_p.h>
+#include <private/qmath_p.h>
+
+QSGNinePatchNode::QSGNinePatchNode()
+ : m_geometry(QSGGeometry::defaultAttributes_TexturedPoint2D(), 0)
+ , m_horizontalTileMode(QSGBorderImage::Stretch)
+ , m_verticalTileMode(QSGBorderImage::Stretch)
+ , m_dirtyGeometry(false)
+ , m_mirror(false)
+{
+ setOpaqueMaterial(&m_material);
+ setMaterial(&m_materialO);
+ setGeometry(&m_geometry);
+ m_geometry.setDrawingMode(GL_TRIANGLES);
+}
+
+void QSGNinePatchNode::setInnerRect(const QRectF &rect)
+{
+ if (m_innerRect == rect)
+ return;
+ m_innerRect = rect;
+ m_dirtyGeometry = true;
+}
+
+void QSGNinePatchNode::setRect(const QRectF &rect)
+{
+ if (m_targetRect == rect)
+ return;
+ m_targetRect = rect;
+ m_dirtyGeometry = true;
+}
+
+void QSGNinePatchNode::setHorzontalTileMode(QSGBorderImage::TileMode mode)
+{
+ if (mode == QSGBorderImage::TileMode(m_horizontalTileMode))
+ return;
+ m_horizontalTileMode = mode;
+ m_dirtyGeometry = true;
+}
+
+
+void QSGNinePatchNode::setVerticalTileMode(QSGBorderImage::TileMode mode)
+{
+ if (mode == QSGBorderImage::TileMode(m_verticalTileMode))
+ return;
+ m_verticalTileMode = mode;
+ m_dirtyGeometry = true;
+}
+
+
+void QSGNinePatchNode::setFiltering(QSGTexture::Filtering filtering)
+{
+ if (m_material.filtering() == filtering)
+ return;
+
+ m_material.setFiltering(filtering);
+ m_materialO.setFiltering(filtering);
+ markDirty(DirtyMaterial);
+}
+
+QSGTexture::Filtering QSGNinePatchNode::filtering() const
+{
+ return m_material.filtering();
+}
+
+void QSGNinePatchNode::setTexture(QSGTexture *texture)
+{
+ if (texture == m_material.texture())
+ return;
+ m_material.setTexture(texture);
+ m_materialO.setTexture(texture);
+ markDirty(DirtyMaterial);
+}
+
+QSGTexture *QSGNinePatchNode::texture() const
+{
+ return m_material.texture();
+}
+
+void QSGNinePatchNode::setMirror(bool m)
+{
+ if (m_mirror == m)
+ return;
+ m_mirror = m;
+ m_dirtyGeometry = true;
+}
+
+
+void QSGNinePatchNode::update()
+{
+ if (!m_dirtyGeometry)
+ return;
+
+ // For stretch this algorithm could be simplified to use less vertices
+ // as more vertices could be reused then, but I doubt its where our main
+ // problem will lie. This way, we at least share the algorithm between all
+
+ Q_ASSERT(m_material.texture());
+
+ float tw = m_material.texture()->textureSize().width();
+ float th = m_material.texture()->textureSize().height();
+
+ float rightBorder = tw - m_innerRect.right();
+ float bottomBorder = th - m_innerRect.bottom();
+
+// qDebug() << m_innerRect << m_targetRect << m_horizontalTileMode << m_verticalTileMode;
+
+ int xChunkCount = 0; // Number of chunks
+ float xChunkSize = 0; // Size of chunk in pixels
+ float xTexSize = m_innerRect.width(); // Size of the texture to stretch/tile
+ float xSize = m_targetRect.width() - m_innerRect.left() - rightBorder; // Size of area to fill with chunks
+
+ if (m_horizontalTileMode == QSGBorderImage::Repeat) {
+ xChunkCount = qCeil(xSize / xTexSize);
+ xChunkSize = xTexSize;
+ } else if (m_horizontalTileMode == QSGBorderImage::Round) {
+ xChunkCount = qCeil(xSize / xTexSize);
+ qreal fullWidth = xChunkCount * xTexSize;
+ xChunkSize = xTexSize * xSize / fullWidth;
+ } else {
+ xChunkCount = 1;
+ xChunkSize = xSize;
+ }
+
+ int yChunkCount = 0;
+ float yChunkSize = 0; // Relative to target rect.
+ float yTexSize = m_innerRect.height(); // Size of the texture to stretch/tile
+ float ySize = m_targetRect.height() - m_innerRect.top() - bottomBorder;
+
+ if (m_verticalTileMode == QSGBorderImage::Repeat) {
+ yChunkCount = qCeil(ySize / yTexSize);
+ yChunkSize = yTexSize;
+ } else if (m_verticalTileMode == QSGBorderImage::Round) {
+ yChunkCount = qCeil(ySize / yTexSize);
+ qreal fullHeight = yChunkCount * yTexSize;
+ yChunkSize = yTexSize * ySize / fullHeight;
+ } else {
+ yChunkCount = 1;
+ yChunkSize = ySize;
+ }
+
+ int xTotalChunkCount = xChunkCount + 2;
+ int yTotalChunkCount = yChunkCount + 2;
+
+ int totalChunkCount = xTotalChunkCount * yTotalChunkCount;
+ int vertexCount = totalChunkCount * 4;
+ int indexCount = totalChunkCount * 6;
+
+ if (vertexCount != m_geometry.vertexCount() || indexCount != m_geometry.indexCount())
+ m_geometry.allocate(vertexCount, indexCount);
+
+ QSGGeometry::TexturedPoint2D *v = m_geometry.vertexDataAsTexturedPoint2D();
+
+
+ // Fill in the vertices.. The loop below is pretty much an exact replica
+ // of the one inside fillRow.
+ float yTexChunk1 = m_innerRect.top() / th;
+ float yTexChunk2 = m_innerRect.bottom() / th;
+
+ fillRow(v, 0, 0, xChunkCount, xChunkSize);
+ fillRow(v, m_innerRect.y(), yTexChunk1, xChunkCount, xChunkSize);
+
+ for (int yc=0; yc<yChunkCount; ++yc) {
+ float yy = m_innerRect.y() + yChunkSize * yc;
+ fillRow(v, yy, yTexChunk1, xChunkCount, xChunkSize);
+
+ // Special case the last one
+ if (yc == yChunkCount - 1) {
+ float t = m_verticalTileMode == QSGBorderImage::Repeat
+ ? yTexChunk1 + (yTexChunk2 - yTexChunk1) * (m_targetRect.height() - bottomBorder - yy) / yChunkSize
+ : yTexChunk2;
+ fillRow(v, m_targetRect.height() - bottomBorder, t, xChunkCount, xChunkSize);
+ } else {
+ fillRow(v, yy + yChunkSize, yTexChunk2, xChunkCount, xChunkSize);
+ }
+ }
+
+ fillRow(v, m_targetRect.height() - bottomBorder, yTexChunk2, xChunkCount, xChunkSize);
+ fillRow(v, m_targetRect.height(), 1, xChunkCount, xChunkSize);
+
+ if (m_mirror) {
+ v = m_geometry.vertexDataAsTexturedPoint2D();
+ for (int i=0; i<m_geometry.vertexCount(); ++i) {
+ v->x = m_targetRect.width() - v->x;
+ ++v;
+ }
+ }
+
+// v = m_geometry.vertexDataAsTexturedPoint2D();
+// for (int i=0; i<m_geometry.vertexCount(); ++i) {
+// printf("Vertex: %d: (%.3f, %.3f) - (%.3f, %.3f)\n",
+// i,
+// v->x, v->y, v->tx, v->ty);
+// ++v;
+// }
+
+ quint16 *i = m_geometry.indexDataAsUShort();
+ int row = xTotalChunkCount * 2;
+ for (int r=0; r<yTotalChunkCount; ++r) {
+ int offset = r * row * 2;
+ for (int c=0; c<xTotalChunkCount; ++c) {
+ *i++ = offset + c * 2;
+ *i++ = offset + c * 2 + 1;
+ *i++ = offset + c * 2 + row;
+ *i++ = offset + c * 2 + 1;
+ *i++ = offset + c * 2 + row + 1;
+ *i++ = offset + c * 2 + row;
+ }
+ }
+
+// i = m_geometry.indexDataAsUShort();
+// for (int idx=0; idx<m_geometry.indexCount(); idx+=6) {
+// printf("%2d: ", idx / 6);
+// for (int s=0; s<6; ++s)
+// printf(" %d", i[idx + s]);
+// printf("\n");
+// }
+
+ markDirty(QSGNode::DirtyGeometry);
+}
+
+void QSGNinePatchNode::fillRow(QSGGeometry::TexturedPoint2D *&v, float y, float ty, int xChunkCount, float xChunkSize)
+{
+ float tw = m_material.texture()->textureSize().width();
+ float rightBorder = tw - m_innerRect.right();
+ float xTexChunk1 = m_innerRect.left() / tw;
+ float xTexChunk2 = m_innerRect.right() / tw;
+
+ v++->set(0, y, 0, ty);
+ v++->set(m_innerRect.x(), y, xTexChunk1, ty);
+
+ for (int xc=0; xc<xChunkCount; ++xc) {
+ float xx = m_innerRect.x() + xChunkSize * xc;
+ v++->set(xx, y, xTexChunk1, ty);
+
+ // Special case the last one
+ if (xc == xChunkCount - 1) {
+ float t = m_horizontalTileMode == QSGBorderImage::Repeat
+ ? xTexChunk1 + (xTexChunk2 - xTexChunk1) * (m_targetRect.width() - rightBorder - xx) / xChunkSize
+ : xTexChunk2;
+ v->set(m_targetRect.width() - rightBorder, y, t, ty);
+ } else {
+ v->set(xx + xChunkSize, y, xTexChunk2, ty);
+ }
+ ++v;
+ }
+
+ v++->set(m_targetRect.width() - rightBorder, y, xTexChunk2, ty);
+ v++->set(m_targetRect.width(), y, 1, ty);
+}
diff --git a/src/declarative/items/qsgninepatchnode_p.h b/src/declarative/items/qsgninepatchnode_p.h
new file mode 100644
index 0000000000..ef1686d528
--- /dev/null
+++ b/src/declarative/items/qsgninepatchnode_p.h
@@ -0,0 +1,98 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGNINEPATCHNODE_H
+#define QSGNINEPATCHNODE_H
+
+#include "qsgnode.h"
+#include "qsgtexturematerial.h"
+#include "qsgborderimage_p.h"
+
+class TextureReference;
+
+class QSGNinePatchNode : public QSGGeometryNode
+{
+public:
+ QSGNinePatchNode();
+
+ void setTexture(QSGTexture *texture);
+ QSGTexture *texture() const;
+
+ void setRect(const QRectF &rect);
+ QRectF rect() const { return m_targetRect; }
+
+ void setInnerRect(const QRectF &rect);
+ QRectF innerRect() const { return m_innerRect; }
+
+ void setFiltering(QSGTexture::Filtering filtering);
+ QSGTexture::Filtering filtering() const;
+
+ void setHorzontalTileMode(QSGBorderImage::TileMode mode);
+ QSGBorderImage::TileMode horizontalTileMode() const {
+ return (QSGBorderImage::TileMode) m_horizontalTileMode;
+ }
+
+ void setVerticalTileMode(QSGBorderImage::TileMode mode);
+ QSGBorderImage::TileMode verticalTileMode() const {
+ return (QSGBorderImage::TileMode) m_verticalTileMode;
+ }
+
+ void setMirror(bool m);
+ bool mirror() const { return m_mirror; }
+
+ void update();
+
+private:
+ void fillRow(QSGGeometry::TexturedPoint2D *&v, float y, float ty, int xChunkCount, float xChunkSize);
+ QRectF m_targetRect;
+ QRectF m_innerRect;
+ QSGOpaqueTextureMaterial m_material;
+ QSGTextureMaterial m_materialO;
+ QSGGeometry m_geometry;
+
+ uint m_horizontalTileMode : 2;
+ uint m_verticalTileMode : 2;
+
+ uint m_dirtyGeometry : 1;
+ uint m_mirror : 1;
+};
+
+#endif // QSGNINEPATCHNODE_H
diff --git a/src/declarative/items/qsgpainteditem.cpp b/src/declarative/items/qsgpainteditem.cpp
new file mode 100644
index 0000000000..775405c1fb
--- /dev/null
+++ b/src/declarative/items/qsgpainteditem.cpp
@@ -0,0 +1,475 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgpainteditem.h"
+#include <private/qsgpainteditem_p.h>
+#include <private/qsgpainternode_p.h>
+
+#include <private/qsgcontext_p.h>
+#include <private/qsgadaptationlayer_p.h>
+#include <qmath.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QSGPaintedItem
+ \brief The QSGPaintedItem class provides a way to use the QPainter API in the
+ QML Scene Graph.
+
+ The QSGPaintedItem makes it possible to use the QPainter API with the QML Scene Graph.
+ It sets up a textured rectangle in the Scene Graph and uses a QPainter to paint
+ onto the texture. The render target can be either a QImage or a QGLFramebufferObject.
+ When the render target is a QImage, QPainter first renders into the image then
+ the content is uploaded to the texture.
+ When a QGLFramebufferObject is used, QPainter paints directly onto the texture.
+ Call update() to trigger a repaint.
+
+ To enable QPainter to do anti-aliased rendering, use setAntialiasing().
+
+ QSGPaintedItem is meant to make it easier to port old code that is using the
+ QPainter API to the QML Scene Graph API and it should be used only for that purpose.
+
+ To write your own painted item, you first create a subclass of QSGPaintedItem, and then
+ start by implementing its only pure virtual public function: paint(), which implements
+ the actual painting. To get the size of the area painted by the item, use
+ contentsBoundingRect().
+*/
+
+/*!
+ \enum QSGPaintedItem::RenderTarget
+
+ This enum describes QSGPaintedItem's render targets. The render target is the
+ surface QPainter paints onto before the item is rendered on screen.
+
+ \value Image The default; QPainter paints into a QImage using the raster paint engine.
+ The image's content needs to be uploaded to graphics memory afterward, this operation
+ can potentially be slow if the item is large. This render target allows high quality
+ anti-aliasing and fast item resizing.
+
+ \value FramebufferObject QPainter paints into a QGLFramebufferObject using the GL
+ paint engine. Painting can be faster as no texture upload is required, but anti-aliasing
+ quality is not as good as if using an image. This render target allows faster rendering
+ in some cases, but you should avoid using it if the item is resized often.
+
+ \sa setRenderTarget()
+*/
+
+/*!
+ \internal
+*/
+QSGPaintedItemPrivate::QSGPaintedItemPrivate()
+ : QSGItemPrivate()
+ , contentsScale(1.0)
+ , fillColor(Qt::transparent)
+ , renderTarget(QSGPaintedItem::Image)
+ , geometryDirty(false)
+ , contentsDirty(false)
+ , opaquePainting(false)
+ , antialiasing(false)
+ , mipmap(false)
+{
+}
+
+/*!
+ Constructs a QSGPaintedItem with the given \a parent item.
+ */
+QSGPaintedItem::QSGPaintedItem(QSGItem *parent)
+ : QSGItem(*(new QSGPaintedItemPrivate), parent)
+{
+ setFlag(ItemHasContents);
+}
+
+/*!
+ \internal
+*/
+QSGPaintedItem::QSGPaintedItem(QSGPaintedItemPrivate &dd, QSGItem *parent)
+ : QSGItem(dd, parent)
+{
+ setFlag(ItemHasContents);
+}
+
+/*!
+ Destroys the QSGPaintedItem.
+*/
+QSGPaintedItem::~QSGPaintedItem()
+{
+}
+
+/*!
+ Schedules a redraw of the area covered by \a rect in this item. You can call this function
+ whenever your item needs to be redrawn, such as if it changes appearance or size.
+
+ This function does not cause an immediate paint; instead it schedules a paint request that
+ is processed by the QML Scene Graph when the next frame is rendered. The item will only be
+ redrawn if it is visible.
+
+ Note that calling this function will trigger a repaint of the whole scene.
+
+ \sa paint()
+*/
+void QSGPaintedItem::update(const QRect &rect)
+{
+ Q_D(QSGPaintedItem);
+ d->contentsDirty = true;
+
+ QRect srect(qCeil(rect.x()*d->contentsScale),
+ qCeil(rect.y()*d->contentsScale),
+ qCeil(rect.width()*d->contentsScale),
+ qCeil(rect.height()*d->contentsScale));
+
+ if (srect.isNull() && !d->dirtyRect.isNull())
+ d->dirtyRect = contentsBoundingRect().toAlignedRect();
+ else
+ d->dirtyRect |= (contentsBoundingRect() & srect).toAlignedRect();
+ QSGItem::update();
+}
+
+/*!
+ Returns true if this item is opaque; otherwise, false is returned.
+
+ By default, painted items are not opaque.
+
+ \sa setOpaquePainting()
+*/
+bool QSGPaintedItem::opaquePainting() const
+{
+ Q_D(const QSGPaintedItem);
+ return d->opaquePainting;
+}
+
+/*!
+ If \a opaque is true, the item is opaque; otherwise, it is considered as translucent.
+
+ Opaque items are not blended with the rest of the scene, you should set this to true
+ if the content of the item is opaque to speed up rendering.
+
+ By default, painted items are not opaque.
+
+ \sa opaquePainting()
+*/
+void QSGPaintedItem::setOpaquePainting(bool opaque)
+{
+ Q_D(QSGPaintedItem);
+
+ if (d->opaquePainting == opaque)
+ return;
+
+ d->opaquePainting = opaque;
+ QSGItem::update();
+}
+
+/*!
+ Returns true if antialiased painting is enabled; otherwise, false is returned.
+
+ By default, antialiasing is not enabled.
+
+ \sa setAntialiasing()
+*/
+bool QSGPaintedItem::antialiasing() const
+{
+ Q_D(const QSGPaintedItem);
+ return d->antialiasing;
+}
+
+/*!
+ If \a enable is true, antialiased painting is enabled.
+
+ By default, antialiasing is not enabled.
+
+ \sa antialiasing()
+*/
+void QSGPaintedItem::setAntialiasing(bool enable)
+{
+ Q_D(QSGPaintedItem);
+
+ if (d->antialiasing == enable)
+ return;
+
+ d->antialiasing = enable;
+ update();
+}
+
+/*!
+ Returns true if mipmaps are enabled; otherwise, false is returned.
+
+ By default, mipmapping is not enabled.
+
+ \sa setMipmap()
+*/
+bool QSGPaintedItem::mipmap() const
+{
+ Q_D(const QSGPaintedItem);
+ return d->mipmap;
+}
+
+/*!
+ If \a enable is true, mipmapping is enabled on the associated texture.
+
+ Mipmapping increases rendering speed and reduces aliasing artifacts when the item is
+ scaled down.
+
+ By default, mipmapping is not enabled.
+
+ \sa mipmap()
+*/
+void QSGPaintedItem::setMipmap(bool enable)
+{
+ Q_D(QSGPaintedItem);
+
+ if (d->mipmap == enable)
+ return;
+
+ d->mipmap = enable;
+ update();
+}
+
+/*!
+ This function returns the outer bounds of the item as a rectangle; all painting must be
+ restricted to inside an item's bounding rect.
+
+ If the contents size has not been set it reflects the size of the item; otherwise
+ it reflects the contents size scaled by the contents scale.
+
+ Use this function to know the area painted by the item.
+
+ \sa QSGItem::width(), QSGItem::height(), contentsSize(), contentsScale()
+*/
+QRectF QSGPaintedItem::contentsBoundingRect() const
+{
+ Q_D(const QSGPaintedItem);
+
+ qreal w = d->width;
+ QSizeF sz = d->contentsSize * d->contentsScale;
+ if (w < sz.width())
+ w = sz.width();
+ qreal h = d->height;
+ if (h < sz.height())
+ h = sz.height();
+
+ return QRectF(0, 0, w, h);
+}
+
+/*!
+ \property QSGPaintedItem::contentsSize
+ \brief The size of the contents
+
+ The contents size is the size of the item in regards to how it is painted
+ using the paint() function. This is distinct from the size of the
+ item in regards to height() and width().
+*/
+QSize QSGPaintedItem::contentsSize() const
+{
+ Q_D(const QSGPaintedItem);
+ return d->contentsSize;
+}
+
+void QSGPaintedItem::setContentsSize(const QSize &size)
+{
+ Q_D(QSGPaintedItem);
+
+ if (d->contentsSize == size)
+ return;
+
+ d->contentsSize = size;
+ update();
+}
+
+/*!
+ This convenience function is equivalent to calling setContentsSize(QSize()).
+*/
+void QSGPaintedItem::resetContentsSize()
+{
+ setContentsSize(QSize());
+}
+
+/*!
+ \property QSGPaintedItem::contentsScale
+ \brief The scale of the contents
+
+ All painting happening in paint() is scaled by the contents scale. This is distinct
+ from the scale of the item in regards to scale().
+
+ The default value is 1.
+*/
+qreal QSGPaintedItem::contentsScale() const
+{
+ Q_D(const QSGPaintedItem);
+ return d->contentsScale;
+}
+
+void QSGPaintedItem::setContentsScale(qreal scale)
+{
+ Q_D(QSGPaintedItem);
+
+ if (d->contentsScale == scale)
+ return;
+
+ d->contentsScale = scale;
+ update();
+}
+
+/*!
+ \property QSGPaintedItem::fillColor
+ \brief The item's background fill color.
+
+ By default, the fill color is set to Qt::transparent.
+*/
+QColor QSGPaintedItem::fillColor() const
+{
+ Q_D(const QSGPaintedItem);
+ return d->fillColor;
+}
+
+void QSGPaintedItem::setFillColor(const QColor &c)
+{
+ Q_D(QSGPaintedItem);
+
+ if (d->fillColor == c)
+ return;
+
+ d->fillColor = c;
+ update();
+
+ emit fillColorChanged();
+}
+
+/*!
+ \property QSGPaintedItem::renderTarget
+ \brief The item's render target.
+
+ This property defines which render target the QPainter renders into, it can be either
+ QSGPaintedItem::Image or QSGPaintedItem::FramebufferObject. Both have certains benefits,
+ typically performance versus quality. Using a framebuffer object avoids a costly upload
+ of the image contents to the texture in graphics memory, while using an image enables
+ high quality anti-aliasing.
+
+ \warning Resizing a framebuffer object is a costly operation, avoid using
+ the QSGPaintedItem::FramebufferObject render target if the item gets resized often.
+
+ By default, the render target is QSGPaintedItem::Image.
+*/
+QSGPaintedItem::RenderTarget QSGPaintedItem::renderTarget() const
+{
+ Q_D(const QSGPaintedItem);
+ return d->renderTarget;
+}
+
+void QSGPaintedItem::setRenderTarget(RenderTarget target)
+{
+ Q_D(QSGPaintedItem);
+
+ if (d->renderTarget == target)
+ return;
+
+ d->renderTarget = target;
+ update();
+
+ emit renderTargetChanged();
+}
+
+/*!
+ \fn virtual void QSGPaintedItem::paint(QPainter *painter) = 0
+
+ This function, which is usually called by the QML Scene Graph, paints the
+ contents of an item in local coordinates.
+
+ The function is called after the item has been filled with the fillColor.
+
+ Reimplement this function in a QSGPaintedItem subclass to provide the
+ item's painting implementation, using \a painter.
+
+ \note The QML Scene Graph uses two separate threads, the main thread does things such as
+ processing events or updating animations while a second thread does the actual OpenGL rendering.
+ As a consequence, paint() is not called from the main GUI thread but from the GL enabled
+ renderer thread. At the moment paint() is called, the GUI thread is blocked and this is
+ therefore thread-safe.
+*/
+
+/*!
+ This function is called after the item's geometry has changed.
+*/
+void QSGPaintedItem::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
+{
+ Q_D(QSGPaintedItem);
+ d->geometryDirty = true;
+ QSGItem::geometryChanged(newGeometry, oldGeometry);
+}
+
+
+/*!
+ This function is called when the Scene Graph node associated to the item needs to
+ be updated.
+*/
+QSGNode *QSGPaintedItem::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data)
+{
+ Q_UNUSED(data);
+ Q_D(QSGPaintedItem);
+
+ if (width() <= 0 || height() <= 0) {
+ delete oldNode;
+ return 0;
+ }
+
+ QSGPainterNode *node = static_cast<QSGPainterNode *>(oldNode);
+ if (!node)
+ node = new QSGPainterNode(this);
+
+ QRectF br = contentsBoundingRect();
+
+ node->setPreferredRenderTarget(d->renderTarget);
+ node->setSize(QSize(qRound(br.width()), qRound(br.height())));
+ node->setSmoothPainting(d->antialiasing);
+ node->setLinearFiltering(d->smooth);
+ node->setMipmapping(d->mipmap);
+ node->setOpaquePainting(d->opaquePainting);
+ node->setFillColor(d->fillColor);
+ node->setContentsScale(d->contentsScale);
+ node->setDirty(d->contentsDirty || d->geometryDirty, d->dirtyRect);
+ node->update();
+
+ d->contentsDirty = false;
+ d->geometryDirty = false;
+ d->dirtyRect = QRect();
+
+ return node;
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/items/qsgpainteditem.h b/src/declarative/items/qsgpainteditem.h
new file mode 100644
index 0000000000..a2d3a09e76
--- /dev/null
+++ b/src/declarative/items/qsgpainteditem.h
@@ -0,0 +1,118 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGPAINTEDITEM_P_H
+#define QSGPAINTEDITEM_P_H
+
+#include <qsgitem.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class QSGPaintedItemPrivate;
+class Q_DECLARATIVE_EXPORT QSGPaintedItem : public QSGItem
+{
+ Q_OBJECT
+ Q_ENUMS(RenderTarget)
+
+ Q_PROPERTY(QSize contentsSize READ contentsSize WRITE setContentsSize NOTIFY contentsSizeChanged)
+ Q_PROPERTY(QColor fillColor READ fillColor WRITE setFillColor NOTIFY fillColorChanged)
+ Q_PROPERTY(qreal contentsScale READ contentsScale WRITE setContentsScale NOTIFY contentsScaleChanged)
+ Q_PROPERTY(RenderTarget renderTarget READ renderTarget WRITE setRenderTarget NOTIFY renderTargetChanged)
+public:
+ QSGPaintedItem(QSGItem *parent = 0);
+ virtual ~QSGPaintedItem();
+
+ enum RenderTarget {
+ Image,
+ FramebufferObject
+ };
+
+ void update(const QRect &rect = QRect());
+
+ bool opaquePainting() const;
+ void setOpaquePainting(bool opaque);
+
+ bool antialiasing() const;
+ void setAntialiasing(bool enable);
+
+ bool mipmap() const;
+ void setMipmap(bool enable);
+
+ QRectF contentsBoundingRect() const;
+
+ QSize contentsSize() const;
+ void setContentsSize(const QSize &);
+ void resetContentsSize();
+
+ qreal contentsScale() const;
+ void setContentsScale(qreal);
+
+ QColor fillColor() const;
+ void setFillColor(const QColor&);
+
+ RenderTarget renderTarget() const;
+ void setRenderTarget(RenderTarget target);
+
+ virtual void paint(QPainter *painter) = 0;
+
+Q_SIGNALS:
+ void fillColorChanged();
+ void contentsSizeChanged();
+ void contentsScaleChanged();
+ void renderTargetChanged();
+
+protected:
+ QSGPaintedItem(QSGPaintedItemPrivate &dd, QSGItem *parent = 0);
+ virtual void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry);
+ virtual QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *);
+
+private:
+ Q_DISABLE_COPY(QSGPaintedItem);
+ Q_DECLARE_PRIVATE(QSGPaintedItem);
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QSGPAINTEDITEM_P_H
diff --git a/src/declarative/items/qsgpainteditem_p.h b/src/declarative/items/qsgpainteditem_p.h
new file mode 100644
index 0000000000..9a170d0167
--- /dev/null
+++ b/src/declarative/items/qsgpainteditem_p.h
@@ -0,0 +1,71 @@
+// Commit: ac5c099cc3c5b8c7eec7a49fdeb8a21037230350
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGPAINTEDITEM_P_P_H
+#define QSGPAINTEDITEM_P_P_H
+
+#include "qsgitem_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QSGPaintedItemPrivate : public QSGItemPrivate
+{
+public:
+ QSGPaintedItemPrivate();
+
+ QSize contentsSize;
+ qreal contentsScale;
+ QColor fillColor;
+ QSGPaintedItem::RenderTarget renderTarget;
+
+ QRect dirtyRect;
+
+ bool geometryDirty : 1;
+ bool contentsDirty : 1;
+ bool opaquePainting: 1;
+ bool antialiasing: 1;
+ bool mipmap: 1;
+};
+
+QT_END_NAMESPACE
+
+#endif // QSGPAINTEDITEM_P_P_H
diff --git a/src/declarative/items/qsgpathview.cpp b/src/declarative/items/qsgpathview.cpp
new file mode 100644
index 0000000000..fc3d39aef7
--- /dev/null
+++ b/src/declarative/items/qsgpathview.cpp
@@ -0,0 +1,1416 @@
+// Commit: 806f031efeda71d3f4d7d2f949b437493e79cf52
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgpathview_p.h"
+#include "qsgpathview_p_p.h"
+#include "qsgcanvas.h"
+
+#include <private/qdeclarativestate_p.h>
+#include <private/qdeclarativeopenmetaobject_p.h>
+#include <private/qlistmodelinterface_p.h>
+
+#include <QtGui/qevent.h>
+#include <QtGui/qgraphicssceneevent.h>
+#include <QtGui/qapplication.h>
+#include <QtCore/qmath.h>
+#include <math.h>
+
+QT_BEGIN_NAMESPACE
+
+inline qreal qmlMod(qreal x, qreal y)
+{
+#ifdef QT_USE_MATH_H_FLOATS
+ if(sizeof(qreal) == sizeof(float))
+ return fmodf(float(x), float(y));
+ else
+#endif
+ return fmod(x, y);
+}
+
+static QDeclarativeOpenMetaObjectType *qPathViewAttachedType = 0;
+
+QSGPathViewAttached::QSGPathViewAttached(QObject *parent)
+: QObject(parent), m_percent(-1), m_view(0), m_onPath(false), m_isCurrent(false)
+{
+ if (qPathViewAttachedType) {
+ m_metaobject = new QDeclarativeOpenMetaObject(this, qPathViewAttachedType);
+ m_metaobject->setCached(true);
+ } else {
+ m_metaobject = new QDeclarativeOpenMetaObject(this);
+ }
+}
+
+QSGPathViewAttached::~QSGPathViewAttached()
+{
+}
+
+QVariant QSGPathViewAttached::value(const QByteArray &name) const
+{
+ return m_metaobject->value(name);
+}
+void QSGPathViewAttached::setValue(const QByteArray &name, const QVariant &val)
+{
+ m_metaobject->setValue(name, val);
+}
+
+
+void QSGPathViewPrivate::init()
+{
+ Q_Q(QSGPathView);
+ offset = 0;
+ q->setAcceptedMouseButtons(Qt::LeftButton);
+ q->setFlag(QSGItem::ItemIsFocusScope);
+ q->setFiltersChildMouseEvents(true);
+ q->connect(&tl, SIGNAL(updated()), q, SLOT(ticked()));
+ lastPosTime.invalidate();
+ static int timelineCompletedIdx = -1;
+ static int movementEndingIdx = -1;
+ if (timelineCompletedIdx == -1) {
+ timelineCompletedIdx = QDeclarativeTimeLine::staticMetaObject.indexOfSignal("completed()");
+ movementEndingIdx = QSGPathView::staticMetaObject.indexOfSlot("movementEnding()");
+ }
+ QMetaObject::connect(&tl, timelineCompletedIdx,
+ q, movementEndingIdx, Qt::DirectConnection);
+}
+
+QSGItem *QSGPathViewPrivate::getItem(int modelIndex)
+{
+ Q_Q(QSGPathView);
+ requestedIndex = modelIndex;
+ QSGItem *item = model->item(modelIndex, false);
+ if (item) {
+ if (!attType) {
+ // pre-create one metatype to share with all attached objects
+ attType = new QDeclarativeOpenMetaObjectType(&QSGPathViewAttached::staticMetaObject, qmlEngine(q));
+ foreach(const QString &attr, path->attributes())
+ attType->createProperty(attr.toUtf8());
+ }
+ qPathViewAttachedType = attType;
+ QSGPathViewAttached *att = static_cast<QSGPathViewAttached *>(qmlAttachedPropertiesObject<QSGPathView>(item));
+ qPathViewAttachedType = 0;
+ if (att) {
+ att->m_view = q;
+ att->setOnPath(true);
+ }
+ item->setParentItem(q);
+ QSGItemPrivate *itemPrivate = QSGItemPrivate::get(item);
+ itemPrivate->addItemChangeListener(this, QSGItemPrivate::Geometry);
+ }
+ requestedIndex = -1;
+ return item;
+}
+
+void QSGPathViewPrivate::releaseItem(QSGItem *item)
+{
+ if (!item || !model)
+ return;
+ QSGItemPrivate *itemPrivate = QSGItemPrivate::get(item);
+ itemPrivate->removeItemChangeListener(this, QSGItemPrivate::Geometry);
+ if (model->release(item) == 0) {
+ // item was not destroyed, and we no longer reference it.
+ if (QSGPathViewAttached *att = attached(item))
+ att->setOnPath(false);
+ }
+}
+
+QSGPathViewAttached *QSGPathViewPrivate::attached(QSGItem *item)
+{
+ return static_cast<QSGPathViewAttached *>(qmlAttachedPropertiesObject<QSGPathView>(item, false));
+}
+
+void QSGPathViewPrivate::clear()
+{
+ for (int i=0; i<items.count(); i++){
+ QSGItem *p = items[i];
+ releaseItem(p);
+ }
+ items.clear();
+}
+
+void QSGPathViewPrivate::updateMappedRange()
+{
+ if (model && pathItems != -1 && pathItems < modelCount)
+ mappedRange = qreal(pathItems)/modelCount;
+ else
+ mappedRange = 1.0;
+}
+
+qreal QSGPathViewPrivate::positionOfIndex(qreal index) const
+{
+ qreal pos = -1.0;
+
+ if (model && index >= 0 && index < modelCount) {
+ qreal start = 0.0;
+ if (haveHighlightRange && highlightRangeMode != QSGPathView::NoHighlightRange)
+ start = highlightRangeStart;
+ qreal globalPos = index + offset;
+ globalPos = qmlMod(globalPos, qreal(modelCount)) / modelCount;
+ if (pathItems != -1 && pathItems < modelCount) {
+ globalPos += start * mappedRange;
+ globalPos = qmlMod(globalPos, 1.0);
+ if (globalPos < mappedRange)
+ pos = globalPos / mappedRange;
+ } else {
+ pos = qmlMod(globalPos + start, 1.0);
+ }
+ }
+
+ return pos;
+}
+
+void QSGPathViewPrivate::createHighlight()
+{
+ Q_Q(QSGPathView);
+ if (!q->isComponentComplete())
+ return;
+
+ bool changed = false;
+ if (highlightItem) {
+ highlightItem->setParentItem(0);
+ highlightItem->deleteLater();
+ highlightItem = 0;
+ changed = true;
+ }
+
+ QSGItem *item = 0;
+ if (highlightComponent) {
+ QDeclarativeContext *highlightContext = new QDeclarativeContext(qmlContext(q));
+ QObject *nobj = highlightComponent->create(highlightContext);
+ if (nobj) {
+ QDeclarative_setParent_noEvent(highlightContext, nobj);
+ item = qobject_cast<QSGItem *>(nobj);
+ if (!item)
+ delete nobj;
+ } else {
+ delete highlightContext;
+ }
+ } else {
+ item = new QSGItem;
+ }
+ if (item) {
+ QDeclarative_setParent_noEvent(item, q);
+ item->setParentItem(q);
+ highlightItem = item;
+ changed = true;
+ }
+ if (changed)
+ emit q->highlightItemChanged();
+}
+
+void QSGPathViewPrivate::updateHighlight()
+{
+ Q_Q(QSGPathView);
+ if (!q->isComponentComplete() || !isValid())
+ return;
+ if (highlightItem) {
+ if (haveHighlightRange && highlightRangeMode == QSGPathView::StrictlyEnforceRange) {
+ updateItem(highlightItem, highlightRangeStart);
+ } else {
+ qreal target = currentIndex;
+
+ offsetAdj = 0.0;
+ tl.reset(moveHighlight);
+ moveHighlight.setValue(highlightPosition);
+
+ const int duration = highlightMoveDuration;
+
+ if (target - highlightPosition > modelCount/2) {
+ highlightUp = false;
+ qreal distance = modelCount - target + highlightPosition;
+ tl.move(moveHighlight, 0.0, QEasingCurve(QEasingCurve::InQuad), int(duration * highlightPosition / distance));
+ tl.set(moveHighlight, modelCount-0.01);
+ tl.move(moveHighlight, target, QEasingCurve(QEasingCurve::OutQuad), int(duration * (modelCount-target) / distance));
+ } else if (target - highlightPosition <= -modelCount/2) {
+ highlightUp = true;
+ qreal distance = modelCount - highlightPosition + target;
+ tl.move(moveHighlight, modelCount-0.01, QEasingCurve(QEasingCurve::InQuad), int(duration * (modelCount-highlightPosition) / distance));
+ tl.set(moveHighlight, 0.0);
+ tl.move(moveHighlight, target, QEasingCurve(QEasingCurve::OutQuad), int(duration * target / distance));
+ } else {
+ highlightUp = highlightPosition - target < 0;
+ tl.move(moveHighlight, target, QEasingCurve(QEasingCurve::InOutQuad), duration);
+ }
+ }
+ }
+}
+
+void QSGPathViewPrivate::setHighlightPosition(qreal pos)
+{
+ if (pos != highlightPosition) {
+ qreal start = 0.0;
+ qreal end = 1.0;
+ if (haveHighlightRange && highlightRangeMode != QSGPathView::NoHighlightRange) {
+ start = highlightRangeStart;
+ end = highlightRangeEnd;
+ }
+
+ qreal range = qreal(modelCount);
+ // calc normalized position of highlight relative to offset
+ qreal relativeHighlight = qmlMod(pos + offset, range) / range;
+
+ if (!highlightUp && relativeHighlight > end * mappedRange) {
+ qreal diff = 1.0 - relativeHighlight;
+ setOffset(offset + diff * range);
+ } else if (highlightUp && relativeHighlight >= (end - start) * mappedRange) {
+ qreal diff = relativeHighlight - (end - start) * mappedRange;
+ setOffset(offset - diff * range - 0.00001);
+ }
+
+ highlightPosition = pos;
+ qreal pathPos = positionOfIndex(pos);
+ updateItem(highlightItem, pathPos);
+ if (QSGPathViewAttached *att = attached(highlightItem))
+ att->setOnPath(pathPos != -1.0);
+ }
+}
+
+void QSGPathView::pathUpdated()
+{
+ Q_D(QSGPathView);
+ QList<QSGItem*>::iterator it = d->items.begin();
+ while (it != d->items.end()) {
+ QSGItem *item = *it;
+ if (QSGPathViewAttached *att = d->attached(item))
+ att->m_percent = -1;
+ ++it;
+ }
+ refill();
+}
+
+void QSGPathViewPrivate::updateItem(QSGItem *item, qreal percent)
+{
+ if (QSGPathViewAttached *att = attached(item)) {
+ if (qFuzzyCompare(att->m_percent, percent))
+ return;
+ att->m_percent = percent;
+ foreach(const QString &attr, path->attributes())
+ att->setValue(attr.toUtf8(), path->attributeAt(attr, percent));
+ }
+ QPointF pf = path->pointAt(percent);
+ item->setX(qRound(pf.x() - item->width()/2));
+ item->setY(qRound(pf.y() - item->height()/2));
+}
+
+void QSGPathViewPrivate::regenerate()
+{
+ Q_Q(QSGPathView);
+ if (!q->isComponentComplete())
+ return;
+
+ clear();
+
+ if (!isValid())
+ return;
+
+ firstIndex = -1;
+ updateMappedRange();
+ q->refill();
+}
+
+QSGPathView::QSGPathView(QSGItem *parent)
+ : QSGItem(*(new QSGPathViewPrivate), parent)
+{
+ Q_D(QSGPathView);
+ d->init();
+}
+
+QSGPathView::~QSGPathView()
+{
+ Q_D(QSGPathView);
+ d->clear();
+ if (d->attType)
+ d->attType->release();
+ if (d->ownModel)
+ delete d->model;
+}
+
+QVariant QSGPathView::model() const
+{
+ Q_D(const QSGPathView);
+ return d->modelVariant;
+}
+
+void QSGPathView::setModel(const QVariant &model)
+{
+ Q_D(QSGPathView);
+ if (d->modelVariant == model)
+ return;
+
+ if (d->model) {
+ disconnect(d->model, SIGNAL(itemsInserted(int,int)), this, SLOT(itemsInserted(int,int)));
+ disconnect(d->model, SIGNAL(itemsRemoved(int,int)), this, SLOT(itemsRemoved(int,int)));
+ disconnect(d->model, SIGNAL(itemsMoved(int,int,int)), this, SLOT(itemsMoved(int,int,int)));
+ disconnect(d->model, SIGNAL(modelReset()), this, SLOT(modelReset()));
+ disconnect(d->model, SIGNAL(createdItem(int,QSGItem*)), this, SLOT(createdItem(int,QSGItem*)));
+ for (int i=0; i<d->items.count(); i++){
+ QSGItem *p = d->items[i];
+ d->model->release(p);
+ }
+ d->items.clear();
+ }
+
+ d->modelVariant = model;
+ QObject *object = qvariant_cast<QObject*>(model);
+ QSGVisualModel *vim = 0;
+ if (object && (vim = qobject_cast<QSGVisualModel *>(object))) {
+ if (d->ownModel) {
+ delete d->model;
+ d->ownModel = false;
+ }
+ d->model = vim;
+ } else {
+ if (!d->ownModel) {
+ d->model = new QSGVisualDataModel(qmlContext(this), this);
+ d->ownModel = true;
+ }
+ if (QSGVisualDataModel *dataModel = qobject_cast<QSGVisualDataModel*>(d->model))
+ dataModel->setModel(model);
+ }
+ d->modelCount = 0;
+ if (d->model) {
+ connect(d->model, SIGNAL(itemsInserted(int,int)), this, SLOT(itemsInserted(int,int)));
+ connect(d->model, SIGNAL(itemsRemoved(int,int)), this, SLOT(itemsRemoved(int,int)));
+ connect(d->model, SIGNAL(itemsMoved(int,int,int)), this, SLOT(itemsMoved(int,int,int)));
+ connect(d->model, SIGNAL(modelReset()), this, SLOT(modelReset()));
+ connect(d->model, SIGNAL(createdItem(int,QSGItem*)), this, SLOT(createdItem(int,QSGItem*)));
+ d->modelCount = d->model->count();
+ if (d->model->count())
+ d->offset = qmlMod(d->offset, qreal(d->model->count()));
+ if (d->offset < 0)
+ d->offset = d->model->count() + d->offset;
+}
+ d->regenerate();
+ d->fixOffset();
+ emit countChanged();
+ emit modelChanged();
+}
+
+int QSGPathView::count() const
+{
+ Q_D(const QSGPathView);
+ return d->model ? d->modelCount : 0;
+}
+
+QDeclarativePath *QSGPathView::path() const
+{
+ Q_D(const QSGPathView);
+ return d->path;
+}
+
+void QSGPathView::setPath(QDeclarativePath *path)
+{
+ Q_D(QSGPathView);
+ if (d->path == path)
+ return;
+ if (d->path)
+ disconnect(d->path, SIGNAL(changed()), this, SLOT(pathUpdated()));
+ d->path = path;
+ connect(d->path, SIGNAL(changed()), this, SLOT(pathUpdated()));
+ if (d->isValid() && isComponentComplete()) {
+ d->clear();
+ if (d->attType) {
+ d->attType->release();
+ d->attType = 0;
+ }
+ d->regenerate();
+ }
+ emit pathChanged();
+}
+
+int QSGPathView::currentIndex() const
+{
+ Q_D(const QSGPathView);
+ return d->currentIndex;
+}
+
+void QSGPathView::setCurrentIndex(int idx)
+{
+ Q_D(QSGPathView);
+ if (d->model && d->modelCount)
+ idx = qAbs(idx % d->modelCount);
+ if (d->model && idx != d->currentIndex) {
+ if (d->modelCount) {
+ int itemIndex = (d->currentIndex - d->firstIndex + d->modelCount) % d->modelCount;
+ if (itemIndex < d->items.count()) {
+ if (QSGItem *item = d->items.at(itemIndex)) {
+ if (QSGPathViewAttached *att = d->attached(item))
+ att->setIsCurrentItem(false);
+ }
+ }
+ }
+ d->currentItem = 0;
+ d->moveReason = QSGPathViewPrivate::SetIndex;
+ d->currentIndex = idx;
+ if (d->modelCount) {
+ if (d->haveHighlightRange && d->highlightRangeMode == QSGPathView::StrictlyEnforceRange)
+ d->snapToCurrent();
+ int itemIndex = (idx - d->firstIndex + d->modelCount) % d->modelCount;
+ if (itemIndex < d->items.count()) {
+ d->currentItem = d->items.at(itemIndex);
+ d->currentItem->setFocus(true);
+ if (QSGPathViewAttached *att = d->attached(d->currentItem))
+ att->setIsCurrentItem(true);
+ }
+ d->currentItemOffset = d->positionOfIndex(d->currentIndex);
+ d->updateHighlight();
+ }
+ emit currentIndexChanged();
+ }
+}
+
+void QSGPathView::incrementCurrentIndex()
+{
+ Q_D(QSGPathView);
+ d->moveDirection = QSGPathViewPrivate::Positive;
+ setCurrentIndex(currentIndex()+1);
+}
+
+void QSGPathView::decrementCurrentIndex()
+{
+ Q_D(QSGPathView);
+ if (d->model && d->modelCount) {
+ int idx = currentIndex()-1;
+ if (idx < 0)
+ idx = d->modelCount - 1;
+ d->moveDirection = QSGPathViewPrivate::Negative;
+ setCurrentIndex(idx);
+ }
+}
+
+qreal QSGPathView::offset() const
+{
+ Q_D(const QSGPathView);
+ return d->offset;
+}
+
+void QSGPathView::setOffset(qreal offset)
+{
+ Q_D(QSGPathView);
+ d->setOffset(offset);
+ d->updateCurrent();
+}
+
+void QSGPathViewPrivate::setOffset(qreal o)
+{
+ Q_Q(QSGPathView);
+ if (offset != o) {
+ if (isValid() && q->isComponentComplete()) {
+ offset = qmlMod(o, qreal(modelCount));
+ if (offset < 0)
+ offset += qreal(modelCount);
+ q->refill();
+ } else {
+ offset = o;
+ }
+ emit q->offsetChanged();
+ }
+}
+
+void QSGPathViewPrivate::setAdjustedOffset(qreal o)
+{
+ setOffset(o+offsetAdj);
+}
+
+QDeclarativeComponent *QSGPathView::highlight() const
+{
+ Q_D(const QSGPathView);
+ return d->highlightComponent;
+}
+
+void QSGPathView::setHighlight(QDeclarativeComponent *highlight)
+{
+ Q_D(QSGPathView);
+ if (highlight != d->highlightComponent) {
+ d->highlightComponent = highlight;
+ d->createHighlight();
+ d->updateHighlight();
+ emit highlightChanged();
+ }
+}
+
+QSGItem *QSGPathView::highlightItem()
+{
+ Q_D(const QSGPathView);
+ return d->highlightItem;
+}
+
+qreal QSGPathView::preferredHighlightBegin() const
+{
+ Q_D(const QSGPathView);
+ return d->highlightRangeStart;
+}
+
+void QSGPathView::setPreferredHighlightBegin(qreal start)
+{
+ Q_D(QSGPathView);
+ if (d->highlightRangeStart == start || start < 0 || start > 1.0)
+ return;
+ d->highlightRangeStart = start;
+ d->haveHighlightRange = d->highlightRangeMode != NoHighlightRange && d->highlightRangeStart <= d->highlightRangeEnd;
+ refill();
+ emit preferredHighlightBeginChanged();
+}
+
+qreal QSGPathView::preferredHighlightEnd() const
+{
+ Q_D(const QSGPathView);
+ return d->highlightRangeEnd;
+}
+
+void QSGPathView::setPreferredHighlightEnd(qreal end)
+{
+ Q_D(QSGPathView);
+ if (d->highlightRangeEnd == end || end < 0 || end > 1.0)
+ return;
+ d->highlightRangeEnd = end;
+ d->haveHighlightRange = d->highlightRangeMode != NoHighlightRange && d->highlightRangeStart <= d->highlightRangeEnd;
+ refill();
+ emit preferredHighlightEndChanged();
+}
+
+QSGPathView::HighlightRangeMode QSGPathView::highlightRangeMode() const
+{
+ Q_D(const QSGPathView);
+ return d->highlightRangeMode;
+}
+
+void QSGPathView::setHighlightRangeMode(HighlightRangeMode mode)
+{
+ Q_D(QSGPathView);
+ if (d->highlightRangeMode == mode)
+ return;
+ d->highlightRangeMode = mode;
+ d->haveHighlightRange = d->highlightRangeMode != NoHighlightRange && d->highlightRangeStart <= d->highlightRangeEnd;
+ emit highlightRangeModeChanged();
+}
+
+int QSGPathView::highlightMoveDuration() const
+{
+ Q_D(const QSGPathView);
+ return d->highlightMoveDuration;
+}
+
+void QSGPathView::setHighlightMoveDuration(int duration)
+{
+ Q_D(QSGPathView);
+ if (d->highlightMoveDuration == duration)
+ return;
+ d->highlightMoveDuration = duration;
+ emit highlightMoveDurationChanged();
+}
+
+qreal QSGPathView::dragMargin() const
+{
+ Q_D(const QSGPathView);
+ return d->dragMargin;
+}
+
+void QSGPathView::setDragMargin(qreal dragMargin)
+{
+ Q_D(QSGPathView);
+ if (d->dragMargin == dragMargin)
+ return;
+ d->dragMargin = dragMargin;
+ emit dragMarginChanged();
+}
+
+qreal QSGPathView::flickDeceleration() const
+{
+ Q_D(const QSGPathView);
+ return d->deceleration;
+}
+
+void QSGPathView::setFlickDeceleration(qreal dec)
+{
+ Q_D(QSGPathView);
+ if (d->deceleration == dec)
+ return;
+ d->deceleration = dec;
+ emit flickDecelerationChanged();
+}
+
+bool QSGPathView::isInteractive() const
+{
+ Q_D(const QSGPathView);
+ return d->interactive;
+}
+
+void QSGPathView::setInteractive(bool interactive)
+{
+ Q_D(QSGPathView);
+ if (interactive != d->interactive) {
+ d->interactive = interactive;
+ if (!interactive)
+ d->tl.clear();
+ emit interactiveChanged();
+ }
+}
+
+bool QSGPathView::isMoving() const
+{
+ Q_D(const QSGPathView);
+ return d->moving;
+}
+
+bool QSGPathView::isFlicking() const
+{
+ Q_D(const QSGPathView);
+ return d->flicking;
+}
+
+QDeclarativeComponent *QSGPathView::delegate() const
+{
+ Q_D(const QSGPathView);
+ if (d->model) {
+ if (QSGVisualDataModel *dataModel = qobject_cast<QSGVisualDataModel*>(d->model))
+ return dataModel->delegate();
+ }
+
+ return 0;
+}
+
+void QSGPathView::setDelegate(QDeclarativeComponent *delegate)
+{
+ Q_D(QSGPathView);
+ if (delegate == this->delegate())
+ return;
+ if (!d->ownModel) {
+ d->model = new QSGVisualDataModel(qmlContext(this));
+ d->ownModel = true;
+ }
+ if (QSGVisualDataModel *dataModel = qobject_cast<QSGVisualDataModel*>(d->model)) {
+ int oldCount = dataModel->count();
+ dataModel->setDelegate(delegate);
+ d->modelCount = dataModel->count();
+ d->regenerate();
+ if (oldCount != dataModel->count())
+ emit countChanged();
+ emit delegateChanged();
+ }
+}
+
+int QSGPathView::pathItemCount() const
+{
+ Q_D(const QSGPathView);
+ return d->pathItems;
+}
+
+void QSGPathView::setPathItemCount(int i)
+{
+ Q_D(QSGPathView);
+ if (i == d->pathItems)
+ return;
+ if (i < 1)
+ i = 1;
+ d->pathItems = i;
+ d->updateMappedRange();
+ if (d->isValid() && isComponentComplete()) {
+ d->regenerate();
+ }
+ emit pathItemCountChanged();
+}
+
+QPointF QSGPathViewPrivate::pointNear(const QPointF &point, qreal *nearPercent) const
+{
+ //XXX maybe do recursively at increasing resolution.
+ qreal mindist = 1e10; // big number
+ QPointF nearPoint = path->pointAt(0);
+ qreal nearPc = 0;
+ for (qreal i=1; i < 1000; i++) {
+ QPointF pt = path->pointAt(i/1000.0);
+ QPointF diff = pt - point;
+ qreal dist = diff.x()*diff.x() + diff.y()*diff.y();
+ if (dist < mindist) {
+ nearPoint = pt;
+ nearPc = i;
+ mindist = dist;
+ }
+ }
+
+ if (nearPercent)
+ *nearPercent = nearPc / 1000.0;
+
+ return nearPoint;
+}
+
+void QSGPathView::mousePressEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(QSGPathView);
+ if (d->interactive) {
+ d->handleMousePressEvent(event);
+ event->accept();
+ } else {
+ QSGItem::mousePressEvent(event);
+ }
+}
+
+void QSGPathViewPrivate::handleMousePressEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_Q(QSGPathView);
+ if (!interactive || !items.count())
+ return;
+ QPointF scenePoint = q->mapToScene(event->pos());
+ int idx = 0;
+ for (; idx < items.count(); ++idx) {
+ QRectF rect = items.at(idx)->boundingRect();
+ rect = items.at(idx)->mapRectToScene(rect);
+ if (rect.contains(scenePoint))
+ break;
+ }
+ if (idx == items.count() && dragMargin == 0.) // didn't click on an item
+ return;
+
+ startPoint = pointNear(event->pos(), &startPc);
+ if (idx == items.count()) {
+ qreal distance = qAbs(event->pos().x() - startPoint.x()) + qAbs(event->pos().y() - startPoint.y());
+ if (distance > dragMargin)
+ return;
+ }
+
+ if (tl.isActive() && flicking)
+ stealMouse = true; // If we've been flicked then steal the click.
+ else
+ stealMouse = false;
+
+ lastElapsed = 0;
+ lastDist = 0;
+ QSGItemPrivate::start(lastPosTime);
+ tl.clear();
+}
+
+void QSGPathView::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(QSGPathView);
+ if (d->interactive) {
+ d->handleMouseMoveEvent(event);
+ if (d->stealMouse)
+ setKeepMouseGrab(true);
+ event->accept();
+ } else {
+ QSGItem::mouseMoveEvent(event);
+ }
+}
+
+void QSGPathViewPrivate::handleMouseMoveEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_Q(QSGPathView);
+ if (!interactive || !lastPosTime.isValid())
+ return;
+
+ qreal newPc;
+ QPointF pathPoint = pointNear(event->pos(), &newPc);
+ if (!stealMouse) {
+ QPointF delta = pathPoint - startPoint;
+ if (qAbs(delta.x()) > QApplication::startDragDistance() || qAbs(delta.y()) > QApplication::startDragDistance()) {
+ stealMouse = true;
+ startPc = newPc;
+ }
+ }
+
+ if (stealMouse) {
+ moveReason = QSGPathViewPrivate::Mouse;
+ qreal diff = (newPc - startPc)*modelCount*mappedRange;
+ if (diff) {
+ q->setOffset(offset + diff);
+
+ if (diff > modelCount/2)
+ diff -= modelCount;
+ else if (diff < -modelCount/2)
+ diff += modelCount;
+
+ lastElapsed = QSGItemPrivate::restart(lastPosTime);
+ lastDist = diff;
+ startPc = newPc;
+ }
+ if (!moving) {
+ moving = true;
+ emit q->movingChanged();
+ emit q->movementStarted();
+ }
+ }
+}
+
+void QSGPathView::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(QSGPathView);
+ if (d->interactive) {
+ d->handleMouseReleaseEvent(event);
+ event->accept();
+ ungrabMouse();
+ } else {
+ QSGItem::mouseReleaseEvent(event);
+ }
+}
+
+void QSGPathViewPrivate::handleMouseReleaseEvent(QGraphicsSceneMouseEvent *)
+{
+ Q_Q(QSGPathView);
+ stealMouse = false;
+ q->setKeepMouseGrab(false);
+ if (!interactive || !lastPosTime.isValid())
+ return;
+
+ qreal elapsed = qreal(lastElapsed + QSGItemPrivate::elapsed(lastPosTime)) / 1000.;
+ qreal velocity = elapsed > 0. ? lastDist / elapsed : 0;
+ if (model && modelCount && qAbs(velocity) > 1.) {
+ qreal count = pathItems == -1 ? modelCount : pathItems;
+ if (qAbs(velocity) > count * 2) // limit velocity
+ velocity = (velocity > 0 ? count : -count) * 2;
+ // Calculate the distance to be travelled
+ qreal v2 = velocity*velocity;
+ qreal accel = deceleration/10;
+ // + 0.25 to encourage moving at least one item in the flick direction
+ qreal dist = qMin(qreal(modelCount-1), qreal(v2 / (accel * 2.0) + 0.25));
+ if (haveHighlightRange && highlightRangeMode == QSGPathView::StrictlyEnforceRange) {
+ // round to nearest item.
+ if (velocity > 0.)
+ dist = qRound(dist + offset) - offset;
+ else
+ dist = qRound(dist - offset) + offset;
+ // Calculate accel required to stop on item boundary
+ if (dist <= 0.) {
+ dist = 0.;
+ accel = 0.;
+ } else {
+ accel = v2 / (2.0f * qAbs(dist));
+ }
+ }
+ offsetAdj = 0.0;
+ moveOffset.setValue(offset);
+ tl.accel(moveOffset, velocity, accel, dist);
+ tl.callback(QDeclarativeTimeLineCallback(&moveOffset, fixOffsetCallback, this));
+ if (!flicking) {
+ flicking = true;
+ emit q->flickingChanged();
+ emit q->flickStarted();
+ }
+ } else {
+ fixOffset();
+ }
+
+ lastPosTime.invalidate();
+ if (!tl.isActive())
+ q->movementEnding();
+}
+
+bool QSGPathView::sendMouseEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(QSGPathView);
+ QGraphicsSceneMouseEvent mouseEvent(event->type());
+ QRectF myRect = mapRectToScene(QRectF(0, 0, width(), height()));
+ QSGCanvas *c = canvas();
+ QSGItem *grabber = c ? c->mouseGrabberItem() : 0;
+ bool stealThisEvent = d->stealMouse;
+ if ((stealThisEvent || myRect.contains(event->scenePos().toPoint())) && (!grabber || !grabber->keepMouseGrab())) {
+ mouseEvent.setAccepted(false);
+ for (int i = 0x1; i <= 0x10; i <<= 1) {
+ if (event->buttons() & i) {
+ Qt::MouseButton button = Qt::MouseButton(i);
+ mouseEvent.setButtonDownPos(button, mapFromScene(event->buttonDownPos(button)));
+ }
+ }
+ mouseEvent.setScenePos(event->scenePos());
+ mouseEvent.setLastScenePos(event->lastScenePos());
+ mouseEvent.setPos(mapFromScene(event->scenePos()));
+ mouseEvent.setLastPos(mapFromScene(event->lastScenePos()));
+
+ switch(mouseEvent.type()) {
+ case QEvent::GraphicsSceneMouseMove:
+ d->handleMouseMoveEvent(&mouseEvent);
+ break;
+ case QEvent::GraphicsSceneMousePress:
+ d->handleMousePressEvent(&mouseEvent);
+ stealThisEvent = d->stealMouse; // Update stealThisEvent in case changed by function call above
+ break;
+ case QEvent::GraphicsSceneMouseRelease:
+ d->handleMouseReleaseEvent(&mouseEvent);
+ break;
+ default:
+ break;
+ }
+ grabber = c->mouseGrabberItem();
+ if (grabber && stealThisEvent && !grabber->keepMouseGrab() && grabber != this)
+ grabMouse();
+
+ return d->stealMouse;
+ } else if (d->lastPosTime.isValid()) {
+ d->lastPosTime.invalidate();
+ }
+ if (mouseEvent.type() == QEvent::GraphicsSceneMouseRelease)
+ d->stealMouse = false;
+ return false;
+}
+
+bool QSGPathView::childMouseEventFilter(QSGItem *i, QEvent *e)
+{
+ Q_D(QSGPathView);
+ if (!isVisible() || !d->interactive)
+ return QSGItem::childMouseEventFilter(i, e);
+
+ switch (e->type()) {
+ case QEvent::GraphicsSceneMousePress:
+ case QEvent::GraphicsSceneMouseMove:
+ case QEvent::GraphicsSceneMouseRelease:
+ return sendMouseEvent(static_cast<QGraphicsSceneMouseEvent *>(e));
+ default:
+ break;
+ }
+
+ return QSGItem::childMouseEventFilter(i, e);
+}
+
+void QSGPathView::updatePolish()
+{
+ QSGItem::updatePolish();
+ refill();
+}
+
+void QSGPathView::componentComplete()
+{
+ Q_D(QSGPathView);
+ QSGItem::componentComplete();
+ d->createHighlight();
+ // It is possible that a refill has already happended to to Path
+ // bindings being handled in the componentComplete(). If so
+ // don't do it again.
+ if (d->items.count() == 0 && d->model) {
+ d->modelCount = d->model->count();
+ d->regenerate();
+ }
+ d->updateHighlight();
+}
+
+void QSGPathView::refill()
+{
+ Q_D(QSGPathView);
+ if (!d->isValid() || !isComponentComplete())
+ return;
+
+ d->layoutScheduled = false;
+ bool currentVisible = false;
+
+ // first move existing items and remove items off path
+ int idx = d->firstIndex;
+ QList<QSGItem*>::iterator it = d->items.begin();
+ while (it != d->items.end()) {
+ qreal pos = d->positionOfIndex(idx);
+ QSGItem *item = *it;
+ if (pos >= 0.0) {
+ d->updateItem(item, pos);
+ if (idx == d->currentIndex) {
+ currentVisible = true;
+ d->currentItemOffset = pos;
+ }
+ ++it;
+ } else {
+// qDebug() << "release";
+ d->updateItem(item, 1.0);
+ d->releaseItem(item);
+ if (it == d->items.begin()) {
+ if (++d->firstIndex >= d->modelCount)
+ d->firstIndex = 0;
+ }
+ it = d->items.erase(it);
+ }
+ ++idx;
+ if (idx >= d->modelCount)
+ idx = 0;
+ }
+ if (!d->items.count())
+ d->firstIndex = -1;
+
+ if (d->modelCount) {
+ // add items to beginning and end
+ int count = d->pathItems == -1 ? d->modelCount : qMin(d->pathItems, d->modelCount);
+ if (d->items.count() < count) {
+ int idx = qRound(d->modelCount - d->offset) % d->modelCount;
+ qreal startPos = 0.0;
+ if (d->haveHighlightRange && d->highlightRangeMode != QSGPathView::NoHighlightRange)
+ startPos = d->highlightRangeStart;
+ if (d->firstIndex >= 0) {
+ startPos = d->positionOfIndex(d->firstIndex);
+ idx = (d->firstIndex + d->items.count()) % d->modelCount;
+ }
+ qreal pos = d->positionOfIndex(idx);
+ while ((pos > startPos || !d->items.count()) && d->items.count() < count) {
+ // qDebug() << "append" << idx;
+ QSGItem *item = d->getItem(idx);
+ if (d->model->completePending())
+ item->setZ(idx+1);
+ if (d->currentIndex == idx) {
+ item->setFocus(true);
+ if (QSGPathViewAttached *att = d->attached(item))
+ att->setIsCurrentItem(true);
+ currentVisible = true;
+ d->currentItemOffset = pos;
+ d->currentItem = item;
+ }
+ if (d->items.count() == 0)
+ d->firstIndex = idx;
+ d->items.append(item);
+ d->updateItem(item, pos);
+ if (d->model->completePending())
+ d->model->completeItem();
+ ++idx;
+ if (idx >= d->modelCount)
+ idx = 0;
+ pos = d->positionOfIndex(idx);
+ }
+
+ idx = d->firstIndex - 1;
+ if (idx < 0)
+ idx = d->modelCount - 1;
+ pos = d->positionOfIndex(idx);
+ while (pos >= 0.0 && pos < startPos) {
+ // qDebug() << "prepend" << idx;
+ QSGItem *item = d->getItem(idx);
+ if (d->model->completePending())
+ item->setZ(idx+1);
+ if (d->currentIndex == idx) {
+ item->setFocus(true);
+ if (QSGPathViewAttached *att = d->attached(item))
+ att->setIsCurrentItem(true);
+ currentVisible = true;
+ d->currentItemOffset = pos;
+ d->currentItem = item;
+ }
+ d->items.prepend(item);
+ d->updateItem(item, pos);
+ if (d->model->completePending())
+ d->model->completeItem();
+ d->firstIndex = idx;
+ idx = d->firstIndex - 1;
+ if (idx < 0)
+ idx = d->modelCount - 1;
+ pos = d->positionOfIndex(idx);
+ }
+ }
+ }
+
+ if (!currentVisible)
+ d->currentItemOffset = 1.0;
+
+ if (d->highlightItem && d->haveHighlightRange && d->highlightRangeMode == QSGPathView::StrictlyEnforceRange) {
+ d->updateItem(d->highlightItem, d->highlightRangeStart);
+ if (QSGPathViewAttached *att = d->attached(d->highlightItem))
+ att->setOnPath(true);
+ } else if (d->highlightItem && d->moveReason != QSGPathViewPrivate::SetIndex) {
+ d->updateItem(d->highlightItem, d->currentItemOffset);
+ if (QSGPathViewAttached *att = d->attached(d->highlightItem))
+ att->setOnPath(currentVisible);
+ }
+ while (d->itemCache.count())
+ d->releaseItem(d->itemCache.takeLast());
+}
+
+void QSGPathView::itemsInserted(int modelIndex, int count)
+{
+ //XXX support animated insertion
+ Q_D(QSGPathView);
+ if (!d->isValid() || !isComponentComplete())
+ return;
+
+ if (d->modelCount) {
+ d->itemCache += d->items;
+ d->items.clear();
+ if (modelIndex <= d->currentIndex) {
+ d->currentIndex += count;
+ emit currentIndexChanged();
+ } else if (d->offset != 0) {
+ d->offset += count;
+ d->offsetAdj += count;
+ }
+ }
+
+ d->modelCount += count;
+ if (d->flicking || d->moving) {
+ d->regenerate();
+ d->updateCurrent();
+ } else {
+ d->firstIndex = -1;
+ d->updateMappedRange();
+ d->scheduleLayout();
+ }
+ emit countChanged();
+}
+
+void QSGPathView::itemsRemoved(int modelIndex, int count)
+{
+ //XXX support animated removal
+ Q_D(QSGPathView);
+ if (!d->model || !d->modelCount || !d->model->isValid() || !d->path || !isComponentComplete())
+ return;
+
+ // fix current
+ bool currentChanged = false;
+ if (d->currentIndex >= modelIndex + count) {
+ d->currentIndex -= count;
+ currentChanged = true;
+ } else if (d->currentIndex >= modelIndex && d->currentIndex < modelIndex + count) {
+ // current item has been removed.
+ d->currentIndex = qMin(modelIndex, d->modelCount-count-1);
+ if (d->currentItem) {
+ if (QSGPathViewAttached *att = d->attached(d->currentItem))
+ att->setIsCurrentItem(true);
+ }
+ currentChanged = true;
+ }
+
+ d->itemCache += d->items;
+ d->items.clear();
+
+ bool changedOffset = false;
+ if (modelIndex > d->currentIndex) {
+ if (d->offset >= count) {
+ changedOffset = true;
+ d->offset -= count;
+ d->offsetAdj -= count;
+ }
+ }
+
+ d->modelCount -= count;
+ if (!d->modelCount) {
+ while (d->itemCache.count())
+ d->releaseItem(d->itemCache.takeLast());
+ d->offset = 0;
+ changedOffset = true;
+ d->tl.reset(d->moveOffset);
+ } else {
+ d->regenerate();
+ d->updateCurrent();
+ if (!d->flicking && !d->moving && d->haveHighlightRange && d->highlightRangeMode == QSGPathView::StrictlyEnforceRange)
+ d->snapToCurrent();
+ }
+ if (changedOffset)
+ emit offsetChanged();
+ if (currentChanged)
+ emit currentIndexChanged();
+ emit countChanged();
+}
+
+void QSGPathView::itemsMoved(int /*from*/, int /*to*/, int /*count*/)
+{
+ Q_D(QSGPathView);
+ if (!d->isValid() || !isComponentComplete())
+ return;
+
+ QList<QSGItem *> removedItems = d->items;
+ d->items.clear();
+ d->regenerate();
+ while (removedItems.count())
+ d->releaseItem(removedItems.takeLast());
+
+ // Fix current index
+ if (d->currentIndex >= 0 && d->currentItem) {
+ int oldCurrent = d->currentIndex;
+ d->currentIndex = d->model->indexOf(d->currentItem, this);
+ if (oldCurrent != d->currentIndex)
+ emit currentIndexChanged();
+ }
+ d->updateCurrent();
+}
+
+void QSGPathView::modelReset()
+{
+ Q_D(QSGPathView);
+ d->modelCount = d->model->count();
+ d->regenerate();
+ emit countChanged();
+}
+
+void QSGPathView::createdItem(int index, QSGItem *item)
+{
+ Q_D(QSGPathView);
+ if (d->requestedIndex != index) {
+ if (!d->attType) {
+ // pre-create one metatype to share with all attached objects
+ d->attType = new QDeclarativeOpenMetaObjectType(&QSGPathViewAttached::staticMetaObject, qmlEngine(this));
+ foreach(const QString &attr, d->path->attributes())
+ d->attType->createProperty(attr.toUtf8());
+ }
+ qPathViewAttachedType = d->attType;
+ QSGPathViewAttached *att = static_cast<QSGPathViewAttached *>(qmlAttachedPropertiesObject<QSGPathView>(item));
+ qPathViewAttachedType = 0;
+ if (att) {
+ att->m_view = this;
+ att->setOnPath(false);
+ }
+ item->setParentItem(this);
+ d->updateItem(item, index < d->firstIndex ? 0.0 : 1.0);
+ }
+}
+
+void QSGPathView::destroyingItem(QSGItem *item)
+{
+ Q_UNUSED(item);
+}
+
+void QSGPathView::ticked()
+{
+ Q_D(QSGPathView);
+ d->updateCurrent();
+}
+
+void QSGPathView::movementEnding()
+{
+ Q_D(QSGPathView);
+ if (d->flicking) {
+ d->flicking = false;
+ emit flickingChanged();
+ emit flickEnded();
+ }
+ if (d->moving && !d->stealMouse) {
+ d->moving = false;
+ emit movingChanged();
+ emit movementEnded();
+ }
+}
+
+// find the item closest to the snap position
+int QSGPathViewPrivate::calcCurrentIndex()
+{
+ int current = -1;
+ if (modelCount && model && items.count()) {
+ offset = qmlMod(offset, modelCount);
+ if (offset < 0)
+ offset += modelCount;
+ current = qRound(qAbs(qmlMod(modelCount - offset, modelCount)));
+ current = current % modelCount;
+ }
+
+ return current;
+}
+
+void QSGPathViewPrivate::updateCurrent()
+{
+ Q_Q(QSGPathView);
+ if (moveReason != Mouse)
+ return;
+ if (!modelCount || !haveHighlightRange || highlightRangeMode != QSGPathView::StrictlyEnforceRange)
+ return;
+
+ int idx = calcCurrentIndex();
+ if (model && idx != currentIndex) {
+ int itemIndex = (currentIndex - firstIndex + modelCount) % modelCount;
+ if (itemIndex < items.count()) {
+ if (QSGItem *item = items.at(itemIndex)) {
+ if (QSGPathViewAttached *att = attached(item))
+ att->setIsCurrentItem(false);
+ }
+ }
+ currentIndex = idx;
+ currentItem = 0;
+ itemIndex = (idx - firstIndex + modelCount) % modelCount;
+ if (itemIndex < items.count()) {
+ currentItem = items.at(itemIndex);
+ currentItem->setFocus(true);
+ if (QSGPathViewAttached *att = attached(currentItem))
+ att->setIsCurrentItem(true);
+ }
+ emit q->currentIndexChanged();
+ }
+}
+
+void QSGPathViewPrivate::fixOffsetCallback(void *d)
+{
+ ((QSGPathViewPrivate *)d)->fixOffset();
+}
+
+void QSGPathViewPrivate::fixOffset()
+{
+ Q_Q(QSGPathView);
+ if (model && items.count()) {
+ if (haveHighlightRange && highlightRangeMode == QSGPathView::StrictlyEnforceRange) {
+ int curr = calcCurrentIndex();
+ if (curr != currentIndex)
+ q->setCurrentIndex(curr);
+ else
+ snapToCurrent();
+ }
+ }
+}
+
+void QSGPathViewPrivate::snapToCurrent()
+{
+ if (!model || modelCount <= 0)
+ return;
+
+ qreal targetOffset = qmlMod(modelCount - currentIndex, modelCount);
+
+ moveReason = Other;
+ offsetAdj = 0.0;
+ tl.reset(moveOffset);
+ moveOffset.setValue(offset);
+
+ const int duration = highlightMoveDuration;
+
+ if (moveDirection == Positive || (moveDirection == Shortest && targetOffset - offset > modelCount/2)) {
+ qreal distance = modelCount - targetOffset + offset;
+ if (targetOffset > moveOffset) {
+ tl.move(moveOffset, 0.0, QEasingCurve(QEasingCurve::InQuad), int(duration * offset / distance));
+ tl.set(moveOffset, modelCount);
+ tl.move(moveOffset, targetOffset, QEasingCurve(offset == 0.0 ? QEasingCurve::InOutQuad : QEasingCurve::OutQuad), int(duration * (modelCount-targetOffset) / distance));
+ } else {
+ tl.move(moveOffset, targetOffset, QEasingCurve(QEasingCurve::InOutQuad), duration);
+ }
+ } else if (moveDirection == Negative || targetOffset - offset <= -modelCount/2) {
+ qreal distance = modelCount - offset + targetOffset;
+ if (targetOffset < moveOffset) {
+ tl.move(moveOffset, modelCount, QEasingCurve(targetOffset == 0 ? QEasingCurve::InOutQuad : QEasingCurve::InQuad), int(duration * (modelCount-offset) / distance));
+ tl.set(moveOffset, 0.0);
+ tl.move(moveOffset, targetOffset, QEasingCurve(QEasingCurve::OutQuad), int(duration * targetOffset / distance));
+ } else {
+ tl.move(moveOffset, targetOffset, QEasingCurve(QEasingCurve::InOutQuad), duration);
+ }
+ } else {
+ tl.move(moveOffset, targetOffset, QEasingCurve(QEasingCurve::InOutQuad), duration);
+ }
+ moveDirection = Shortest;
+}
+
+QSGPathViewAttached *QSGPathView::qmlAttachedProperties(QObject *obj)
+{
+ return new QSGPathViewAttached(obj);
+}
+
+QT_END_NAMESPACE
+
diff --git a/src/declarative/items/qsgpathview_p.h b/src/declarative/items/qsgpathview_p.h
new file mode 100644
index 0000000000..d75063395a
--- /dev/null
+++ b/src/declarative/items/qsgpathview_p.h
@@ -0,0 +1,254 @@
+// Commit: ac5c099cc3c5b8c7eec7a49fdeb8a21037230350
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGPATHVIEW_P_H
+#define QSGPATHVIEW_P_H
+
+#include "qsgitem.h"
+
+#include <private/qdeclarativepath_p.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QSGPathViewPrivate;
+class QSGPathViewAttached;
+class Q_AUTOTEST_EXPORT QSGPathView : public QSGItem
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QVariant model READ model WRITE setModel NOTIFY modelChanged)
+ Q_PROPERTY(QDeclarativePath *path READ path WRITE setPath NOTIFY pathChanged)
+ Q_PROPERTY(int currentIndex READ currentIndex WRITE setCurrentIndex NOTIFY currentIndexChanged)
+ Q_PROPERTY(qreal offset READ offset WRITE setOffset NOTIFY offsetChanged)
+
+ Q_PROPERTY(QDeclarativeComponent *highlight READ highlight WRITE setHighlight NOTIFY highlightChanged)
+ Q_PROPERTY(QSGItem *highlightItem READ highlightItem NOTIFY highlightItemChanged)
+
+ Q_PROPERTY(qreal preferredHighlightBegin READ preferredHighlightBegin WRITE setPreferredHighlightBegin NOTIFY preferredHighlightBeginChanged)
+ Q_PROPERTY(qreal preferredHighlightEnd READ preferredHighlightEnd WRITE setPreferredHighlightEnd NOTIFY preferredHighlightEndChanged)
+ Q_PROPERTY(HighlightRangeMode highlightRangeMode READ highlightRangeMode WRITE setHighlightRangeMode NOTIFY highlightRangeModeChanged)
+ Q_PROPERTY(int highlightMoveDuration READ highlightMoveDuration WRITE setHighlightMoveDuration NOTIFY highlightMoveDurationChanged)
+
+ Q_PROPERTY(qreal dragMargin READ dragMargin WRITE setDragMargin NOTIFY dragMarginChanged)
+ Q_PROPERTY(qreal flickDeceleration READ flickDeceleration WRITE setFlickDeceleration NOTIFY flickDecelerationChanged)
+ Q_PROPERTY(bool interactive READ isInteractive WRITE setInteractive NOTIFY interactiveChanged)
+
+ Q_PROPERTY(bool moving READ isMoving NOTIFY movingChanged)
+ Q_PROPERTY(bool flicking READ isFlicking NOTIFY flickingChanged)
+
+ Q_PROPERTY(int count READ count NOTIFY countChanged)
+ Q_PROPERTY(QDeclarativeComponent *delegate READ delegate WRITE setDelegate NOTIFY delegateChanged)
+ Q_PROPERTY(int pathItemCount READ pathItemCount WRITE setPathItemCount NOTIFY pathItemCountChanged)
+
+ Q_ENUMS(HighlightRangeMode)
+
+public:
+ QSGPathView(QSGItem *parent=0);
+ virtual ~QSGPathView();
+
+ QVariant model() const;
+ void setModel(const QVariant &);
+
+ QDeclarativePath *path() const;
+ void setPath(QDeclarativePath *);
+
+ int currentIndex() const;
+ void setCurrentIndex(int idx);
+
+ qreal offset() const;
+ void setOffset(qreal offset);
+
+ QDeclarativeComponent *highlight() const;
+ void setHighlight(QDeclarativeComponent *highlight);
+ QSGItem *highlightItem();
+
+ enum HighlightRangeMode { NoHighlightRange, ApplyRange, StrictlyEnforceRange };
+ HighlightRangeMode highlightRangeMode() const;
+ void setHighlightRangeMode(HighlightRangeMode mode);
+
+ qreal preferredHighlightBegin() const;
+ void setPreferredHighlightBegin(qreal);
+
+ qreal preferredHighlightEnd() const;
+ void setPreferredHighlightEnd(qreal);
+
+ int highlightMoveDuration() const;
+ void setHighlightMoveDuration(int);
+
+ qreal dragMargin() const;
+ void setDragMargin(qreal margin);
+
+ qreal flickDeceleration() const;
+ void setFlickDeceleration(qreal dec);
+
+ bool isInteractive() const;
+ void setInteractive(bool);
+
+ bool isMoving() const;
+ bool isFlicking() const;
+
+ int count() const;
+
+ QDeclarativeComponent *delegate() const;
+ void setDelegate(QDeclarativeComponent *);
+
+ int pathItemCount() const;
+ void setPathItemCount(int);
+
+ static QSGPathViewAttached *qmlAttachedProperties(QObject *);
+
+public Q_SLOTS:
+ void incrementCurrentIndex();
+ void decrementCurrentIndex();
+
+Q_SIGNALS:
+ void currentIndexChanged();
+ void offsetChanged();
+ void modelChanged();
+ void countChanged();
+ void pathChanged();
+ void preferredHighlightBeginChanged();
+ void preferredHighlightEndChanged();
+ void highlightRangeModeChanged();
+ void dragMarginChanged();
+ void snapPositionChanged();
+ void delegateChanged();
+ void pathItemCountChanged();
+ void flickDecelerationChanged();
+ void interactiveChanged();
+ void movingChanged();
+ void flickingChanged();
+ void highlightChanged();
+ void highlightItemChanged();
+ void highlightMoveDurationChanged();
+ void movementStarted();
+ void movementEnded();
+ void flickStarted();
+ void flickEnded();
+
+protected:
+ virtual void updatePolish();
+ void mousePressEvent(QGraphicsSceneMouseEvent *event);
+ void mouseMoveEvent(QGraphicsSceneMouseEvent *event);
+ void mouseReleaseEvent(QGraphicsSceneMouseEvent *);
+ bool sendMouseEvent(QGraphicsSceneMouseEvent *event);
+ bool childMouseEventFilter(QSGItem *, QEvent *);
+ void componentComplete();
+
+private Q_SLOTS:
+ void refill();
+ void ticked();
+ void movementEnding();
+ void itemsInserted(int index, int count);
+ void itemsRemoved(int index, int count);
+ void itemsMoved(int,int,int);
+ void modelReset();
+ void createdItem(int index, QSGItem *item);
+ void destroyingItem(QSGItem *item);
+ void pathUpdated();
+
+private:
+ friend class QSGPathViewAttached;
+ Q_DISABLE_COPY(QSGPathView)
+ Q_DECLARE_PRIVATE(QSGPathView)
+};
+
+class QDeclarativeOpenMetaObject;
+class QSGPathViewAttached : public QObject
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QSGPathView *view READ view CONSTANT)
+ Q_PROPERTY(bool isCurrentItem READ isCurrentItem NOTIFY currentItemChanged)
+ Q_PROPERTY(bool onPath READ isOnPath NOTIFY pathChanged)
+
+public:
+ QSGPathViewAttached(QObject *parent);
+ ~QSGPathViewAttached();
+
+ QSGPathView *view() { return m_view; }
+
+ bool isCurrentItem() const { return m_isCurrent; }
+ void setIsCurrentItem(bool c) {
+ if (m_isCurrent != c) {
+ m_isCurrent = c;
+ emit currentItemChanged();
+ }
+ }
+
+ QVariant value(const QByteArray &name) const;
+ void setValue(const QByteArray &name, const QVariant &val);
+
+ bool isOnPath() const { return m_onPath; }
+ void setOnPath(bool on) {
+ if (on != m_onPath) {
+ m_onPath = on;
+ emit pathChanged();
+ }
+ }
+ qreal m_percent;
+
+Q_SIGNALS:
+ void currentItemChanged();
+ void pathChanged();
+
+private:
+ friend class QSGPathViewPrivate;
+ friend class QSGPathView;
+ QSGPathView *m_view;
+ QDeclarativeOpenMetaObject *m_metaobject;
+ bool m_onPath : 1;
+ bool m_isCurrent : 1;
+};
+
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QSGPathView)
+QML_DECLARE_TYPEINFO(QSGPathView, QML_HAS_ATTACHED_PROPERTIES)
+QT_END_HEADER
+
+#endif // QSGPATHVIEW_P_H
diff --git a/src/declarative/items/qsgpathview_p_p.h b/src/declarative/items/qsgpathview_p_p.h
new file mode 100644
index 0000000000..ed54f29abe
--- /dev/null
+++ b/src/declarative/items/qsgpathview_p_p.h
@@ -0,0 +1,193 @@
+// Commit: ac5c099cc3c5b8c7eec7a49fdeb8a21037230350
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVEPATHVIEW_P_H
+#define QDECLARATIVEPATHVIEW_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 "qsgpathview_p.h"
+#include "qsgitem_p.h"
+#include "qsgvisualitemmodel_p.h"
+
+#include <QtDeclarative/qdeclarative.h>
+#include <QtCore/qdatetime.h>
+#include <QtCore/qcoreapplication.h>
+
+#include <private/qdeclarativeanimation_p_p.h>
+#include <private/qdeclarativeguard_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativeOpenMetaObjectType;
+class QSGPathViewAttached;
+class QSGPathViewPrivate : public QSGItemPrivate, public QSGItemChangeListener
+{
+ Q_DECLARE_PUBLIC(QSGPathView)
+
+public:
+ QSGPathViewPrivate()
+ : path(0), currentIndex(0), currentItemOffset(0.0), startPc(0), lastDist(0)
+ , lastElapsed(0), offset(0.0), offsetAdj(0.0), mappedRange(1.0)
+ , stealMouse(false), ownModel(false), interactive(true), haveHighlightRange(true)
+ , autoHighlight(true), highlightUp(false), layoutScheduled(false)
+ , moving(false), flicking(false)
+ , dragMargin(0), deceleration(100)
+ , moveOffset(this, &QSGPathViewPrivate::setAdjustedOffset)
+ , firstIndex(-1), pathItems(-1), requestedIndex(-1)
+ , moveReason(Other), moveDirection(Shortest), attType(0), highlightComponent(0), highlightItem(0)
+ , moveHighlight(this, &QSGPathViewPrivate::setHighlightPosition)
+ , highlightPosition(0)
+ , highlightRangeStart(0), highlightRangeEnd(0)
+ , highlightRangeMode(QSGPathView::StrictlyEnforceRange)
+ , highlightMoveDuration(300), modelCount(0)
+ {
+ }
+
+ void init();
+
+ void itemGeometryChanged(QSGItem *item, const QRectF &newGeometry, const QRectF &oldGeometry) {
+ if ((newGeometry.size() != oldGeometry.size())
+ && (!highlightItem || item != highlightItem)) {
+ if (QSGPathViewAttached *att = attached(item))
+ att->m_percent = -1;
+ scheduleLayout();
+ }
+ }
+
+ void scheduleLayout() {
+ Q_Q(QSGPathView);
+ if (!layoutScheduled) {
+ layoutScheduled = true;
+ q->polish();
+ }
+ }
+
+ QSGItem *getItem(int modelIndex);
+ void releaseItem(QSGItem *item);
+ QSGPathViewAttached *attached(QSGItem *item);
+ void clear();
+ void updateMappedRange();
+ qreal positionOfIndex(qreal index) const;
+ void createHighlight();
+ void updateHighlight();
+ void setHighlightPosition(qreal pos);
+ bool isValid() const {
+ return model && model->count() > 0 && model->isValid() && path;
+ }
+
+ void handleMousePressEvent(QGraphicsSceneMouseEvent *event);
+ void handleMouseMoveEvent(QGraphicsSceneMouseEvent *event);
+ void handleMouseReleaseEvent(QGraphicsSceneMouseEvent *);
+
+ int calcCurrentIndex();
+ void updateCurrent();
+ static void fixOffsetCallback(void*);
+ void fixOffset();
+ void setOffset(qreal offset);
+ void setAdjustedOffset(qreal offset);
+ void regenerate();
+ void updateItem(QSGItem *, qreal);
+ void snapToCurrent();
+ QPointF pointNear(const QPointF &point, qreal *nearPercent=0) const;
+
+ QDeclarativePath *path;
+ int currentIndex;
+ QDeclarativeGuard<QSGItem> currentItem;
+ qreal currentItemOffset;
+ qreal startPc;
+ QPointF startPoint;
+ qreal lastDist;
+ int lastElapsed;
+ qreal offset;
+ qreal offsetAdj;
+ qreal mappedRange;
+ bool stealMouse : 1;
+ bool ownModel : 1;
+ bool interactive : 1;
+ bool haveHighlightRange : 1;
+ bool autoHighlight : 1;
+ bool highlightUp : 1;
+ bool layoutScheduled : 1;
+ bool moving : 1;
+ bool flicking : 1;
+ QElapsedTimer lastPosTime;
+ QPointF lastPos;
+ qreal dragMargin;
+ qreal deceleration;
+ QDeclarativeTimeLine tl;
+ QDeclarativeTimeLineValueProxy<QSGPathViewPrivate> moveOffset;
+ int firstIndex;
+ int pathItems;
+ int requestedIndex;
+ QList<QSGItem *> items;
+ QList<QSGItem *> itemCache;
+ QDeclarativeGuard<QSGVisualModel> model;
+ QVariant modelVariant;
+ enum MovementReason { Other, SetIndex, Mouse };
+ MovementReason moveReason;
+ enum MovementDirection { Shortest, Negative, Positive };
+ MovementDirection moveDirection;
+ QDeclarativeOpenMetaObjectType *attType;
+ QDeclarativeComponent *highlightComponent;
+ QSGItem *highlightItem;
+ QDeclarativeTimeLineValueProxy<QSGPathViewPrivate> moveHighlight;
+ qreal highlightPosition;
+ qreal highlightRangeStart;
+ qreal highlightRangeEnd;
+ QSGPathView::HighlightRangeMode highlightRangeMode;
+ int highlightMoveDuration;
+ int modelCount;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/declarative/items/qsgpincharea.cpp b/src/declarative/items/qsgpincharea.cpp
new file mode 100644
index 0000000000..f21d873e5e
--- /dev/null
+++ b/src/declarative/items/qsgpincharea.cpp
@@ -0,0 +1,421 @@
+// Commit: f707672eb4c51ea82fbd98e1da16ece61a74c690
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtSG module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgpincharea_p_p.h"
+#include "qsgcanvas.h"
+
+#include <QtGui/qgraphicssceneevent.h>
+#include <QtGui/qapplication.h>
+
+#include <float.h>
+#include <math.h>
+
+QT_BEGIN_NAMESPACE
+
+QSGPinch::QSGPinch()
+ : m_target(0), m_minScale(1.0), m_maxScale(1.0)
+ , m_minRotation(0.0), m_maxRotation(0.0)
+ , m_axis(NoDrag), m_xmin(-FLT_MAX), m_xmax(FLT_MAX)
+ , m_ymin(-FLT_MAX), m_ymax(FLT_MAX), m_active(false)
+{
+}
+
+QSGPinchAreaPrivate::~QSGPinchAreaPrivate()
+{
+ delete pinch;
+}
+
+QSGPinchArea::QSGPinchArea(QSGItem *parent)
+ : QSGItem(*(new QSGPinchAreaPrivate), parent)
+{
+ Q_D(QSGPinchArea);
+ d->init();
+}
+
+QSGPinchArea::~QSGPinchArea()
+{
+}
+
+bool QSGPinchArea::isEnabled() const
+{
+ Q_D(const QSGPinchArea);
+ return d->absorb;
+}
+
+void QSGPinchArea::setEnabled(bool a)
+{
+ Q_D(QSGPinchArea);
+ if (a != d->absorb) {
+ d->absorb = a;
+ emit enabledChanged();
+ }
+}
+
+void QSGPinchArea::touchEvent(QTouchEvent *event)
+{
+ Q_D(QSGPinchArea);
+ if (!d->absorb || !isVisible()) {
+ QSGItem::event(event);
+ return;
+ }
+
+ switch (event->type()) {
+ case QEvent::TouchBegin:
+ case QEvent::TouchUpdate:
+ d->touchPoints.clear();
+ for (int i = 0; i < event->touchPoints().count(); ++i) {
+ if (!(event->touchPoints().at(i).state() & Qt::TouchPointReleased)) {
+ d->touchPoints << event->touchPoints().at(i);
+ }
+ }
+ updatePinch();
+ break;
+ case QEvent::TouchEnd:
+ d->touchPoints.clear();
+ updatePinch();
+ break;
+ default:
+ QSGItem::event(event);
+ }
+}
+
+void QSGPinchArea::updatePinch()
+{
+ Q_D(QSGPinchArea);
+ if (d->touchPoints.count() == 0) {
+ if (d->inPinch) {
+ d->stealMouse = false;
+ setKeepMouseGrab(false);
+ d->inPinch = false;
+ QPointF pinchCenter = mapFromScene(d->sceneLastCenter);
+ QSGPinchEvent pe(pinchCenter, d->pinchLastScale, d->pinchLastAngle, d->pinchRotation);
+ pe.setStartCenter(d->pinchStartCenter);
+ pe.setPreviousCenter(pinchCenter);
+ pe.setPreviousAngle(d->pinchLastAngle);
+ pe.setPreviousScale(d->pinchLastScale);
+ pe.setStartPoint1(mapFromScene(d->sceneStartPoint1));
+ pe.setStartPoint2(mapFromScene(d->sceneStartPoint2));
+ pe.setPoint1(mapFromScene(d->lastPoint1));
+ pe.setPoint2(mapFromScene(d->lastPoint2));
+ emit pinchFinished(&pe);
+ d->pinchStartDist = 0;
+ d->pinchActivated = false;
+ if (d->pinch && d->pinch->target())
+ d->pinch->setActive(false);
+ }
+ return;
+ }
+ QTouchEvent::TouchPoint touchPoint1 = d->touchPoints.at(0);
+ QTouchEvent::TouchPoint touchPoint2 = d->touchPoints.at(d->touchPoints. count() >= 2 ? 1 : 0);
+ if (d->touchPoints.count() == 2
+ && (touchPoint1.state() & Qt::TouchPointPressed || touchPoint2.state() & Qt::TouchPointPressed)) {
+ d->id1 = touchPoint1.id();
+ d->sceneStartPoint1 = touchPoint1.scenePos();
+ d->sceneStartPoint2 = touchPoint2.scenePos();
+ d->inPinch = false;
+ d->pinchRejected = false;
+ d->pinchActivated = true;
+ } else if (d->pinchActivated && !d->pinchRejected){
+ const int dragThreshold = QApplication::startDragDistance();
+ QPointF p1 = touchPoint1.scenePos();
+ QPointF p2 = touchPoint2.scenePos();
+ qreal dx = p1.x() - p2.x();
+ qreal dy = p1.y() - p2.y();
+ qreal dist = sqrt(dx*dx + dy*dy);
+ QPointF sceneCenter = (p1 + p2)/2;
+ qreal angle = QLineF(p1, p2).angle();
+ if (d->touchPoints.count() == 1) {
+ // If we only have one point then just move the center
+ if (d->id1 == touchPoint1.id())
+ sceneCenter = d->sceneLastCenter + touchPoint1.scenePos() - d->lastPoint1;
+ else
+ sceneCenter = d->sceneLastCenter + touchPoint2.scenePos() - d->lastPoint2;
+ angle = d->pinchLastAngle;
+ }
+ d->id1 = touchPoint1.id();
+ if (angle > 180)
+ angle -= 360;
+ if (!d->inPinch) {
+ if (d->touchPoints.count() >= 2
+ && (qAbs(p1.x()-d->sceneStartPoint1.x()) > dragThreshold
+ || qAbs(p1.y()-d->sceneStartPoint1.y()) > dragThreshold
+ || qAbs(p2.x()-d->sceneStartPoint2.x()) > dragThreshold
+ || qAbs(p2.y()-d->sceneStartPoint2.y()) > dragThreshold)) {
+ d->sceneStartCenter = sceneCenter;
+ d->sceneLastCenter = sceneCenter;
+ d->pinchStartCenter = mapFromScene(sceneCenter);
+ d->pinchStartDist = dist;
+ d->pinchStartAngle = angle;
+ d->pinchLastScale = 1.0;
+ d->pinchLastAngle = angle;
+ d->pinchRotation = 0.0;
+ d->lastPoint1 = p1;
+ d->lastPoint2 = p2;
+ QSGPinchEvent pe(d->pinchStartCenter, 1.0, angle, 0.0);
+ pe.setStartCenter(d->pinchStartCenter);
+ pe.setPreviousCenter(d->pinchStartCenter);
+ pe.setPreviousAngle(d->pinchLastAngle);
+ pe.setPreviousScale(d->pinchLastScale);
+ pe.setStartPoint1(mapFromScene(d->sceneStartPoint1));
+ pe.setStartPoint2(mapFromScene(d->sceneStartPoint2));
+ pe.setPoint1(mapFromScene(d->lastPoint1));
+ pe.setPoint2(mapFromScene(d->lastPoint2));
+ pe.setPointCount(d->touchPoints.count());
+ emit pinchStarted(&pe);
+ if (pe.accepted()) {
+ d->inPinch = true;
+ d->stealMouse = true;
+ QSGCanvas *c = canvas();
+ if (c && c->mouseGrabberItem() != this)
+ grabMouse();
+ setKeepMouseGrab(true);
+ if (d->pinch && d->pinch->target()) {
+ d->pinchStartPos = pinch()->target()->pos();
+ d->pinchStartScale = d->pinch->target()->scale();
+ d->pinchStartRotation = d->pinch->target()->rotation();
+ d->pinch->setActive(true);
+ }
+ } else {
+ d->pinchRejected = true;
+ }
+ }
+ } else if (d->pinchStartDist > 0) {
+ qreal scale = dist ? dist / d->pinchStartDist : d->pinchLastScale;
+ qreal da = d->pinchLastAngle - angle;
+ if (da > 180)
+ da -= 360;
+ else if (da < -180)
+ da += 360;
+ d->pinchRotation += da;
+ QPointF pinchCenter = mapFromScene(sceneCenter);
+ QSGPinchEvent pe(pinchCenter, scale, angle, d->pinchRotation);
+ pe.setStartCenter(d->pinchStartCenter);
+ pe.setPreviousCenter(mapFromScene(d->sceneLastCenter));
+ pe.setPreviousAngle(d->pinchLastAngle);
+ pe.setPreviousScale(d->pinchLastScale);
+ pe.setStartPoint1(mapFromScene(d->sceneStartPoint1));
+ pe.setStartPoint2(mapFromScene(d->sceneStartPoint2));
+ pe.setPoint1(touchPoint1.pos());
+ pe.setPoint2(touchPoint2.pos());
+ pe.setPointCount(d->touchPoints.count());
+ d->pinchLastScale = scale;
+ d->sceneLastCenter = sceneCenter;
+ d->pinchLastAngle = angle;
+ d->lastPoint1 = touchPoint1.scenePos();
+ d->lastPoint2 = touchPoint2.scenePos();
+ emit pinchUpdated(&pe);
+ if (d->pinch && d->pinch->target()) {
+ qreal s = d->pinchStartScale * scale;
+ s = qMin(qMax(pinch()->minimumScale(),s), pinch()->maximumScale());
+ pinch()->target()->setScale(s);
+ QPointF pos = sceneCenter - d->sceneStartCenter + d->pinchStartPos;
+ if (pinch()->axis() & QSGPinch::XAxis) {
+ qreal x = pos.x();
+ if (x < pinch()->xmin())
+ x = pinch()->xmin();
+ else if (x > pinch()->xmax())
+ x = pinch()->xmax();
+ pinch()->target()->setX(x);
+ }
+ if (pinch()->axis() & QSGPinch::YAxis) {
+ qreal y = pos.y();
+ if (y < pinch()->ymin())
+ y = pinch()->ymin();
+ else if (y > pinch()->ymax())
+ y = pinch()->ymax();
+ pinch()->target()->setY(y);
+ }
+ if (d->pinchStartRotation >= pinch()->minimumRotation()
+ && d->pinchStartRotation <= pinch()->maximumRotation()) {
+ qreal r = d->pinchRotation + d->pinchStartRotation;
+ r = qMin(qMax(pinch()->minimumRotation(),r), pinch()->maximumRotation());
+ pinch()->target()->setRotation(r);
+ }
+ }
+ }
+ }
+}
+
+void QSGPinchArea::mousePressEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(QSGPinchArea);
+ d->stealMouse = false;
+ if (!d->absorb)
+ QSGItem::mousePressEvent(event);
+ else {
+ setKeepMouseGrab(false);
+ event->setAccepted(true);
+ }
+}
+
+void QSGPinchArea::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(QSGPinchArea);
+ if (!d->absorb) {
+ QSGItem::mouseMoveEvent(event);
+ return;
+ }
+}
+
+void QSGPinchArea::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(QSGPinchArea);
+ d->stealMouse = false;
+ if (!d->absorb) {
+ QSGItem::mouseReleaseEvent(event);
+ } else {
+ QSGCanvas *c = canvas();
+ if (c && c->mouseGrabberItem() == this)
+ ungrabMouse();
+ setKeepMouseGrab(false);
+ }
+}
+
+void QSGPinchArea::mouseUngrabEvent()
+{
+ setKeepMouseGrab(false);
+}
+
+bool QSGPinchArea::sendMouseEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(QSGPinchArea);
+ QGraphicsSceneMouseEvent mouseEvent(event->type());
+ QRectF myRect = mapRectToScene(QRectF(0, 0, width(), height()));
+
+ QSGCanvas *c = canvas();
+ QSGItem *grabber = c ? c->mouseGrabberItem() : 0;
+ bool stealThisEvent = d->stealMouse;
+ if ((stealThisEvent || myRect.contains(event->scenePos().toPoint())) && (!grabber || !grabber->keepMouseGrab())) {
+ mouseEvent.setAccepted(false);
+ for (int i = 0x1; i <= 0x10; i <<= 1) {
+ if (event->buttons() & i) {
+ Qt::MouseButton button = Qt::MouseButton(i);
+ mouseEvent.setButtonDownPos(button, mapFromScene(event->buttonDownPos(button)));
+ }
+ }
+ mouseEvent.setScenePos(event->scenePos());
+ mouseEvent.setLastScenePos(event->lastScenePos());
+ mouseEvent.setPos(mapFromScene(event->scenePos()));
+ mouseEvent.setLastPos(mapFromScene(event->lastScenePos()));
+
+ switch(mouseEvent.type()) {
+ case QEvent::GraphicsSceneMouseMove:
+ mouseMoveEvent(&mouseEvent);
+ break;
+ case QEvent::GraphicsSceneMousePress:
+ mousePressEvent(&mouseEvent);
+ break;
+ case QEvent::GraphicsSceneMouseRelease:
+ mouseReleaseEvent(&mouseEvent);
+ break;
+ default:
+ break;
+ }
+ grabber = c->mouseGrabberItem();
+ if (grabber && stealThisEvent && !grabber->keepMouseGrab() && grabber != this)
+ grabMouse();
+
+ return stealThisEvent;
+ }
+ if (mouseEvent.type() == QEvent::GraphicsSceneMouseRelease) {
+ d->stealMouse = false;
+ if (c && c->mouseGrabberItem() == this)
+ ungrabMouse();
+ setKeepMouseGrab(false);
+ }
+ return false;
+}
+
+bool QSGPinchArea::childMouseEventFilter(QSGItem *i, QEvent *e)
+{
+ Q_D(QSGPinchArea);
+ if (!d->absorb || !isVisible())
+ return QSGItem::childMouseEventFilter(i, e);
+ switch (e->type()) {
+ case QEvent::GraphicsSceneMousePress:
+ case QEvent::GraphicsSceneMouseMove:
+ case QEvent::GraphicsSceneMouseRelease:
+ return sendMouseEvent(static_cast<QGraphicsSceneMouseEvent *>(e));
+ break;
+ case QEvent::TouchBegin:
+ case QEvent::TouchUpdate: {
+ QTouchEvent *touch = static_cast<QTouchEvent*>(e);
+ d->touchPoints.clear();
+ for (int i = 0; i < touch->touchPoints().count(); ++i)
+ if (!(touch->touchPoints().at(i).state() & Qt::TouchPointReleased))
+ d->touchPoints << touch->touchPoints().at(i);
+ updatePinch();
+ }
+ return d->inPinch;
+ case QEvent::TouchEnd:
+ d->touchPoints.clear();
+ updatePinch();
+ break;
+ default:
+ break;
+ }
+
+ return QSGItem::childMouseEventFilter(i, e);
+}
+
+void QSGPinchArea::geometryChanged(const QRectF &newGeometry,
+ const QRectF &oldGeometry)
+{
+ QSGItem::geometryChanged(newGeometry, oldGeometry);
+}
+
+void QSGPinchArea::itemChange(ItemChange change, const ItemChangeData &value)
+{
+ QSGItem::itemChange(change, value);
+}
+
+QSGPinch *QSGPinchArea::pinch()
+{
+ Q_D(QSGPinchArea);
+ if (!d->pinch)
+ d->pinch = new QSGPinch;
+ return d->pinch;
+}
+
+
+QT_END_NAMESPACE
+
diff --git a/src/declarative/items/qsgpincharea_p.h b/src/declarative/items/qsgpincharea_p.h
new file mode 100644
index 0000000000..4cba6367e1
--- /dev/null
+++ b/src/declarative/items/qsgpincharea_p.h
@@ -0,0 +1,315 @@
+// Commit: f707672eb4c51ea82fbd98e1da16ece61a74c690
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtSG module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGPINCHAREA_H
+#define QSGPINCHAREA_H
+
+#include "qsgitem.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class Q_AUTOTEST_EXPORT QSGPinch : public QObject
+{
+ Q_OBJECT
+
+ Q_ENUMS(Axis)
+ Q_PROPERTY(QSGItem *target READ target WRITE setTarget RESET resetTarget)
+ Q_PROPERTY(qreal minimumScale READ minimumScale WRITE setMinimumScale NOTIFY minimumScaleChanged)
+ Q_PROPERTY(qreal maximumScale READ maximumScale WRITE setMaximumScale NOTIFY maximumScaleChanged)
+ Q_PROPERTY(qreal minimumRotation READ minimumRotation WRITE setMinimumRotation NOTIFY minimumRotationChanged)
+ Q_PROPERTY(qreal maximumRotation READ maximumRotation WRITE setMaximumRotation NOTIFY maximumRotationChanged)
+ Q_PROPERTY(Axis dragAxis READ axis WRITE setAxis NOTIFY dragAxisChanged)
+ Q_PROPERTY(qreal minimumX READ xmin WRITE setXmin NOTIFY minimumXChanged)
+ Q_PROPERTY(qreal maximumX READ xmax WRITE setXmax NOTIFY maximumXChanged)
+ Q_PROPERTY(qreal minimumY READ ymin WRITE setYmin NOTIFY minimumYChanged)
+ Q_PROPERTY(qreal maximumY READ ymax WRITE setYmax NOTIFY maximumYChanged)
+ Q_PROPERTY(bool active READ active NOTIFY activeChanged)
+
+public:
+ QSGPinch();
+
+ QSGItem *target() const { return m_target; }
+ void setTarget(QSGItem *target) {
+ if (target == m_target)
+ return;
+ m_target = target;
+ emit targetChanged();
+ }
+ void resetTarget() {
+ if (!m_target)
+ return;
+ m_target = 0;
+ emit targetChanged();
+ }
+
+ qreal minimumScale() const { return m_minScale; }
+ void setMinimumScale(qreal s) {
+ if (s == m_minScale)
+ return;
+ m_minScale = s;
+ emit minimumScaleChanged();
+ }
+ qreal maximumScale() const { return m_maxScale; }
+ void setMaximumScale(qreal s) {
+ if (s == m_maxScale)
+ return;
+ m_maxScale = s;
+ emit maximumScaleChanged();
+ }
+
+ qreal minimumRotation() const { return m_minRotation; }
+ void setMinimumRotation(qreal r) {
+ if (r == m_minRotation)
+ return;
+ m_minRotation = r;
+ emit minimumRotationChanged();
+ }
+ qreal maximumRotation() const { return m_maxRotation; }
+ void setMaximumRotation(qreal r) {
+ if (r == m_maxRotation)
+ return;
+ m_maxRotation = r;
+ emit maximumRotationChanged();
+ }
+
+ enum Axis { NoDrag=0x00, XAxis=0x01, YAxis=0x02, XandYAxis=0x03 };
+ Axis axis() const { return m_axis; }
+ void setAxis(Axis a) {
+ if (a == m_axis)
+ return;
+ m_axis = a;
+ emit dragAxisChanged();
+ }
+
+ qreal xmin() const { return m_xmin; }
+ void setXmin(qreal x) {
+ if (x == m_xmin)
+ return;
+ m_xmin = x;
+ emit minimumXChanged();
+ }
+ qreal xmax() const { return m_xmax; }
+ void setXmax(qreal x) {
+ if (x == m_xmax)
+ return;
+ m_xmax = x;
+ emit maximumXChanged();
+ }
+ qreal ymin() const { return m_ymin; }
+ void setYmin(qreal y) {
+ if (y == m_ymin)
+ return;
+ m_ymin = y;
+ emit minimumYChanged();
+ }
+ qreal ymax() const { return m_ymax; }
+ void setYmax(qreal y) {
+ if (y == m_ymax)
+ return;
+ m_ymax = y;
+ emit maximumYChanged();
+ }
+
+ bool active() const { return m_active; }
+ void setActive(bool a) {
+ if (a == m_active)
+ return;
+ m_active = a;
+ emit activeChanged();
+ }
+
+signals:
+ void targetChanged();
+ void minimumScaleChanged();
+ void maximumScaleChanged();
+ void minimumRotationChanged();
+ void maximumRotationChanged();
+ void dragAxisChanged();
+ void minimumXChanged();
+ void maximumXChanged();
+ void minimumYChanged();
+ void maximumYChanged();
+ void activeChanged();
+
+private:
+ QSGItem *m_target;
+ qreal m_minScale;
+ qreal m_maxScale;
+ qreal m_minRotation;
+ qreal m_maxRotation;
+ Axis m_axis;
+ qreal m_xmin;
+ qreal m_xmax;
+ qreal m_ymin;
+ qreal m_ymax;
+ bool m_active;
+};
+
+class Q_AUTOTEST_EXPORT QSGPinchEvent : public QObject
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QPointF center READ center)
+ Q_PROPERTY(QPointF startCenter READ startCenter)
+ Q_PROPERTY(QPointF previousCenter READ previousCenter)
+ Q_PROPERTY(qreal scale READ scale)
+ Q_PROPERTY(qreal previousScale READ previousScale)
+ Q_PROPERTY(qreal angle READ angle)
+ Q_PROPERTY(qreal previousAngle READ previousAngle)
+ Q_PROPERTY(qreal rotation READ rotation)
+ Q_PROPERTY(QPointF point1 READ point1)
+ Q_PROPERTY(QPointF startPoint1 READ startPoint1)
+ Q_PROPERTY(QPointF point2 READ point2)
+ Q_PROPERTY(QPointF startPoint2 READ startPoint2)
+ Q_PROPERTY(int pointCount READ pointCount)
+ Q_PROPERTY(bool accepted READ accepted WRITE setAccepted)
+
+public:
+ QSGPinchEvent(QPointF c, qreal s, qreal a, qreal r)
+ : QObject(), m_center(c), m_scale(s), m_angle(a), m_rotation(r)
+ , m_pointCount(0), m_accepted(true) {}
+
+ QPointF center() const { return m_center; }
+ QPointF startCenter() const { return m_startCenter; }
+ void setStartCenter(QPointF c) { m_startCenter = c; }
+ QPointF previousCenter() const { return m_lastCenter; }
+ void setPreviousCenter(QPointF c) { m_lastCenter = c; }
+ qreal scale() const { return m_scale; }
+ qreal previousScale() const { return m_lastScale; }
+ void setPreviousScale(qreal s) { m_lastScale = s; }
+ qreal angle() const { return m_angle; }
+ qreal previousAngle() const { return m_lastAngle; }
+ void setPreviousAngle(qreal a) { m_lastAngle = a; }
+ qreal rotation() const { return m_rotation; }
+ QPointF point1() const { return m_point1; }
+ void setPoint1(QPointF p) { m_point1 = p; }
+ QPointF startPoint1() const { return m_startPoint1; }
+ void setStartPoint1(QPointF p) { m_startPoint1 = p; }
+ QPointF point2() const { return m_point2; }
+ void setPoint2(QPointF p) { m_point2 = p; }
+ QPointF startPoint2() const { return m_startPoint2; }
+ void setStartPoint2(QPointF p) { m_startPoint2 = p; }
+ int pointCount() const { return m_pointCount; }
+ void setPointCount(int count) { m_pointCount = count; }
+
+ bool accepted() const { return m_accepted; }
+ void setAccepted(bool a) { m_accepted = a; }
+
+private:
+ QPointF m_center;
+ QPointF m_startCenter;
+ QPointF m_lastCenter;
+ qreal m_scale;
+ qreal m_lastScale;
+ qreal m_angle;
+ qreal m_lastAngle;
+ qreal m_rotation;
+ QPointF m_point1;
+ QPointF m_point2;
+ QPointF m_startPoint1;
+ QPointF m_startPoint2;
+ int m_pointCount;
+ bool m_accepted;
+};
+
+
+class QSGMouseEvent;
+class QSGPinchAreaPrivate;
+class Q_AUTOTEST_EXPORT QSGPinchArea : public QSGItem
+{
+ Q_OBJECT
+
+ Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled NOTIFY enabledChanged)
+ Q_PROPERTY(QSGPinch *pinch READ pinch CONSTANT)
+
+public:
+ QSGPinchArea(QSGItem *parent=0);
+ ~QSGPinchArea();
+
+ bool isEnabled() const;
+ void setEnabled(bool);
+
+ QSGPinch *pinch();
+
+Q_SIGNALS:
+ void enabledChanged();
+ void pinchStarted(QSGPinchEvent *pinch);
+ void pinchUpdated(QSGPinchEvent *pinch);
+ void pinchFinished(QSGPinchEvent *pinch);
+
+protected:
+ virtual void mousePressEvent(QGraphicsSceneMouseEvent *event);
+ virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *event);
+ virtual void mouseMoveEvent(QGraphicsSceneMouseEvent *event);
+ virtual void mouseUngrabEvent();
+ virtual bool sendMouseEvent(QGraphicsSceneMouseEvent *event);
+ virtual bool childMouseEventFilter(QSGItem *i, QEvent *e);
+ virtual void touchEvent(QTouchEvent *event);
+
+ virtual void geometryChanged(const QRectF &newGeometry,
+ const QRectF &oldGeometry);
+ virtual void itemChange(ItemChange change, const ItemChangeData& value);
+
+private:
+ void updatePinch();
+ void handlePress();
+ void handleRelease();
+
+private:
+ Q_DISABLE_COPY(QSGPinchArea)
+ Q_DECLARE_PRIVATE(QSGPinchArea)
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QSGPinch)
+QML_DECLARE_TYPE(QSGPinchEvent)
+QML_DECLARE_TYPE(QSGPinchArea)
+
+QT_END_HEADER
+
+#endif // QSGPINCHAREA_H
+
diff --git a/src/declarative/items/qsgpincharea_p_p.h b/src/declarative/items/qsgpincharea_p_p.h
new file mode 100644
index 0000000000..b93d095e0e
--- /dev/null
+++ b/src/declarative/items/qsgpincharea_p_p.h
@@ -0,0 +1,115 @@
+// Commit: f707672eb4c51ea82fbd98e1da16ece61a74c690
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtSG module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGPINCHAREA_P_H
+#define QSGPINCHAREA_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 <qevent.h>
+
+#include "qsgitem_p.h"
+#include "qsgpincharea_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QSGPinch;
+class QSGPinchAreaPrivate : public QSGItemPrivate
+{
+ Q_DECLARE_PUBLIC(QSGPinchArea)
+public:
+ QSGPinchAreaPrivate()
+ : absorb(true), stealMouse(false), inPinch(false)
+ , pinchRejected(false), pinchActivated(false)
+ , pinch(0), pinchStartDist(0), pinchStartScale(1.0)
+ , pinchLastScale(1.0), pinchStartRotation(0.0), pinchStartAngle(0.0)
+ , pinchLastAngle(0.0), pinchRotation(0.0)
+ {
+ }
+
+ ~QSGPinchAreaPrivate();
+
+ void init()
+ {
+ Q_Q(QSGPinchArea);
+ q->setAcceptedMouseButtons(Qt::LeftButton);
+ q->setFiltersChildMouseEvents(true);
+ }
+
+ bool absorb : 1;
+ bool stealMouse : 1;
+ bool inPinch : 1;
+ bool pinchRejected : 1;
+ bool pinchActivated : 1;
+ QSGPinch *pinch;
+ QPointF sceneStartPoint1;
+ QPointF sceneStartPoint2;
+ QPointF lastPoint1;
+ QPointF lastPoint2;
+ qreal pinchStartDist;
+ qreal pinchStartScale;
+ qreal pinchLastScale;
+ qreal pinchStartRotation;
+ qreal pinchStartAngle;
+ qreal pinchLastAngle;
+ qreal pinchRotation;
+ QPointF sceneStartCenter;
+ QPointF pinchStartCenter;
+ QPointF sceneLastCenter;
+ QPointF pinchStartPos;
+ QList<QTouchEvent::TouchPoint> touchPoints;
+ int id1;
+};
+
+QT_END_NAMESPACE
+
+#endif // QSGPINCHAREA_P_H
+
diff --git a/src/declarative/items/qsgpositioners.cpp b/src/declarative/items/qsgpositioners.cpp
new file mode 100644
index 0000000000..f174612af6
--- /dev/null
+++ b/src/declarative/items/qsgpositioners.cpp
@@ -0,0 +1,788 @@
+// Commit: 1f38d41854fa2daa51d938a4eb398752b1751e0b
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgpositioners_p.h"
+#include "qsgpositioners_p_p.h"
+
+#include <QtDeclarative/qdeclarative.h>
+#include <QtDeclarative/qdeclarativeinfo.h>
+#include <QtCore/qmath.h>
+#include <QtCore/qcoreapplication.h>
+
+#include <private/qdeclarativestate_p.h>
+#include <private/qdeclarativestategroup_p.h>
+#include <private/qdeclarativestateoperations_p.h>
+
+QT_BEGIN_NAMESPACE
+
+static const QSGItemPrivate::ChangeTypes watchedChanges
+ = QSGItemPrivate::Geometry
+ | QSGItemPrivate::SiblingOrder
+ | QSGItemPrivate::Visibility
+ | QSGItemPrivate::Opacity
+ | QSGItemPrivate::Destroyed;
+
+void QSGBasePositionerPrivate::watchChanges(QSGItem *other)
+{
+ QSGItemPrivate *otherPrivate = QSGItemPrivate::get(other);
+ otherPrivate->addItemChangeListener(this, watchedChanges);
+}
+
+void QSGBasePositionerPrivate::unwatchChanges(QSGItem* other)
+{
+ QSGItemPrivate *otherPrivate = QSGItemPrivate::get(other);
+ otherPrivate->removeItemChangeListener(this, watchedChanges);
+}
+
+QSGBasePositioner::QSGBasePositioner(PositionerType at, QSGItem *parent)
+ : QSGImplicitSizeItem(*(new QSGBasePositionerPrivate), parent)
+{
+ Q_D(QSGBasePositioner);
+ d->init(at);
+}
+
+QSGBasePositioner::QSGBasePositioner(QSGBasePositionerPrivate &dd, PositionerType at, QSGItem *parent)
+ : QSGImplicitSizeItem(dd, parent)
+{
+ Q_D(QSGBasePositioner);
+ d->init(at);
+}
+
+QSGBasePositioner::~QSGBasePositioner()
+{
+ Q_D(QSGBasePositioner);
+ for (int i = 0; i < positionedItems.count(); ++i)
+ d->unwatchChanges(positionedItems.at(i).item);
+ positionedItems.clear();
+}
+
+int QSGBasePositioner::spacing() const
+{
+ Q_D(const QSGBasePositioner);
+ return d->spacing;
+}
+
+void QSGBasePositioner::setSpacing(int s)
+{
+ Q_D(QSGBasePositioner);
+ if (s==d->spacing)
+ return;
+ d->spacing = s;
+ prePositioning();
+ emit spacingChanged();
+}
+
+QDeclarativeTransition *QSGBasePositioner::move() const
+{
+ Q_D(const QSGBasePositioner);
+ return d->moveTransition;
+}
+
+void QSGBasePositioner::setMove(QDeclarativeTransition *mt)
+{
+ Q_D(QSGBasePositioner);
+ if (mt == d->moveTransition)
+ return;
+ d->moveTransition = mt;
+ emit moveChanged();
+}
+
+QDeclarativeTransition *QSGBasePositioner::add() const
+{
+ Q_D(const QSGBasePositioner);
+ return d->addTransition;
+}
+
+void QSGBasePositioner::setAdd(QDeclarativeTransition *add)
+{
+ Q_D(QSGBasePositioner);
+ if (add == d->addTransition)
+ return;
+
+ d->addTransition = add;
+ emit addChanged();
+}
+
+void QSGBasePositioner::componentComplete()
+{
+ QSGItem::componentComplete();
+ positionedItems.reserve(childItems().count());
+ prePositioning();
+ reportConflictingAnchors();
+}
+
+void QSGBasePositioner::itemChange(ItemChange change, const ItemChangeData &value)
+{
+ Q_D(QSGBasePositioner);
+ if (change == ItemChildAddedChange){
+ prePositioning();
+ } else if (change == ItemChildRemovedChange) {
+ QSGItem *child = value.item;
+ QSGBasePositioner::PositionedItem posItem(child);
+ int idx = positionedItems.find(posItem);
+ if (idx >= 0) {
+ d->unwatchChanges(child);
+ positionedItems.remove(idx);
+ }
+ prePositioning();
+ }
+
+ QSGItem::itemChange(change, value);
+}
+
+void QSGBasePositioner::prePositioning()
+{
+ Q_D(QSGBasePositioner);
+ if (!isComponentComplete())
+ return;
+
+ if (d->doingPositioning)
+ return;
+
+ d->queuedPositioning = false;
+ d->doingPositioning = true;
+ //Need to order children by creation order modified by stacking order
+ QList<QSGItem *> children = childItems();
+
+ QPODVector<PositionedItem,8> oldItems;
+ positionedItems.copyAndClear(oldItems);
+ for (int ii = 0; ii < children.count(); ++ii) {
+ QSGItem *child = children.at(ii);
+ QSGItemPrivate *childPrivate = QSGItemPrivate::get(child);
+ PositionedItem *item = 0;
+ PositionedItem posItem(child);
+ int wIdx = oldItems.find(posItem);
+ if (wIdx < 0) {
+ d->watchChanges(child);
+ positionedItems.append(posItem);
+ item = &positionedItems[positionedItems.count()-1];
+ item->isNew = true;
+ if (child->opacity() <= 0.0 || !childPrivate->explicitVisible || !child->width() || !child->height())
+ item->isVisible = false;
+ } else {
+ item = &oldItems[wIdx];
+ // Items are only omitted from positioning if they are explicitly hidden
+ // i.e. their positioning is not affected if an ancestor is hidden.
+ if (child->opacity() <= 0.0 || !childPrivate->explicitVisible || !child->width() || !child->height()) {
+ item->isVisible = false;
+ } else if (!item->isVisible) {
+ item->isVisible = true;
+ item->isNew = true;
+ } else {
+ item->isNew = false;
+ }
+ positionedItems.append(*item);
+ }
+ }
+ QSizeF contentSize;
+ doPositioning(&contentSize);
+ if(d->addTransition || d->moveTransition)
+ finishApplyTransitions();
+ d->doingPositioning = false;
+ //Set implicit size to the size of its children
+ setImplicitHeight(contentSize.height());
+ setImplicitWidth(contentSize.width());
+}
+
+void QSGBasePositioner::positionX(int x, const PositionedItem &target)
+{
+ Q_D(QSGBasePositioner);
+ if(d->type == Horizontal || d->type == Both){
+ if (target.isNew) {
+ if (!d->addTransition)
+ target.item->setX(x);
+ else
+ d->addActions << QDeclarativeAction(target.item, QLatin1String("x"), QVariant(x));
+ } else if (x != target.item->x()) {
+ if (!d->moveTransition)
+ target.item->setX(x);
+ else
+ d->moveActions << QDeclarativeAction(target.item, QLatin1String("x"), QVariant(x));
+ }
+ }
+}
+
+void QSGBasePositioner::positionY(int y, const PositionedItem &target)
+{
+ Q_D(QSGBasePositioner);
+ if(d->type == Vertical || d->type == Both){
+ if (target.isNew) {
+ if (!d->addTransition)
+ target.item->setY(y);
+ else
+ d->addActions << QDeclarativeAction(target.item, QLatin1String("y"), QVariant(y));
+ } else if (y != target.item->y()) {
+ if (!d->moveTransition)
+ target.item->setY(y);
+ else
+ d->moveActions << QDeclarativeAction(target.item, QLatin1String("y"), QVariant(y));
+ }
+ }
+}
+
+void QSGBasePositioner::finishApplyTransitions()
+{
+ Q_D(QSGBasePositioner);
+ // Note that if a transition is not set the transition manager will
+ // apply the changes directly, in the case add/move aren't set
+ d->addTransitionManager.transition(d->addActions, d->addTransition);
+ d->moveTransitionManager.transition(d->moveActions, d->moveTransition);
+ d->addActions.clear();
+ d->moveActions.clear();
+}
+
+QSGColumn::QSGColumn(QSGItem *parent)
+: QSGBasePositioner(Vertical, parent)
+{
+}
+
+void QSGColumn::doPositioning(QSizeF *contentSize)
+{
+ int voffset = 0;
+
+ for (int ii = 0; ii < positionedItems.count(); ++ii) {
+ const PositionedItem &child = positionedItems.at(ii);
+ if (!child.item || !child.isVisible)
+ continue;
+
+ if(child.item->y() != voffset)
+ positionY(voffset, child);
+
+ contentSize->setWidth(qMax(contentSize->width(), child.item->width()));
+
+ voffset += child.item->height();
+ voffset += spacing();
+ }
+
+ contentSize->setHeight(voffset - spacing());
+}
+
+void QSGColumn::reportConflictingAnchors()
+{
+ QSGBasePositionerPrivate *d = static_cast<QSGBasePositionerPrivate*>(QSGBasePositionerPrivate::get(this));
+ for (int ii = 0; ii < positionedItems.count(); ++ii) {
+ const PositionedItem &child = positionedItems.at(ii);
+ if (child.item) {
+ QSGAnchors *anchors = QSGItemPrivate::get(static_cast<QSGItem *>(child.item))->_anchors;
+ if (anchors) {
+ QSGAnchors::Anchors usedAnchors = anchors->usedAnchors();
+ if (usedAnchors & QSGAnchors::TopAnchor ||
+ usedAnchors & QSGAnchors::BottomAnchor ||
+ usedAnchors & QSGAnchors::VCenterAnchor ||
+ anchors->fill() || anchors->centerIn()) {
+ d->anchorConflict = true;
+ break;
+ }
+ }
+ }
+ }
+ if (d->anchorConflict) {
+ qmlInfo(this) << "Cannot specify top, bottom, verticalCenter, fill or centerIn anchors for items inside Column";
+ }
+}
+
+QSGRow::QSGRow(QSGItem *parent)
+: QSGBasePositioner(Horizontal, parent)
+{
+}
+
+Qt::LayoutDirection QSGRow::layoutDirection() const
+{
+ return QSGBasePositionerPrivate::getLayoutDirection(this);
+}
+
+void QSGRow::setLayoutDirection(Qt::LayoutDirection layoutDirection)
+{
+ QSGBasePositionerPrivate *d = static_cast<QSGBasePositionerPrivate* >(QSGBasePositionerPrivate::get(this));
+ if (d->layoutDirection != layoutDirection) {
+ d->layoutDirection = layoutDirection;
+ // For RTL layout the positioning changes when the width changes.
+ if (d->layoutDirection == Qt::RightToLeft)
+ d->addItemChangeListener(d, QSGItemPrivate::Geometry);
+ else
+ d->removeItemChangeListener(d, QSGItemPrivate::Geometry);
+ prePositioning();
+ emit layoutDirectionChanged();
+ emit effectiveLayoutDirectionChanged();
+ }
+}
+
+Qt::LayoutDirection QSGRow::effectiveLayoutDirection() const
+{
+ return QSGBasePositionerPrivate::getEffectiveLayoutDirection(this);
+}
+
+void QSGRow::doPositioning(QSizeF *contentSize)
+{
+ QSGBasePositionerPrivate *d = static_cast<QSGBasePositionerPrivate* >(QSGBasePositionerPrivate::get(this));
+ int hoffset = 0;
+
+ QList<int> hoffsets;
+ for (int ii = 0; ii < positionedItems.count(); ++ii) {
+ const PositionedItem &child = positionedItems.at(ii);
+ if (!child.item || !child.isVisible)
+ continue;
+
+ if (d->isLeftToRight()) {
+ if (child.item->x() != hoffset)
+ positionX(hoffset, child);
+ } else {
+ hoffsets << hoffset;
+ }
+
+ contentSize->setHeight(qMax(contentSize->height(), child.item->height()));
+
+ hoffset += child.item->width();
+ hoffset += spacing();
+ }
+
+ contentSize->setWidth(hoffset - spacing());
+
+ if (d->isLeftToRight())
+ return;
+
+ //Right to Left layout
+ int end = 0;
+ if (!widthValid())
+ end = contentSize->width();
+ else
+ end = width();
+
+ int acc = 0;
+ for (int ii = 0; ii < positionedItems.count(); ++ii) {
+ const PositionedItem &child = positionedItems.at(ii);
+ if (!child.item || !child.isVisible)
+ continue;
+ hoffset = end - hoffsets[acc++] - child.item->width();
+ if (child.item->x() != hoffset)
+ positionX(hoffset, child);
+ }
+}
+
+void QSGRow::reportConflictingAnchors()
+{
+ QSGBasePositionerPrivate *d = static_cast<QSGBasePositionerPrivate*>(QSGBasePositionerPrivate::get(this));
+ for (int ii = 0; ii < positionedItems.count(); ++ii) {
+ const PositionedItem &child = positionedItems.at(ii);
+ if (child.item) {
+ QSGAnchors *anchors = QSGItemPrivate::get(static_cast<QSGItem *>(child.item))->_anchors;
+ if (anchors) {
+ QSGAnchors::Anchors usedAnchors = anchors->usedAnchors();
+ if (usedAnchors & QSGAnchors::LeftAnchor ||
+ usedAnchors & QSGAnchors::RightAnchor ||
+ usedAnchors & QSGAnchors::HCenterAnchor ||
+ anchors->fill() || anchors->centerIn()) {
+ d->anchorConflict = true;
+ break;
+ }
+ }
+ }
+ }
+ if (d->anchorConflict)
+ qmlInfo(this) << "Cannot specify left, right, horizontalCenter, fill or centerIn anchors for items inside Row";
+}
+
+QSGGrid::QSGGrid(QSGItem *parent) :
+ QSGBasePositioner(Both, parent), m_rows(-1), m_columns(-1), m_flow(LeftToRight)
+{
+}
+
+void QSGGrid::setColumns(const int columns)
+{
+ if (columns == m_columns)
+ return;
+ m_columns = columns;
+ prePositioning();
+ emit columnsChanged();
+}
+
+void QSGGrid::setRows(const int rows)
+{
+ if (rows == m_rows)
+ return;
+ m_rows = rows;
+ prePositioning();
+ emit rowsChanged();
+}
+
+QSGGrid::Flow QSGGrid::flow() const
+{
+ return m_flow;
+}
+
+void QSGGrid::setFlow(Flow flow)
+{
+ if (m_flow != flow) {
+ m_flow = flow;
+ prePositioning();
+ emit flowChanged();
+ }
+}
+
+Qt::LayoutDirection QSGGrid::layoutDirection() const
+{
+ return QSGBasePositionerPrivate::getLayoutDirection(this);
+}
+
+void QSGGrid::setLayoutDirection(Qt::LayoutDirection layoutDirection)
+{
+ QSGBasePositionerPrivate *d = static_cast<QSGBasePositionerPrivate*>(QSGBasePositionerPrivate::get(this));
+ if (d->layoutDirection != layoutDirection) {
+ d->layoutDirection = layoutDirection;
+ // For RTL layout the positioning changes when the width changes.
+ if (d->layoutDirection == Qt::RightToLeft)
+ d->addItemChangeListener(d, QSGItemPrivate::Geometry);
+ else
+ d->removeItemChangeListener(d, QSGItemPrivate::Geometry);
+ prePositioning();
+ emit layoutDirectionChanged();
+ emit effectiveLayoutDirectionChanged();
+ }
+}
+
+Qt::LayoutDirection QSGGrid::effectiveLayoutDirection() const
+{
+ return QSGBasePositionerPrivate::getEffectiveLayoutDirection(this);
+}
+
+void QSGGrid::doPositioning(QSizeF *contentSize)
+{
+ QSGBasePositionerPrivate *d = static_cast<QSGBasePositionerPrivate*>(QSGBasePositionerPrivate::get(this));
+ int c = m_columns;
+ int r = m_rows;
+ //Is allocating the extra QPODVector too much overhead?
+ QPODVector<PositionedItem, 8> visibleItems;//we aren't concerned with invisible items
+ visibleItems.reserve(positionedItems.count());
+ for(int i=0; i<positionedItems.count(); i++)
+ if(positionedItems[i].item && positionedItems[i].isVisible)
+ visibleItems.append(positionedItems[i]);
+
+ int numVisible = visibleItems.count();
+ if (m_columns <= 0 && m_rows <= 0){
+ c = 4;
+ r = (numVisible+3)/4;
+ } else if (m_rows <= 0){
+ r = (numVisible+(m_columns-1))/m_columns;
+ } else if (m_columns <= 0){
+ c = (numVisible+(m_rows-1))/m_rows;
+ }
+
+ if(r==0 || c==0)
+ return; //Nothing to do
+
+ QList<int> maxColWidth;
+ QList<int> maxRowHeight;
+ int childIndex =0;
+ if (m_flow == LeftToRight) {
+ for (int i=0; i < r; i++){
+ for (int j=0; j < c; j++){
+ if (j==0)
+ maxRowHeight << 0;
+ if (i==0)
+ maxColWidth << 0;
+
+ if (childIndex == visibleItems.count())
+ break;
+
+ const PositionedItem &child = visibleItems.at(childIndex++);
+ if (child.item->width() > maxColWidth[j])
+ maxColWidth[j] = child.item->width();
+ if (child.item->height() > maxRowHeight[i])
+ maxRowHeight[i] = child.item->height();
+ }
+ }
+ } else {
+ for (int j=0; j < c; j++){
+ for (int i=0; i < r; i++){
+ if (j==0)
+ maxRowHeight << 0;
+ if (i==0)
+ maxColWidth << 0;
+
+ if (childIndex == visibleItems.count())
+ break;
+
+ const PositionedItem &child = visibleItems.at(childIndex++);
+ if (child.item->width() > maxColWidth[j])
+ maxColWidth[j] = child.item->width();
+ if (child.item->height() > maxRowHeight[i])
+ maxRowHeight[i] = child.item->height();
+ }
+ }
+ }
+
+ int widthSum = 0;
+ for (int j=0; j < maxColWidth.size(); j++){
+ if (j)
+ widthSum += spacing();
+ widthSum += maxColWidth[j];
+ }
+
+ int heightSum = 0;
+ for (int i=0; i < maxRowHeight.size(); i++){
+ if (i)
+ heightSum += spacing();
+ heightSum += maxRowHeight[i];
+ }
+
+ contentSize->setHeight(heightSum);
+ contentSize->setWidth(widthSum);
+
+ int end = 0;
+ if (widthValid())
+ end = width();
+ else
+ end = widthSum;
+
+ int xoffset=0;
+ if (!d->isLeftToRight())
+ xoffset = end;
+ int yoffset=0;
+ int curRow =0;
+ int curCol =0;
+ for (int i = 0; i < visibleItems.count(); ++i) {
+ const PositionedItem &child = visibleItems.at(i);
+ int childXOffset = xoffset;
+ if (!d->isLeftToRight())
+ childXOffset -= child.item->width();
+ if ((child.item->x() != childXOffset) || (child.item->y() != yoffset)){
+ positionX(childXOffset, child);
+ positionY(yoffset, child);
+ }
+
+ if (m_flow == LeftToRight) {
+ if (d->isLeftToRight())
+ xoffset += maxColWidth[curCol]+spacing();
+ else
+ xoffset -= maxColWidth[curCol]+spacing();
+ curCol++;
+ curCol%=c;
+ if (!curCol){
+ yoffset += maxRowHeight[curRow]+spacing();
+ if (d->isLeftToRight())
+ xoffset = 0;
+ else
+ xoffset = end;
+ curRow++;
+ if (curRow>=r)
+ break;
+ }
+ } else {
+ yoffset+=maxRowHeight[curRow]+spacing();
+ curRow++;
+ curRow%=r;
+ if (!curRow){
+ if (d->isLeftToRight())
+ xoffset += maxColWidth[curCol]+spacing();
+ else
+ xoffset -= maxColWidth[curCol]+spacing();
+ yoffset=0;
+ curCol++;
+ if (curCol>=c)
+ break;
+ }
+ }
+ }
+}
+
+void QSGGrid::reportConflictingAnchors()
+{
+ QSGBasePositionerPrivate *d = static_cast<QSGBasePositionerPrivate*>(QSGBasePositionerPrivate::get(this));
+ for (int ii = 0; ii < positionedItems.count(); ++ii) {
+ const PositionedItem &child = positionedItems.at(ii);
+ if (child.item) {
+ QSGAnchors *anchors = QSGItemPrivate::get(static_cast<QSGItem *>(child.item))->_anchors;
+ if (anchors && (anchors->usedAnchors() || anchors->fill() || anchors->centerIn())) {
+ d->anchorConflict = true;
+ break;
+ }
+ }
+ }
+ if (d->anchorConflict)
+ qmlInfo(this) << "Cannot specify anchors for items inside Grid";
+}
+
+class QSGFlowPrivate : public QSGBasePositionerPrivate
+{
+ Q_DECLARE_PUBLIC(QSGFlow)
+
+public:
+ QSGFlowPrivate()
+ : QSGBasePositionerPrivate(), flow(QSGFlow::LeftToRight)
+ {}
+
+ QSGFlow::Flow flow;
+};
+
+QSGFlow::QSGFlow(QSGItem *parent)
+: QSGBasePositioner(*(new QSGFlowPrivate), Both, parent)
+{
+ Q_D(QSGFlow);
+ // Flow layout requires relayout if its own size changes too.
+ d->addItemChangeListener(d, QSGItemPrivate::Geometry);
+}
+
+QSGFlow::Flow QSGFlow::flow() const
+{
+ Q_D(const QSGFlow);
+ return d->flow;
+}
+
+void QSGFlow::setFlow(Flow flow)
+{
+ Q_D(QSGFlow);
+ if (d->flow != flow) {
+ d->flow = flow;
+ prePositioning();
+ emit flowChanged();
+ }
+}
+
+Qt::LayoutDirection QSGFlow::layoutDirection() const
+{
+ Q_D(const QSGFlow);
+ return d->layoutDirection;
+}
+
+void QSGFlow::setLayoutDirection(Qt::LayoutDirection layoutDirection)
+{
+ Q_D(QSGFlow);
+ if (d->layoutDirection != layoutDirection) {
+ d->layoutDirection = layoutDirection;
+ prePositioning();
+ emit layoutDirectionChanged();
+ emit effectiveLayoutDirectionChanged();
+ }
+}
+
+Qt::LayoutDirection QSGFlow::effectiveLayoutDirection() const
+{
+ return QSGBasePositionerPrivate::getEffectiveLayoutDirection(this);
+}
+
+void QSGFlow::doPositioning(QSizeF *contentSize)
+{
+ Q_D(QSGFlow);
+
+ int hoffset = 0;
+ int voffset = 0;
+ int linemax = 0;
+ QList<int> hoffsets;
+
+ for (int i = 0; i < positionedItems.count(); ++i) {
+ const PositionedItem &child = positionedItems.at(i);
+ if (!child.item || !child.isVisible)
+ continue;
+
+ if (d->flow == LeftToRight) {
+ if (widthValid() && hoffset && hoffset + child.item->width() > width()) {
+ hoffset = 0;
+ voffset += linemax + spacing();
+ linemax = 0;
+ }
+ } else {
+ if (heightValid() && voffset && voffset + child.item->height() > height()) {
+ voffset = 0;
+ hoffset += linemax + spacing();
+ linemax = 0;
+ }
+ }
+
+ if (d->isLeftToRight()) {
+ if (child.item->x() != hoffset)
+ positionX(hoffset, child);
+ } else {
+ hoffsets << hoffset;
+ }
+ if (child.item->y() != voffset)
+ positionY(voffset, child);
+
+ contentSize->setWidth(qMax(contentSize->width(), hoffset + child.item->width()));
+ contentSize->setHeight(qMax(contentSize->height(), voffset + child.item->height()));
+
+ if (d->flow == LeftToRight) {
+ hoffset += child.item->width();
+ hoffset += spacing();
+ linemax = qMax(linemax, qCeil(child.item->height()));
+ } else {
+ voffset += child.item->height();
+ voffset += spacing();
+ linemax = qMax(linemax, qCeil(child.item->width()));
+ }
+ }
+ if (d->isLeftToRight())
+ return;
+
+ int end;
+ if (widthValid())
+ end = width();
+ else
+ end = contentSize->width();
+ int acc = 0;
+ for (int i = 0; i < positionedItems.count(); ++i) {
+ const PositionedItem &child = positionedItems.at(i);
+ if (!child.item || !child.isVisible)
+ continue;
+ hoffset = end - hoffsets[acc++] - child.item->width();
+ if (child.item->x() != hoffset)
+ positionX(hoffset, child);
+ }
+}
+
+void QSGFlow::reportConflictingAnchors()
+{
+ Q_D(QSGFlow);
+ for (int ii = 0; ii < positionedItems.count(); ++ii) {
+ const PositionedItem &child = positionedItems.at(ii);
+ if (child.item) {
+ QSGAnchors *anchors = QSGItemPrivate::get(static_cast<QSGItem *>(child.item))->_anchors;
+ if (anchors && (anchors->usedAnchors() || anchors->fill() || anchors->centerIn())) {
+ d->anchorConflict = true;
+ break;
+ }
+ }
+ }
+ if (d->anchorConflict)
+ qmlInfo(this) << "Cannot specify anchors for items inside Flow";
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/items/qsgpositioners_p.h b/src/declarative/items/qsgpositioners_p.h
new file mode 100644
index 0000000000..eb0e73456b
--- /dev/null
+++ b/src/declarative/items/qsgpositioners_p.h
@@ -0,0 +1,242 @@
+// Commit: 2c7cab4172f1acc86fd49345a2847417e162f2c3
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGPOSITIONERS_P_H
+#define QSGPOSITIONERS_P_H
+
+#include "qsgimplicitsizeitem_p.h"
+
+#include <private/qdeclarativestate_p.h>
+#include <private/qpodvector_p.h>
+
+#include <QtCore/qobject.h>
+#include <QtCore/qstring.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QSGBasePositionerPrivate;
+
+class Q_DECLARATIVE_PRIVATE_EXPORT QSGBasePositioner : public QSGImplicitSizeItem
+{
+ Q_OBJECT
+
+ Q_PROPERTY(int spacing READ spacing WRITE setSpacing NOTIFY spacingChanged)
+ Q_PROPERTY(QDeclarativeTransition *move READ move WRITE setMove NOTIFY moveChanged)
+ Q_PROPERTY(QDeclarativeTransition *add READ add WRITE setAdd NOTIFY addChanged)
+public:
+ enum PositionerType { None = 0x0, Horizontal = 0x1, Vertical = 0x2, Both = 0x3 };
+ QSGBasePositioner(PositionerType, QSGItem *parent);
+ ~QSGBasePositioner();
+
+ int spacing() const;
+ void setSpacing(int);
+
+ QDeclarativeTransition *move() const;
+ void setMove(QDeclarativeTransition *);
+
+ QDeclarativeTransition *add() const;
+ void setAdd(QDeclarativeTransition *);
+
+protected:
+ QSGBasePositioner(QSGBasePositionerPrivate &dd, PositionerType at, QSGItem *parent);
+ virtual void componentComplete();
+ virtual void itemChange(ItemChange, const ItemChangeData &);
+ void finishApplyTransitions();
+
+Q_SIGNALS:
+ void spacingChanged();
+ void moveChanged();
+ void addChanged();
+
+protected Q_SLOTS:
+ void prePositioning();
+
+protected:
+ virtual void doPositioning(QSizeF *contentSize)=0;
+ virtual void reportConflictingAnchors()=0;
+ class PositionedItem {
+ public :
+ PositionedItem(QSGItem *i) : item(i), isNew(false), isVisible(true) {}
+ bool operator==(const PositionedItem &other) const { return other.item == item; }
+ QSGItem *item;
+ bool isNew;
+ bool isVisible;
+ };
+
+ QPODVector<PositionedItem,8> positionedItems;
+ void positionX(int,const PositionedItem &target);
+ void positionY(int,const PositionedItem &target);
+
+private:
+ Q_DISABLE_COPY(QSGBasePositioner)
+ Q_DECLARE_PRIVATE(QSGBasePositioner)
+};
+
+class Q_AUTOTEST_EXPORT QSGColumn : public QSGBasePositioner
+{
+ Q_OBJECT
+public:
+ QSGColumn(QSGItem *parent=0);
+protected:
+ virtual void doPositioning(QSizeF *contentSize);
+ virtual void reportConflictingAnchors();
+private:
+ Q_DISABLE_COPY(QSGColumn)
+};
+
+class Q_AUTOTEST_EXPORT QSGRow: public QSGBasePositioner
+{
+ Q_OBJECT
+ Q_PROPERTY(Qt::LayoutDirection layoutDirection READ layoutDirection WRITE setLayoutDirection NOTIFY layoutDirectionChanged)
+ Q_PROPERTY(Qt::LayoutDirection effectiveLayoutDirection READ effectiveLayoutDirection NOTIFY effectiveLayoutDirectionChanged)
+public:
+ QSGRow(QSGItem *parent=0);
+
+ Qt::LayoutDirection layoutDirection() const;
+ void setLayoutDirection (Qt::LayoutDirection);
+ Qt::LayoutDirection effectiveLayoutDirection() const;
+
+Q_SIGNALS:
+ void layoutDirectionChanged();
+ void effectiveLayoutDirectionChanged();
+
+protected:
+ virtual void doPositioning(QSizeF *contentSize);
+ virtual void reportConflictingAnchors();
+private:
+ Q_DISABLE_COPY(QSGRow)
+};
+
+class Q_AUTOTEST_EXPORT QSGGrid : public QSGBasePositioner
+{
+ Q_OBJECT
+ Q_PROPERTY(int rows READ rows WRITE setRows NOTIFY rowsChanged)
+ Q_PROPERTY(int columns READ columns WRITE setColumns NOTIFY columnsChanged)
+ Q_PROPERTY(Flow flow READ flow WRITE setFlow NOTIFY flowChanged)
+ Q_PROPERTY(Qt::LayoutDirection layoutDirection READ layoutDirection WRITE setLayoutDirection NOTIFY layoutDirectionChanged)
+ Q_PROPERTY(Qt::LayoutDirection effectiveLayoutDirection READ effectiveLayoutDirection NOTIFY effectiveLayoutDirectionChanged)
+
+public:
+ QSGGrid(QSGItem *parent=0);
+
+ int rows() const {return m_rows;}
+ void setRows(const int rows);
+
+ int columns() const {return m_columns;}
+ void setColumns(const int columns);
+
+ Q_ENUMS(Flow)
+ enum Flow { LeftToRight, TopToBottom };
+ Flow flow() const;
+ void setFlow(Flow);
+
+ Qt::LayoutDirection layoutDirection() const;
+ void setLayoutDirection (Qt::LayoutDirection);
+ Qt::LayoutDirection effectiveLayoutDirection() const;
+
+Q_SIGNALS:
+ void rowsChanged();
+ void columnsChanged();
+ void flowChanged();
+ void layoutDirectionChanged();
+ void effectiveLayoutDirectionChanged();
+
+protected:
+ virtual void doPositioning(QSizeF *contentSize);
+ virtual void reportConflictingAnchors();
+
+private:
+ int m_rows;
+ int m_columns;
+ Flow m_flow;
+ Q_DISABLE_COPY(QSGGrid)
+};
+
+class QSGFlowPrivate;
+class Q_AUTOTEST_EXPORT QSGFlow: public QSGBasePositioner
+{
+ Q_OBJECT
+ Q_PROPERTY(Flow flow READ flow WRITE setFlow NOTIFY flowChanged)
+ Q_PROPERTY(Qt::LayoutDirection layoutDirection READ layoutDirection WRITE setLayoutDirection NOTIFY layoutDirectionChanged)
+ Q_PROPERTY(Qt::LayoutDirection effectiveLayoutDirection READ effectiveLayoutDirection NOTIFY effectiveLayoutDirectionChanged)
+public:
+ QSGFlow(QSGItem *parent=0);
+
+ Q_ENUMS(Flow)
+ enum Flow { LeftToRight, TopToBottom };
+ Flow flow() const;
+ void setFlow(Flow);
+
+ Qt::LayoutDirection layoutDirection() const;
+ void setLayoutDirection (Qt::LayoutDirection);
+ Qt::LayoutDirection effectiveLayoutDirection() const;
+
+Q_SIGNALS:
+ void flowChanged();
+ void layoutDirectionChanged();
+ void effectiveLayoutDirectionChanged();
+
+protected:
+ virtual void doPositioning(QSizeF *contentSize);
+ virtual void reportConflictingAnchors();
+protected:
+ QSGFlow(QSGFlowPrivate &dd, QSGItem *parent);
+private:
+ Q_DISABLE_COPY(QSGFlow)
+ Q_DECLARE_PRIVATE(QSGFlow)
+};
+
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QSGColumn)
+QML_DECLARE_TYPE(QSGRow)
+QML_DECLARE_TYPE(QSGGrid)
+QML_DECLARE_TYPE(QSGFlow)
+
+QT_END_HEADER
+
+#endif // QSGPOSITIONERS_P_H
diff --git a/src/declarative/items/qsgpositioners_p_p.h b/src/declarative/items/qsgpositioners_p_p.h
new file mode 100644
index 0000000000..49de12a1fd
--- /dev/null
+++ b/src/declarative/items/qsgpositioners_p_p.h
@@ -0,0 +1,174 @@
+// Commit: 2c7cab4172f1acc86fd49345a2847417e162f2c3
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGPOSITIONERS_P_P_H
+#define QSGPOSITIONERS_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 "qsgpositioners_p.h"
+#include "qsgimplicitsizeitem_p_p.h"
+
+#include <private/qdeclarativestate_p.h>
+#include <private/qdeclarativetransitionmanager_p_p.h>
+#include <private/qdeclarativestateoperations_p.h>
+
+#include <QtCore/qobject.h>
+#include <QtCore/qstring.h>
+#include <QtCore/qtimer.h>
+
+QT_BEGIN_NAMESPACE
+
+class QSGBasePositionerPrivate : public QSGImplicitSizeItemPrivate, public QSGItemChangeListener
+{
+ Q_DECLARE_PUBLIC(QSGBasePositioner)
+
+public:
+ QSGBasePositionerPrivate()
+ : spacing(0), type(QSGBasePositioner::None)
+ , moveTransition(0), addTransition(0), queuedPositioning(false)
+ , doingPositioning(false), anchorConflict(false), layoutDirection(Qt::LeftToRight)
+ {
+ }
+
+ void init(QSGBasePositioner::PositionerType at)
+ {
+ type = at;
+ childrenDoNotOverlap = true;
+ }
+
+ int spacing;
+
+ QSGBasePositioner::PositionerType type;
+ QDeclarativeTransition *moveTransition;
+ QDeclarativeTransition *addTransition;
+ QDeclarativeStateOperation::ActionList addActions;
+ QDeclarativeStateOperation::ActionList moveActions;
+ QDeclarativeTransitionManager addTransitionManager;
+ QDeclarativeTransitionManager moveTransitionManager;
+
+ void watchChanges(QSGItem *other);
+ void unwatchChanges(QSGItem* other);
+ bool queuedPositioning : 1;
+ bool doingPositioning : 1;
+ bool anchorConflict : 1;
+
+ Qt::LayoutDirection layoutDirection;
+
+ void schedulePositioning()
+ {
+ Q_Q(QSGBasePositioner);
+ if(!queuedPositioning){
+ QTimer::singleShot(0,q,SLOT(prePositioning()));
+ queuedPositioning = true;
+ }
+ }
+
+ void mirrorChange() {
+ Q_Q(QSGBasePositioner);
+ if (type != QSGBasePositioner::Vertical)
+ q->prePositioning();
+ }
+ bool isLeftToRight() const {
+ if (type == QSGBasePositioner::Vertical)
+ return true;
+ else
+ return effectiveLayoutMirror ? layoutDirection == Qt::RightToLeft : layoutDirection == Qt::LeftToRight;
+ }
+
+ virtual void itemSiblingOrderChanged(QSGItem* other)
+ {
+ Q_UNUSED(other);
+ //Delay is due to many children often being reordered at once
+ //And we only want to reposition them all once
+ schedulePositioning();
+ }
+
+ void itemGeometryChanged(QSGItem *, const QRectF &newGeometry, const QRectF &oldGeometry)
+ {
+ Q_Q(QSGBasePositioner);
+ if (newGeometry.size() != oldGeometry.size())
+ q->prePositioning();
+ }
+
+ virtual void itemVisibilityChanged(QSGItem *)
+ {
+ schedulePositioning();
+ }
+ virtual void itemOpacityChanged(QSGItem *)
+ {
+ Q_Q(QSGBasePositioner);
+ q->prePositioning();
+ }
+
+ void itemDestroyed(QSGItem *item)
+ {
+ Q_Q(QSGBasePositioner);
+ q->positionedItems.removeOne(QSGBasePositioner::PositionedItem(item));
+ }
+
+ static Qt::LayoutDirection getLayoutDirection(const QSGBasePositioner *positioner)
+ {
+ return positioner->d_func()->layoutDirection;
+ }
+
+ static Qt::LayoutDirection getEffectiveLayoutDirection(const QSGBasePositioner *positioner)
+ {
+ if (positioner->d_func()->effectiveLayoutMirror)
+ return positioner->d_func()->layoutDirection == Qt::RightToLeft ? Qt::LeftToRight : Qt::RightToLeft;
+ else
+ return positioner->d_func()->layoutDirection;
+ }
+};
+
+QT_END_NAMESPACE
+
+#endif // QSGPOSITIONERS_P_P_H
diff --git a/src/declarative/items/qsgrectangle.cpp b/src/declarative/items/qsgrectangle.cpp
new file mode 100644
index 0000000000..e97abe3e1c
--- /dev/null
+++ b/src/declarative/items/qsgrectangle.cpp
@@ -0,0 +1,308 @@
+// Commit: acc903853d5ac54d646d324b7386c998bc07d464
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgrectangle_p.h"
+#include "qsgrectangle_p_p.h"
+
+#include <private/qsgcontext_p.h>
+#include <private/qsgadaptationlayer_p.h>
+
+#include <QtGui/qpixmapcache.h>
+#include <QtCore/qstringbuilder.h>
+#include <QtCore/qmath.h>
+
+QT_BEGIN_NAMESPACE
+
+// XXX todo - should we change rectangle to draw entirely within its width/height?
+
+QSGPen::QSGPen(QObject *parent)
+ : QObject(parent)
+ , m_width(1)
+ , m_color("#000000")
+ , m_aligned(true)
+ , m_valid(false)
+{
+}
+
+qreal QSGPen::width() const
+{
+ return m_width;
+}
+
+void QSGPen::setWidth(qreal w)
+{
+ if (m_width == w && m_valid)
+ return;
+
+ m_width = w;
+ m_valid = m_color.alpha() && (qRound(m_width) >= 1 || (!m_aligned && m_width > 0));
+ emit penChanged();
+}
+
+QColor QSGPen::color() const
+{
+ return m_color;
+}
+
+void QSGPen::setColor(const QColor &c)
+{
+ m_color = c;
+ m_valid = m_color.alpha() && (qRound(m_width) >= 1 || (!m_aligned && m_width > 0));
+ emit penChanged();
+}
+
+bool QSGPen::aligned() const
+{
+ return m_aligned;
+}
+
+void QSGPen::setAligned(bool aligned)
+{
+ if (aligned == m_aligned)
+ return;
+ m_aligned = aligned;
+ m_valid = m_color.alpha() && (qRound(m_width) >= 1 || (!m_aligned && m_width > 0));
+ emit penChanged();
+}
+
+bool QSGPen::isValid() const
+{
+ return m_valid;
+}
+
+QSGGradientStop::QSGGradientStop(QObject *parent)
+ : QObject(parent)
+{
+}
+
+qreal QSGGradientStop::position() const
+{
+ return m_position;
+}
+
+void QSGGradientStop::setPosition(qreal position)
+{
+ m_position = position; updateGradient();
+}
+
+QColor QSGGradientStop::color() const
+{
+ return m_color;
+}
+
+void QSGGradientStop::setColor(const QColor &color)
+{
+ m_color = color; updateGradient();
+}
+
+void QSGGradientStop::updateGradient()
+{
+ if (QSGGradient *grad = qobject_cast<QSGGradient*>(parent()))
+ grad->doUpdate();
+}
+
+QSGGradient::QSGGradient(QObject *parent)
+: QObject(parent), m_gradient(0)
+{
+}
+
+QSGGradient::~QSGGradient()
+{
+ delete m_gradient;
+}
+
+QDeclarativeListProperty<QSGGradientStop> QSGGradient::stops()
+{
+ return QDeclarativeListProperty<QSGGradientStop>(this, m_stops);
+}
+
+const QGradient *QSGGradient::gradient() const
+{
+ if (!m_gradient && !m_stops.isEmpty()) {
+ m_gradient = new QLinearGradient(0,0,0,1.0);
+ for (int i = 0; i < m_stops.count(); ++i) {
+ const QSGGradientStop *stop = m_stops.at(i);
+ m_gradient->setCoordinateMode(QGradient::ObjectBoundingMode);
+ m_gradient->setColorAt(stop->position(), stop->color());
+ }
+ }
+
+ return m_gradient;
+}
+
+void QSGGradient::doUpdate()
+{
+ delete m_gradient;
+ m_gradient = 0;
+ emit updated();
+}
+
+int QSGRectanglePrivate::doUpdateSlotIdx = -1;
+
+QSGRectangle::QSGRectangle(QSGItem *parent)
+: QSGItem(*(new QSGRectanglePrivate), parent)
+{
+ setFlag(ItemHasContents);
+}
+
+void QSGRectangle::doUpdate()
+{
+ Q_D(QSGRectangle);
+ const int pw = d->pen && d->pen->isValid() ? d->pen->width() : 0;
+ d->setPaintMargin((pw+1)/2);
+ update();
+}
+
+QSGPen *QSGRectangle::border()
+{
+ Q_D(QSGRectangle);
+ return d->getPen();
+}
+
+QSGGradient *QSGRectangle::gradient() const
+{
+ Q_D(const QSGRectangle);
+ return d->gradient;
+}
+
+void QSGRectangle::setGradient(QSGGradient *gradient)
+{
+ Q_D(QSGRectangle);
+ if (d->gradient == gradient)
+ return;
+ static int updatedSignalIdx = -1;
+ if (updatedSignalIdx < 0)
+ updatedSignalIdx = QSGGradient::staticMetaObject.indexOfSignal("updated()");
+ if (d->doUpdateSlotIdx < 0)
+ d->doUpdateSlotIdx = QSGRectangle::staticMetaObject.indexOfSlot("doUpdate()");
+ if (d->gradient)
+ QMetaObject::disconnect(d->gradient, updatedSignalIdx, this, d->doUpdateSlotIdx);
+ d->gradient = gradient;
+ if (d->gradient)
+ QMetaObject::connect(d->gradient, updatedSignalIdx, this, d->doUpdateSlotIdx);
+ update();
+}
+
+qreal QSGRectangle::radius() const
+{
+ Q_D(const QSGRectangle);
+ return d->radius;
+}
+
+void QSGRectangle::setRadius(qreal radius)
+{
+ Q_D(QSGRectangle);
+ if (d->radius == radius)
+ return;
+
+ d->radius = radius;
+ update();
+ emit radiusChanged();
+}
+
+QColor QSGRectangle::color() const
+{
+ Q_D(const QSGRectangle);
+ return d->color;
+}
+
+void QSGRectangle::setColor(const QColor &c)
+{
+ Q_D(QSGRectangle);
+ if (d->color == c)
+ return;
+
+ d->color = c;
+ update();
+ emit colorChanged();
+}
+
+QSGNode *QSGRectangle::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data)
+{
+ Q_UNUSED(data);
+ Q_D(QSGRectangle);
+
+ if (width() <= 0 || height() <= 0) {
+ delete oldNode;
+ return 0;
+ }
+
+ QSGRectangleNode *rectangle = static_cast<QSGRectangleNode *>(oldNode);
+ if (!rectangle) rectangle = d->sceneGraphContext()->createRectangleNode();
+
+ rectangle->setRect(QRectF(0, 0, width(), height()));
+ rectangle->setColor(d->color);
+
+ if (d->pen && d->pen->isValid()) {
+ rectangle->setPenColor(d->pen->color());
+ rectangle->setPenWidth(d->pen->width());
+ rectangle->setAligned(d->pen->aligned());
+ } else {
+ rectangle->setPenWidth(0);
+ }
+
+ rectangle->setRadius(d->radius);
+
+ QGradientStops stops;
+ if (d->gradient) {
+ QList<QSGGradientStop *> qxstops = d->gradient->m_stops;
+ for (int i = 0; i < qxstops.size(); ++i){
+ int j = 0;
+ while (j < stops.size() && stops.at(j).first < qxstops[i]->position())
+ j++;
+ stops.insert(j, QGradientStop(qxstops.at(i)->position(), qxstops.at(i)->color()));
+ }
+ }
+ rectangle->setGradientStops(stops);
+
+ rectangle->update();
+
+ return rectangle;
+}
+
+QRectF QSGRectangle::boundingRect() const
+{
+ Q_D(const QSGRectangle);
+ return QRectF(-d->paintmargin, -d->paintmargin, width()+d->paintmargin*2, height()+d->paintmargin*2);
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/items/qsgrectangle_p.h b/src/declarative/items/qsgrectangle_p.h
new file mode 100644
index 0000000000..6157d82442
--- /dev/null
+++ b/src/declarative/items/qsgrectangle_p.h
@@ -0,0 +1,189 @@
+// Commit: ac5c099cc3c5b8c7eec7a49fdeb8a21037230350
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGRECTANGLE_P_H
+#define QSGRECTANGLE_P_H
+
+#include "qsgitem.h"
+
+#include <QtGui/qbrush.h>
+
+#include <private/qdeclarativeglobal_p.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+class Q_DECLARATIVE_PRIVATE_EXPORT QSGPen : public QObject
+{
+ Q_OBJECT
+
+ Q_PROPERTY(qreal width READ width WRITE setWidth NOTIFY penChanged)
+ Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY penChanged)
+ Q_PROPERTY(bool aligned READ aligned WRITE setAligned NOTIFY penChanged)
+public:
+ QSGPen(QObject *parent=0);
+
+ qreal width() const;
+ void setWidth(qreal w);
+
+ QColor color() const;
+ void setColor(const QColor &c);
+
+ bool aligned() const;
+ void setAligned(bool aligned);
+
+ bool isValid() const;
+
+Q_SIGNALS:
+ void penChanged();
+
+private:
+ qreal m_width;
+ QColor m_color;
+ bool m_aligned : 1;
+ bool m_valid : 1;
+};
+
+class Q_AUTOTEST_EXPORT QSGGradientStop : public QObject
+{
+ Q_OBJECT
+
+ Q_PROPERTY(qreal position READ position WRITE setPosition)
+ Q_PROPERTY(QColor color READ color WRITE setColor)
+
+public:
+ QSGGradientStop(QObject *parent=0);
+
+ qreal position() const;
+ void setPosition(qreal position);
+
+ QColor color() const;
+ void setColor(const QColor &color);
+
+private:
+ void updateGradient();
+
+private:
+ qreal m_position;
+ QColor m_color;
+};
+
+class Q_AUTOTEST_EXPORT QSGGradient : public QObject
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QDeclarativeListProperty<QSGGradientStop> stops READ stops)
+ Q_CLASSINFO("DefaultProperty", "stops")
+
+public:
+ QSGGradient(QObject *parent=0);
+ ~QSGGradient();
+
+ QDeclarativeListProperty<QSGGradientStop> stops();
+
+ const QGradient *gradient() const;
+
+Q_SIGNALS:
+ void updated();
+
+private:
+ void doUpdate();
+
+private:
+ QList<QSGGradientStop *> m_stops;
+ mutable QGradient *m_gradient;
+ friend class QSGRectangle;
+ friend class QSGGradientStop;
+};
+
+class QSGRectanglePrivate;
+class Q_DECLARATIVE_PRIVATE_EXPORT QSGRectangle : public QSGItem
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged)
+ Q_PROPERTY(QSGGradient *gradient READ gradient WRITE setGradient)
+ Q_PROPERTY(QSGPen * border READ border CONSTANT)
+ Q_PROPERTY(qreal radius READ radius WRITE setRadius NOTIFY radiusChanged)
+public:
+ QSGRectangle(QSGItem *parent=0);
+
+ QColor color() const;
+ void setColor(const QColor &);
+
+ QSGPen *border();
+
+ QSGGradient *gradient() const;
+ void setGradient(QSGGradient *gradient);
+
+ qreal radius() const;
+ void setRadius(qreal radius);
+
+ QRectF boundingRect() const;
+
+Q_SIGNALS:
+ void colorChanged();
+ void radiusChanged();
+
+protected:
+ virtual QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *);
+
+private Q_SLOTS:
+ void doUpdate();
+
+private:
+ Q_DISABLE_COPY(QSGRectangle)
+ Q_DECLARE_PRIVATE(QSGRectangle)
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QSGPen)
+QML_DECLARE_TYPE(QSGGradientStop)
+QML_DECLARE_TYPE(QSGGradient)
+QML_DECLARE_TYPE(QSGRectangle)
+
+QT_END_HEADER
+
+#endif // QSGRECTANGLE_P_H
diff --git a/src/declarative/items/qsgrectangle_p_p.h b/src/declarative/items/qsgrectangle_p_p.h
new file mode 100644
index 0000000000..15bbd1f032
--- /dev/null
+++ b/src/declarative/items/qsgrectangle_p_p.h
@@ -0,0 +1,109 @@
+// Commit: ac5c099cc3c5b8c7eec7a49fdeb8a21037230350
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGRECTANGLE_P_P_H
+#define QSGRECTANGLE_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 "qsgitem_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QSGGradient;
+class QSGRectangle;
+class QSGRectanglePrivate : public QSGItemPrivate
+{
+ Q_DECLARE_PUBLIC(QSGRectangle)
+
+public:
+ QSGRectanglePrivate() :
+ color(Qt::white), gradient(0), pen(0), radius(0), paintmargin(0)
+ {
+ }
+
+ ~QSGRectanglePrivate()
+ {
+ delete pen;
+ }
+
+ QColor color;
+ QSGGradient *gradient;
+ QSGPen *pen;
+ qreal radius;
+ qreal paintmargin;
+ static int doUpdateSlotIdx;
+
+ QSGPen *getPen() {
+ if (!pen) {
+ Q_Q(QSGRectangle);
+ pen = new QSGPen;
+ static int penChangedSignalIdx = -1;
+ if (penChangedSignalIdx < 0)
+ penChangedSignalIdx = QSGPen::staticMetaObject.indexOfSignal("penChanged()");
+ if (doUpdateSlotIdx < 0)
+ doUpdateSlotIdx = QSGRectangle::staticMetaObject.indexOfSlot("doUpdate()");
+ QMetaObject::connect(pen, penChangedSignalIdx, q, doUpdateSlotIdx);
+ }
+ return pen;
+ }
+
+ void setPaintMargin(qreal margin)
+ {
+ if (margin == paintmargin)
+ return;
+ paintmargin = margin;
+ }
+};
+
+QT_END_NAMESPACE
+
+#endif // QSGRECTANGLE_P_P_H
diff --git a/src/declarative/items/qsgrepeater.cpp b/src/declarative/items/qsgrepeater.cpp
new file mode 100644
index 0000000000..ac6086fc62
--- /dev/null
+++ b/src/declarative/items/qsgrepeater.cpp
@@ -0,0 +1,294 @@
+// Commit: a9f1eaa6a368bf7a72b52c428728a3e3e0a76209
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgrepeater_p.h"
+#include "qsgrepeater_p_p.h"
+#include "qsgvisualitemmodel_p.h"
+
+#include <private/qdeclarativeglobal_p.h>
+#include <private/qdeclarativelistaccessor_p.h>
+#include <private/qlistmodelinterface_p.h>
+
+QT_BEGIN_NAMESPACE
+
+QSGRepeaterPrivate::QSGRepeaterPrivate()
+: model(0), ownModel(false)
+{
+}
+
+QSGRepeaterPrivate::~QSGRepeaterPrivate()
+{
+ if (ownModel)
+ delete model;
+}
+
+QSGRepeater::QSGRepeater(QSGItem *parent)
+ : QSGItem(*(new QSGRepeaterPrivate), parent)
+{
+}
+
+QSGRepeater::~QSGRepeater()
+{
+}
+
+QVariant QSGRepeater::model() const
+{
+ Q_D(const QSGRepeater);
+ return d->dataSource;
+}
+
+void QSGRepeater::setModel(const QVariant &model)
+{
+ Q_D(QSGRepeater);
+ if (d->dataSource == model)
+ return;
+
+ clear();
+ if (d->model) {
+ disconnect(d->model, SIGNAL(itemsInserted(int,int)), this, SLOT(itemsInserted(int,int)));
+ disconnect(d->model, SIGNAL(itemsRemoved(int,int)), this, SLOT(itemsRemoved(int,int)));
+ disconnect(d->model, SIGNAL(itemsMoved(int,int,int)), this, SLOT(itemsMoved(int,int,int)));
+ disconnect(d->model, SIGNAL(modelReset()), this, SLOT(modelReset()));
+ /*
+ disconnect(d->model, SIGNAL(createdItem(int,QSGItem*)), this, SLOT(createdItem(int,QSGItem*)));
+ disconnect(d->model, SIGNAL(destroyingItem(QSGItem*)), this, SLOT(destroyingItem(QSGItem*)));
+ */
+ }
+ d->dataSource = model;
+ QObject *object = qvariant_cast<QObject*>(model);
+ QSGVisualModel *vim = 0;
+ if (object && (vim = qobject_cast<QSGVisualModel *>(object))) {
+ if (d->ownModel) {
+ delete d->model;
+ d->ownModel = false;
+ }
+ d->model = vim;
+ } else {
+ if (!d->ownModel) {
+ d->model = new QSGVisualDataModel(qmlContext(this));
+ d->ownModel = true;
+ }
+ if (QSGVisualDataModel *dataModel = qobject_cast<QSGVisualDataModel*>(d->model))
+ dataModel->setModel(model);
+ }
+ if (d->model) {
+ connect(d->model, SIGNAL(itemsInserted(int,int)), this, SLOT(itemsInserted(int,int)));
+ connect(d->model, SIGNAL(itemsRemoved(int,int)), this, SLOT(itemsRemoved(int,int)));
+ connect(d->model, SIGNAL(itemsMoved(int,int,int)), this, SLOT(itemsMoved(int,int,int)));
+ connect(d->model, SIGNAL(modelReset()), this, SLOT(modelReset()));
+ /*
+ connect(d->model, SIGNAL(createdItem(int,QSGItem*)), this, SLOT(createdItem(int,QSGItem*)));
+ connect(d->model, SIGNAL(destroyingItem(QSGItem*)), this, SLOT(destroyingItem(QSGItem*)));
+ */
+ regenerate();
+ }
+ emit modelChanged();
+ emit countChanged();
+}
+
+QDeclarativeComponent *QSGRepeater::delegate() const
+{
+ Q_D(const QSGRepeater);
+ if (d->model) {
+ if (QSGVisualDataModel *dataModel = qobject_cast<QSGVisualDataModel*>(d->model))
+ return dataModel->delegate();
+ }
+
+ return 0;
+}
+
+void QSGRepeater::setDelegate(QDeclarativeComponent *delegate)
+{
+ Q_D(QSGRepeater);
+ if (QSGVisualDataModel *dataModel = qobject_cast<QSGVisualDataModel*>(d->model))
+ if (delegate == dataModel->delegate())
+ return;
+
+ if (!d->ownModel) {
+ d->model = new QSGVisualDataModel(qmlContext(this));
+ d->ownModel = true;
+ }
+ if (QSGVisualDataModel *dataModel = qobject_cast<QSGVisualDataModel*>(d->model)) {
+ dataModel->setDelegate(delegate);
+ regenerate();
+ emit delegateChanged();
+ }
+}
+
+int QSGRepeater::count() const
+{
+ Q_D(const QSGRepeater);
+ if (d->model)
+ return d->model->count();
+ return 0;
+}
+
+QSGItem *QSGRepeater::itemAt(int index) const
+{
+ Q_D(const QSGRepeater);
+ if (index >= 0 && index < d->deletables.count())
+ return d->deletables[index];
+ return 0;
+}
+
+void QSGRepeater::componentComplete()
+{
+ QSGItem::componentComplete();
+ regenerate();
+}
+
+void QSGRepeater::itemChange(ItemChange change, const ItemChangeData &value)
+{
+ QSGItem::itemChange(change, value);
+ if (change == ItemParentHasChanged) {
+ regenerate();
+ }
+}
+
+void QSGRepeater::clear()
+{
+ Q_D(QSGRepeater);
+ bool complete = isComponentComplete();
+
+ if (d->model) {
+ while (d->deletables.count() > 0) {
+ QSGItem *item = d->deletables.takeLast();
+ if (complete)
+ emit itemRemoved(d->deletables.count()-1, item);
+ d->model->release(item);
+ }
+ }
+ d->deletables.clear();
+}
+
+void QSGRepeater::regenerate()
+{
+ Q_D(QSGRepeater);
+ if (!isComponentComplete())
+ return;
+
+ clear();
+
+ if (!d->model || !d->model->count() || !d->model->isValid() || !parentItem() || !isComponentComplete())
+ return;
+
+ for (int ii = 0; ii < count(); ++ii) {
+ QSGItem *item = d->model->item(ii);
+ if (item) {
+ QDeclarative_setParent_noEvent(item, parentItem());
+ item->setParentItem(parentItem());
+ item->stackBefore(this);
+ d->deletables << item;
+ emit itemAdded(ii, item);
+ }
+ }
+}
+
+void QSGRepeater::itemsInserted(int index, int count)
+{
+ Q_D(QSGRepeater);
+ if (!isComponentComplete())
+ return;
+ for (int i = 0; i < count; ++i) {
+ int modelIndex = index + i;
+ QSGItem *item = d->model->item(modelIndex);
+ if (item) {
+ QDeclarative_setParent_noEvent(item, parentItem());
+ item->setParentItem(parentItem());
+ if (modelIndex < d->deletables.count())
+ item->stackBefore(d->deletables.at(modelIndex));
+ else
+ item->stackBefore(this);
+ d->deletables.insert(modelIndex, item);
+ emit itemAdded(modelIndex, item);
+ }
+ }
+ emit countChanged();
+}
+
+void QSGRepeater::itemsRemoved(int index, int count)
+{
+ Q_D(QSGRepeater);
+ if (!isComponentComplete() || count <= 0)
+ return;
+ while (count--) {
+ QSGItem *item = d->deletables.takeAt(index);
+ emit itemRemoved(index, item);
+ if (item)
+ d->model->release(item);
+ else
+ break;
+ }
+ emit countChanged();
+}
+
+void QSGRepeater::itemsMoved(int from, int to, int count)
+{
+ Q_D(QSGRepeater);
+ if (!isComponentComplete() || count <= 0)
+ return;
+ if (from + count > d->deletables.count()) {
+ regenerate();
+ return;
+ }
+ QList<QSGItem*> removed;
+ int removedCount = count;
+ while (removedCount--)
+ removed << d->deletables.takeAt(from);
+ for (int i = 0; i < count; ++i)
+ d->deletables.insert(to + i, removed.at(i));
+ d->deletables.last()->stackBefore(this);
+ for (int i = d->model->count()-1; i > 0; --i) {
+ QSGItem *item = d->deletables.at(i-1);
+ item->stackBefore(d->deletables.at(i));
+ }
+}
+
+void QSGRepeater::modelReset()
+{
+ if (!isComponentComplete())
+ return;
+ regenerate();
+ emit countChanged();
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/items/qsgrepeater_p.h b/src/declarative/items/qsgrepeater_p.h
new file mode 100644
index 0000000000..3a53fa4177
--- /dev/null
+++ b/src/declarative/items/qsgrepeater_p.h
@@ -0,0 +1,111 @@
+// Commit: ebd4bc73c46c2962742a682b6a391fb68c482aec
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGREPEATER_P_H
+#define QSGREPEATER_P_H
+
+#include "qsgitem.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QSGRepeaterPrivate;
+class Q_AUTOTEST_EXPORT QSGRepeater : public QSGItem
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QVariant model READ model WRITE setModel NOTIFY modelChanged)
+ Q_PROPERTY(QDeclarativeComponent *delegate READ delegate WRITE setDelegate NOTIFY delegateChanged)
+ Q_PROPERTY(int count READ count NOTIFY countChanged)
+ Q_CLASSINFO("DefaultProperty", "delegate")
+
+public:
+ QSGRepeater(QSGItem *parent=0);
+ virtual ~QSGRepeater();
+
+ QVariant model() const;
+ void setModel(const QVariant &);
+
+ QDeclarativeComponent *delegate() const;
+ void setDelegate(QDeclarativeComponent *);
+
+ int count() const;
+
+ Q_INVOKABLE QSGItem *itemAt(int index) const;
+
+Q_SIGNALS:
+ void modelChanged();
+ void delegateChanged();
+ void countChanged();
+
+ void itemAdded(int index, QSGItem *item);
+ void itemRemoved(int index, QSGItem *item);
+
+private:
+ void clear();
+ void regenerate();
+
+protected:
+ virtual void componentComplete();
+ void itemChange(ItemChange change, const ItemChangeData &value);
+
+private Q_SLOTS:
+ void itemsInserted(int,int);
+ void itemsRemoved(int,int);
+ void itemsMoved(int,int,int);
+ void modelReset();
+
+private:
+ Q_DISABLE_COPY(QSGRepeater)
+ Q_DECLARE_PRIVATE(QSGRepeater)
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QSGRepeater)
+
+QT_END_HEADER
+
+#endif // QSGREPEATER_P_H
diff --git a/src/declarative/items/qsgrepeater_p_p.h b/src/declarative/items/qsgrepeater_p_p.h
new file mode 100644
index 0000000000..155f1b8c6d
--- /dev/null
+++ b/src/declarative/items/qsgrepeater_p_p.h
@@ -0,0 +1,83 @@
+// Commit: ac5c099cc3c5b8c7eec7a49fdeb8a21037230350
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGREPEATER_P_P_H
+#define QSGREPEATER_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 "qsgrepeater_p.h"
+#include "qsgitem_p.h"
+
+#include <QtCore/qpointer.h>
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativeContext;
+class QSGVisualModel;
+class QSGRepeaterPrivate : public QSGItemPrivate
+{
+ Q_DECLARE_PUBLIC(QSGRepeater)
+
+public:
+ QSGRepeaterPrivate();
+ ~QSGRepeaterPrivate();
+
+ QSGVisualModel *model;
+ QVariant dataSource;
+ bool ownModel;
+
+ QList<QPointer<QSGItem> > deletables;
+};
+
+QT_END_NAMESPACE
+
+#endif // QSGREPEATER_P_P_H
diff --git a/src/declarative/items/qsgscalegrid.cpp b/src/declarative/items/qsgscalegrid.cpp
new file mode 100644
index 0000000000..4a73801159
--- /dev/null
+++ b/src/declarative/items/qsgscalegrid.cpp
@@ -0,0 +1,213 @@
+// Commit: 7ddec9f3179bfd854ae53e23ab292de1f9a26377
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgscalegrid_p_p.h"
+
+#include <QtDeclarative/qdeclarative.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \internal
+ \class QSGScaleGrid
+ \brief The QSGScaleGrid class allows you to specify a 3x3 grid to use in scaling an image.
+*/
+
+QSGScaleGrid::QSGScaleGrid(QObject *parent) : QObject(parent), _left(0), _top(0), _right(0), _bottom(0)
+{
+}
+
+QSGScaleGrid::~QSGScaleGrid()
+{
+}
+
+bool QSGScaleGrid::isNull() const
+{
+ return !_left && !_top && !_right && !_bottom;
+}
+
+void QSGScaleGrid::setLeft(int pos)
+{
+ if (_left != pos) {
+ _left = pos;
+ emit borderChanged();
+ }
+}
+
+void QSGScaleGrid::setTop(int pos)
+{
+ if (_top != pos) {
+ _top = pos;
+ emit borderChanged();
+ }
+}
+
+void QSGScaleGrid::setRight(int pos)
+{
+ if (_right != pos) {
+ _right = pos;
+ emit borderChanged();
+ }
+}
+
+void QSGScaleGrid::setBottom(int pos)
+{
+ if (_bottom != pos) {
+ _bottom = pos;
+ emit borderChanged();
+ }
+}
+
+QSGGridScaledImage::QSGGridScaledImage()
+: _l(-1), _r(-1), _t(-1), _b(-1),
+ _h(QSGBorderImage::Stretch), _v(QSGBorderImage::Stretch)
+{
+}
+
+QSGGridScaledImage::QSGGridScaledImage(const QSGGridScaledImage &o)
+: _l(o._l), _r(o._r), _t(o._t), _b(o._b), _h(o._h), _v(o._v), _pix(o._pix)
+{
+}
+
+QSGGridScaledImage &QSGGridScaledImage::operator=(const QSGGridScaledImage &o)
+{
+ _l = o._l;
+ _r = o._r;
+ _t = o._t;
+ _b = o._b;
+ _h = o._h;
+ _v = o._v;
+ _pix = o._pix;
+ return *this;
+}
+
+QSGGridScaledImage::QSGGridScaledImage(QIODevice *data)
+: _l(-1), _r(-1), _t(-1), _b(-1), _h(QSGBorderImage::Stretch), _v(QSGBorderImage::Stretch)
+{
+ int l = -1;
+ int r = -1;
+ int t = -1;
+ int b = -1;
+ QString imgFile;
+
+ QByteArray raw;
+ while(raw = data->readLine(), !raw.isEmpty()) {
+ QString line = QString::fromUtf8(raw.trimmed());
+ if (line.isEmpty() || line.startsWith(QLatin1Char('#')))
+ continue;
+
+ int colonId = line.indexOf(QLatin1Char(':'));
+ if (colonId <= 0)
+ return;
+
+ QStringList list;
+ list.append(line.left(colonId).trimmed());
+ list.append(line.mid(colonId+1).trimmed());
+
+ if (list[0] == QLatin1String("border.left"))
+ l = list[1].toInt();
+ else if (list[0] == QLatin1String("border.right"))
+ r = list[1].toInt();
+ else if (list[0] == QLatin1String("border.top"))
+ t = list[1].toInt();
+ else if (list[0] == QLatin1String("border.bottom"))
+ b = list[1].toInt();
+ else if (list[0] == QLatin1String("source"))
+ imgFile = list[1];
+ else if (list[0] == QLatin1String("horizontalTileRule"))
+ _h = stringToRule(list[1]);
+ else if (list[0] == QLatin1String("verticalTileRule"))
+ _v = stringToRule(list[1]);
+ }
+
+ if (l < 0 || r < 0 || t < 0 || b < 0 || imgFile.isEmpty())
+ return;
+
+ _l = l; _r = r; _t = t; _b = b;
+
+ _pix = imgFile;
+}
+
+QSGBorderImage::TileMode QSGGridScaledImage::stringToRule(const QString &s)
+{
+ if (s == QLatin1String("Stretch"))
+ return QSGBorderImage::Stretch;
+ if (s == QLatin1String("Repeat"))
+ return QSGBorderImage::Repeat;
+ if (s == QLatin1String("Round"))
+ return QSGBorderImage::Round;
+
+ qWarning("QSGGridScaledImage: Invalid tile rule specified. Using Stretch.");
+ return QSGBorderImage::Stretch;
+}
+
+bool QSGGridScaledImage::isValid() const
+{
+ return _l >= 0;
+}
+
+int QSGGridScaledImage::gridLeft() const
+{
+ return _l;
+}
+
+int QSGGridScaledImage::gridRight() const
+{
+ return _r;
+}
+
+int QSGGridScaledImage::gridTop() const
+{
+ return _t;
+}
+
+int QSGGridScaledImage::gridBottom() const
+{
+ return _b;
+}
+
+QString QSGGridScaledImage::pixmapUrl() const
+{
+ return _pix;
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/items/qsgscalegrid_p_p.h b/src/declarative/items/qsgscalegrid_p_p.h
new file mode 100644
index 0000000000..57beb4b3b0
--- /dev/null
+++ b/src/declarative/items/qsgscalegrid_p_p.h
@@ -0,0 +1,134 @@
+// Commit: ac5c099cc3c5b8c7eec7a49fdeb8a21037230350
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGSCALEGRID_P_P_H
+#define QSGSCALEGRID_P_P_H
+
+#include "qsgborderimage_p.h"
+
+#include <QtDeclarative/qdeclarative.h>
+#include <QtCore/qobject.h>
+
+#include <private/qdeclarativepixmapcache_p.h>
+#include <private/qdeclarativeglobal_p.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class Q_DECLARATIVE_PRIVATE_EXPORT QSGScaleGrid : public QObject
+{
+ Q_OBJECT
+ Q_ENUMS(TileRule)
+
+ Q_PROPERTY(int left READ left WRITE setLeft NOTIFY borderChanged)
+ Q_PROPERTY(int top READ top WRITE setTop NOTIFY borderChanged)
+ Q_PROPERTY(int right READ right WRITE setRight NOTIFY borderChanged)
+ Q_PROPERTY(int bottom READ bottom WRITE setBottom NOTIFY borderChanged)
+
+public:
+ QSGScaleGrid(QObject *parent=0);
+ ~QSGScaleGrid();
+
+ bool isNull() const;
+
+ int left() const { return _left; }
+ void setLeft(int);
+
+ int top() const { return _top; }
+ void setTop(int);
+
+ int right() const { return _right; }
+ void setRight(int);
+
+ int bottom() const { return _bottom; }
+ void setBottom(int);
+
+Q_SIGNALS:
+ void borderChanged();
+
+private:
+ int _left;
+ int _top;
+ int _right;
+ int _bottom;
+};
+
+class Q_DECLARATIVE_PRIVATE_EXPORT QSGGridScaledImage
+{
+public:
+ QSGGridScaledImage();
+ QSGGridScaledImage(const QSGGridScaledImage &);
+ QSGGridScaledImage(QIODevice*);
+ QSGGridScaledImage &operator=(const QSGGridScaledImage &);
+ bool isValid() const;
+ int gridLeft() const;
+ int gridRight() const;
+ int gridTop() const;
+ int gridBottom() const;
+ QSGBorderImage::TileMode horizontalTileRule() const { return _h; }
+ QSGBorderImage::TileMode verticalTileRule() const { return _v; }
+
+ QString pixmapUrl() const;
+
+private:
+ static QSGBorderImage::TileMode stringToRule(const QString &);
+
+private:
+ int _l;
+ int _r;
+ int _t;
+ int _b;
+ QSGBorderImage::TileMode _h;
+ QSGBorderImage::TileMode _v;
+ QString _pix;
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QSGScaleGrid)
+
+QT_END_HEADER
+
+#endif // QSGSCALEGRID_P_P_H
diff --git a/src/declarative/items/qsgshadereffectitem.cpp b/src/declarative/items/qsgshadereffectitem.cpp
new file mode 100644
index 0000000000..44e075c6f7
--- /dev/null
+++ b/src/declarative/items/qsgshadereffectitem.cpp
@@ -0,0 +1,590 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <private/qsgshadereffectitem_p.h>
+#include <private/qsgshadereffectnode_p.h>
+
+#include "qsgmaterial.h"
+#include "qsgitem_p.h"
+
+#include <private/qsgcontext_p.h>
+#include <private/qsgtextureprovider_p.h>
+#include "qsgcanvas.h"
+
+#include <QtCore/qsignalmapper.h>
+#include <QtOpenGL/qglframebufferobject.h>
+
+QT_BEGIN_NAMESPACE
+
+static const char qt_default_vertex_code[] =
+ "uniform highp mat4 qt_ModelViewProjectionMatrix; \n"
+ "attribute highp vec4 qt_Vertex; \n"
+ "attribute highp vec2 qt_MultiTexCoord0; \n"
+ "varying highp vec2 qt_TexCoord0; \n"
+ "void main() { \n"
+ " qt_TexCoord0 = qt_MultiTexCoord0; \n"
+ " gl_Position = qt_ModelViewProjectionMatrix * qt_Vertex; \n"
+ "}";
+
+static const char qt_default_fragment_code[] =
+ "varying highp vec2 qt_TexCoord0; \n"
+ "uniform sampler2D source; \n"
+ "uniform lowp float qt_Opacity; \n"
+ "void main() { \n"
+ " gl_FragColor = texture2D(source, qt_TexCoord0) * qt_Opacity; \n"
+ "}";
+
+static const char qt_position_attribute_name[] = "qt_Vertex";
+static const char qt_texcoord_attribute_name[] = "qt_MultiTexCoord0";
+
+const char *qtPositionAttributeName()
+{
+ return qt_position_attribute_name;
+}
+
+const char *qtTexCoordAttributeName()
+{
+ return qt_texcoord_attribute_name;
+}
+
+/*!
+ \qmlclass ShaderEffectItem QSGShaderEffectItem
+ \since 5.0
+ \ingroup qml-basic-visual-elements
+ \brief The ShaderEffectItem element applies custom shaders to a rectangle.
+ \inherits Item
+
+ The ShaderEffectItem element applies a custom OpenGL
+ \l{vertexShader}{vertex} and \l{fragmentShader}{fragment} shader to a
+ rectangle. It allows you to write effects such as drop shadow, blur,
+ colorize and page curl directly in QML.
+
+ There are two types of input to the \l vertexShader:
+ uniform variables and attributes. Some are predefined:
+ \list
+ \o uniform mat4 qt_ModelViewProjectionMatrix - combined transformation
+ matrix, the product of the matrices from the root item to this
+ ShaderEffectItem, and an orthogonal projection.
+ \o uniform float qt_Opacity - combined opacity, the product of the
+ opacities from the root item to this ShaderEffectItem.
+ \o attribute vec4 qt_Vertex - vertex position, the top-left vertex has
+ position (0, 0), the bottom-right (\l{Item::width}{width},
+ \l{Item::height}{height}).
+ \o attribute vec2 qt_MultiTexCoord0 - texture coordinate, the top-left
+ coordinate is (0, 0), the bottom-right (1, 1).
+ \endlist
+
+ In addition, any property that can be mapped to an OpenGL Shading Language
+ (GLSL) type is available as a uniform variable. The following list shows
+ how properties are mapped to GLSL uniform variables:
+ \list
+ \o bool, int, qreal -> bool, int, float - If the type in the shader is not
+ the same as in QML, the value is converted automatically.
+ \o QColor -> vec4 - When colors are passed to the shader, they are first
+ premultiplied. Thus Qt.rgba(0.2, 0.6, 1.0, 0.5) becomes
+ vec4(0.1, 0.3, 0.5, 0.5) in the shader, for example.
+ \o QRect, QRectF -> vec4 - Qt.rect(x, y, w, h) becomes vec4(x, y, w, h) in
+ the shader.
+ \o QPoint, QPointF, QSize, QSizeF -> vec2
+ \o QVector3D -> vec3
+ \o QTransform -> mat4
+ \o \l Image, \l ShaderEffectSource -> sampler2D - Origin is in the top-left
+ corner, and the color values are premultiplied.
+ \endlist
+
+ The output from the \l fragmentShader should be premultiplied. If
+ \l blending is enabled, source-over blending is used. However, additive
+ blending can be achieved by outputting zero in the alpha channel.
+
+ \row
+ \o \image declarative-shadereffectitem.png
+ \o \qml
+ import QtQuick 2.0
+
+ Rectangle {
+ width: 200; height: 100
+ Row {
+ Image { id: img; sourceSize { width: 100; height: 100 } source: "qt-logo.png" }
+ ShaderEffectItem {
+ width: 100; height: 100
+ property variant src: img
+ vertexShader: "
+ uniform highp mat4 qt_ModelViewProjectionMatrix;
+ attribute highp vec4 qt_Vertex;
+ attribute highp vec2 qt_MultiTexCoord0;
+ varying highp vec2 coord;
+ void main() {
+ coord = qt_MultiTexCoord0;
+ gl_Position = qt_ModelViewProjectionMatrix * qt_Vertex;
+ }"
+ fragmentShader: "
+ varying highp vec2 coord;
+ uniform sampler2D src;
+ uniform lowp float qt_Opacity;
+ void main() {
+ lowp vec4 tex = texture2D(src, coord);
+ gl_FragColor = vec4(vec3(dot(tex.rgb, vec3(0.344, 0.5, 0.156))), tex.a) * qt_Opacity;
+ }"
+ }
+ }
+ }
+ \endqml
+ \endrow
+
+ By default, the ShaderEffectItem consists of four vertices, one for each
+ corner. For non-linear vertex transformations, like page curl, you can
+ specify a fine grid of vertices by assigning a \l GridMesh to the \l mesh
+ property.
+
+ \note Scene Graph textures have origin in the top-left corner rather than
+ bottom-left which is common in OpenGL.
+*/
+
+QSGShaderEffectItem::QSGShaderEffectItem(QSGItem *parent)
+ : QSGItem(parent)
+ , m_mesh(0)
+ , m_cullMode(NoCulling)
+ , m_blending(true)
+ , m_dirtyData(true)
+ , m_programDirty(true)
+ , m_dirtyMesh(true)
+ , m_dirtyGeometry(true)
+{
+ setFlag(QSGItem::ItemHasContents);
+}
+
+QSGShaderEffectItem::~QSGShaderEffectItem()
+{
+ reset();
+}
+
+void QSGShaderEffectItem::componentComplete()
+{
+ updateProperties();
+ QSGItem::componentComplete();
+}
+
+/*!
+ \qmlproperty string ShaderEffectItem::fragmentShader
+
+ This property holds the fragment shader's GLSL source code.
+ The default shader passes the texture coordinate along to the fragment
+ shader as "varying highp vec2 qt_TexCoord0".
+*/
+
+void QSGShaderEffectItem::setFragmentShader(const QByteArray &code)
+{
+ if (m_source.fragmentCode.constData() == code.constData())
+ return;
+ m_source.fragmentCode = code;
+ if (isComponentComplete()) {
+ reset();
+ updateProperties();
+ }
+ emit fragmentShaderChanged();
+}
+
+/*!
+ \qmlproperty string ShaderEffectItem::vertexShader
+
+ This property holds the vertex shader's GLSL source code.
+ The default shader expects the texture coordinate to be passed from the
+ vertex shader as "varying highp vec2 qt_TexCoord0", and it samples from a
+ sampler2D named "source".
+*/
+
+void QSGShaderEffectItem::setVertexShader(const QByteArray &code)
+{
+ if (m_source.vertexCode.constData() == code.constData())
+ return;
+ m_source.vertexCode = code;
+ if (isComponentComplete()) {
+ reset();
+ updateProperties();
+ }
+ emit vertexShaderChanged();
+}
+
+/*!
+ \qmlproperty bool ShaderEffectItem::blending
+
+ If this property is true, the output from the \l fragmentShader is blended
+ with the background using source-over blend mode. If false, the background
+ is disregarded. Blending decreases the performance, so you should set this
+ property to false when blending is not needed. The default value is true.
+*/
+
+void QSGShaderEffectItem::setBlending(bool enable)
+{
+ if (blending() == enable)
+ return;
+
+ m_blending = enable;
+ update();
+
+ emit blendingChanged();
+}
+
+/*!
+ \qmlproperty object ShaderEffectItem::mesh
+
+ This property holds the mesh definition. If not set, a simple mesh with one
+ vertex in each corner is used. Assign a \l GridMesh to this property to get
+ a higher resolution grid.
+*/
+
+void QSGShaderEffectItem::setMesh(QSGShaderEffectMesh *mesh)
+{
+ if (mesh == m_mesh)
+ return;
+ if (m_mesh)
+ disconnect(m_mesh, SIGNAL(geometryChanged()), this, 0);
+ m_mesh = mesh;
+ if (m_mesh)
+ connect(m_mesh, SIGNAL(geometryChanged()), this, SLOT(updateGeometry()));
+ m_dirtyMesh = true;
+ update();
+ emit meshChanged();
+}
+
+/*!
+ \qmlproperty enumeration ShaderEffectItem::cullMode
+
+ This property defines which sides of the element should be visible.
+
+ \list
+ \o ShaderEffectItem.NoCulling - Both sides are visible
+ \o ShaderEffectItem.BackFaceCulling - only front side is visible
+ \o ShaderEffectItem.FrontFaceCulling - only back side is visible
+ \endlist
+
+ The default is NoCulling.
+*/
+
+void QSGShaderEffectItem::setCullMode(CullMode face)
+{
+ if (face == m_cullMode)
+ return;
+ m_cullMode = face;
+ update();
+ emit cullModeChanged();
+}
+
+void QSGShaderEffectItem::changeSource(int index)
+{
+ Q_ASSERT(index >= 0 && index < m_sources.size());
+ QVariant v = property(m_sources.at(index).name.constData());
+ setSource(v, index);
+}
+
+void QSGShaderEffectItem::updateData()
+{
+ m_dirtyData = true;
+ update();
+}
+
+void QSGShaderEffectItem::updateGeometry()
+{
+ m_dirtyGeometry = true;
+ update();
+}
+
+void QSGShaderEffectItem::setSource(const QVariant &var, int index)
+{
+ Q_ASSERT(index >= 0 && index < m_sources.size());
+
+ SourceData &source = m_sources[index];
+
+ source.item = 0;
+ if (var.isNull()) {
+ return;
+ } else if (!qVariantCanConvert<QObject *>(var)) {
+ qWarning("Could not assign source of type '%s' to property '%s'.", var.typeName(), source.name.constData());
+ return;
+ }
+
+ QObject *obj = qVariantValue<QObject *>(var);
+
+ QSGTextureProvider *int3rface = QSGTextureProvider::from(obj);
+ if (!int3rface) {
+ qWarning("Could not assign property '%s', did not implement QSGTextureProvider.", source.name.constData());
+ }
+
+ source.item = qobject_cast<QSGItem *>(obj);
+
+ // TODO: Find better solution.
+ // 'source.item' needs a canvas to get a scenegraph node.
+ // The easiest way to make sure it gets a canvas is to
+ // make it a part of the same item tree as 'this'.
+ if (source.item && source.item->parentItem() == 0) {
+ source.item->setParentItem(this);
+ source.item->setVisible(false);
+ }
+}
+
+void QSGShaderEffectItem::disconnectPropertySignals()
+{
+ disconnect(this, 0, this, SLOT(updateData()));
+ for (int i = 0; i < m_sources.size(); ++i) {
+ SourceData &source = m_sources[i];
+ disconnect(this, 0, source.mapper, 0);
+ disconnect(source.mapper, 0, this, 0);
+ }
+}
+
+void QSGShaderEffectItem::connectPropertySignals()
+{
+ QSet<QByteArray>::const_iterator it;
+ for (it = m_source.uniformNames.begin(); it != m_source.uniformNames.end(); ++it) {
+ int pi = metaObject()->indexOfProperty(it->constData());
+ if (pi >= 0) {
+ QMetaProperty mp = metaObject()->property(pi);
+ if (!mp.hasNotifySignal())
+ qWarning("QSGShaderEffectItem: property '%s' does not have notification method!", it->constData());
+ QByteArray signalName("2");
+ signalName.append(mp.notifySignal().signature());
+ connect(this, signalName, this, SLOT(updateData()));
+ } else {
+ qWarning("QSGShaderEffectItem: '%s' does not have a matching property!", it->constData());
+ }
+ }
+ for (int i = 0; i < m_sources.size(); ++i) {
+ SourceData &source = m_sources[i];
+ int pi = metaObject()->indexOfProperty(source.name.constData());
+ if (pi >= 0) {
+ QMetaProperty mp = metaObject()->property(pi);
+ QByteArray signalName("2");
+ signalName.append(mp.notifySignal().signature());
+ connect(this, signalName, source.mapper, SLOT(map()));
+ source.mapper->setMapping(this, i);
+ connect(source.mapper, SIGNAL(mapped(int)), this, SLOT(changeSource(int)));
+ } else {
+ qWarning("QSGShaderEffectItem: '%s' does not have a matching source!", source.name.constData());
+ }
+ }
+}
+
+void QSGShaderEffectItem::reset()
+{
+ disconnectPropertySignals();
+
+ m_source.attributeNames.clear();
+ m_source.uniformNames.clear();
+ m_source.respectsOpacity = false;
+ m_source.respectsMatrix = false;
+ m_source.className = metaObject()->className();
+
+ for (int i = 0; i < m_sources.size(); ++i) {
+ const SourceData &source = m_sources.at(i);
+ delete source.mapper;
+ if (source.item && source.item->parentItem() == this)
+ source.item->setParentItem(0);
+ }
+ m_sources.clear();
+
+ m_programDirty = true;
+ m_dirtyMesh = true;
+}
+
+void QSGShaderEffectItem::updateProperties()
+{
+ QByteArray vertexCode = m_source.vertexCode;
+ QByteArray fragmentCode = m_source.fragmentCode;
+ if (vertexCode.isEmpty())
+ vertexCode = qt_default_vertex_code;
+ if (fragmentCode.isEmpty())
+ fragmentCode = qt_default_fragment_code;
+
+ lookThroughShaderCode(vertexCode);
+ lookThroughShaderCode(fragmentCode);
+
+ if (!m_mesh && !m_source.attributeNames.contains(qt_position_attribute_name))
+ qWarning("QSGShaderEffectItem: Missing reference to \'%s\'.", qt_position_attribute_name);
+ if (!m_mesh && !m_source.attributeNames.contains(qt_texcoord_attribute_name))
+ qWarning("QSGShaderEffectItem: Missing reference to \'%s\'.", qt_texcoord_attribute_name);
+ if (!m_source.respectsMatrix)
+ qWarning("QSGShaderEffectItem: Missing reference to \'qt_ModelViewProjectionMatrix\'.");
+ if (!m_source.respectsOpacity)
+ qWarning("QSGShaderEffectItem: Missing reference to \'qt_Opacity\'.");
+
+ for (int i = 0; i < m_sources.size(); ++i) {
+ QVariant v = property(m_sources.at(i).name);
+ setSource(v, i);
+ }
+
+ connectPropertySignals();
+}
+
+void QSGShaderEffectItem::lookThroughShaderCode(const QByteArray &code)
+{
+ // Regexp for matching attributes and uniforms.
+ // In human readable form: attribute|uniform [lowp|mediump|highp] <type> <name>
+ static QRegExp re(QLatin1String("\\b(attribute|uniform)\\b\\s*\\b(?:lowp|mediump|highp)?\\b\\s*\\b(\\w+)\\b\\s*\\b(\\w+)"));
+ Q_ASSERT(re.isValid());
+
+ int pos = -1;
+
+ QString wideCode = QString::fromLatin1(code.constData(), code.size());
+
+ while ((pos = re.indexIn(wideCode, pos + 1)) != -1) {
+ QByteArray decl = re.cap(1).toLatin1(); // uniform or attribute
+ QByteArray type = re.cap(2).toLatin1(); // type
+ QByteArray name = re.cap(3).toLatin1(); // variable name
+
+ if (decl == "attribute") {
+ m_source.attributeNames.append(name);
+ } else {
+ Q_ASSERT(decl == "uniform");
+
+ if (name == "qt_ModelViewProjectionMatrix") {
+ m_source.respectsMatrix = true;
+ } else if (name == "qt_Opacity") {
+ m_source.respectsOpacity = true;
+ } else {
+ m_source.uniformNames.insert(name);
+ if (type == "sampler2D") {
+ SourceData d;
+ d.mapper = new QSignalMapper;
+ d.name = name;
+ d.item = 0;
+ m_sources.append(d);
+ }
+ }
+ }
+ }
+}
+
+void QSGShaderEffectItem::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
+{
+ m_dirtyGeometry = true;
+ QSGItem::geometryChanged(newGeometry, oldGeometry);
+}
+
+QSGNode *QSGShaderEffectItem::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
+{
+ QSGShaderEffectNode *node = static_cast<QSGShaderEffectNode *>(oldNode);
+
+ if (!node) {
+ node = new QSGShaderEffectNode;
+ node->setMaterial(&m_material);
+ m_programDirty = true;
+ m_dirtyData = true;
+ m_dirtyGeometry = true;
+ }
+
+ if (m_dirtyMesh) {
+ node->setGeometry(0);
+ m_dirtyMesh = false;
+ m_dirtyGeometry = true;
+ }
+
+ if (m_dirtyGeometry) {
+ node->setFlag(QSGNode::OwnsGeometry, false);
+ QSGGeometry *geometry = node->geometry();
+ QRectF rect(0, 0, width(), height());
+ QSGShaderEffectMesh *mesh = m_mesh ? m_mesh : &m_defaultMesh;
+
+ geometry = mesh->updateGeometry(geometry, m_source.attributeNames, rect);
+ if (!geometry) {
+ delete node;
+ return 0;
+ }
+
+ node->setGeometry(geometry);
+ node->setFlag(QSGNode::OwnsGeometry, true);
+
+ m_dirtyGeometry = false;
+ }
+
+ if (m_programDirty) {
+ QSGShaderEffectProgram s = m_source;
+ if (s.fragmentCode.isEmpty())
+ s.fragmentCode = qt_default_fragment_code;
+ if (s.vertexCode.isEmpty())
+ s.vertexCode = qt_default_vertex_code;
+
+ m_material.setProgramSource(s);
+ node->markDirty(QSGNode::DirtyMaterial);
+ m_programDirty = false;
+ }
+
+ // Update blending
+ if (bool(m_material.flags() & QSGMaterial::Blending) != m_blending) {
+ m_material.setFlag(QSGMaterial::Blending, m_blending);
+ node->markDirty(QSGNode::DirtyMaterial);
+ }
+
+ if (int(m_material.cullMode()) != int(m_cullMode)) {
+ m_material.setCullMode(QSGShaderEffectMaterial::CullMode(m_cullMode));
+ node->markDirty(QSGNode::DirtyMaterial);
+ }
+
+ if (m_dirtyData) {
+ QVector<QPair<QByteArray, QVariant> > values;
+ QVector<QPair<QByteArray, QPointer<QSGItem> > > textures;
+ const QVector<QPair<QByteArray, QPointer<QSGItem> > > &oldTextures = m_material.textureProviders();
+
+ for (QSet<QByteArray>::const_iterator it = m_source.uniformNames.begin();
+ it != m_source.uniformNames.end(); ++it) {
+ values.append(qMakePair(*it, property(*it)));
+ }
+ for (int i = 0; i < oldTextures.size(); ++i) {
+ QSGTextureProvider *oldSource = QSGTextureProvider::from(oldTextures.at(i).second);
+ if (oldSource && oldSource->textureChangedSignal())
+ disconnect(oldTextures.at(i).second, oldSource->textureChangedSignal(), node, SLOT(markDirtyTexture()));
+ }
+ for (int i = 0; i < m_sources.size(); ++i) {
+ const SourceData &source = m_sources.at(i);
+ textures.append(qMakePair(source.name, source.item));
+ QSGTextureProvider *t = QSGTextureProvider::from(source.item);
+ if (t && t->textureChangedSignal())
+ connect(source.item, t->textureChangedSignal(), node, SLOT(markDirtyTexture()), Qt::DirectConnection);
+ }
+ m_material.setUniforms(values);
+ m_material.setTextureProviders(textures);
+ node->markDirty(QSGNode::DirtyMaterial);
+ m_dirtyData = false;
+ }
+
+ return node;
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/items/qsgshadereffectitem_p.h b/src/declarative/items/qsgshadereffectitem_p.h
new file mode 100644
index 0000000000..4017d35c64
--- /dev/null
+++ b/src/declarative/items/qsgshadereffectitem_p.h
@@ -0,0 +1,158 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef SHADEREFFECTITEM_H
+#define SHADEREFFECTITEM_H
+
+#include "qsgitem.h"
+
+#include "qsgmaterial.h"
+#include <private/qsgadaptationlayer_p.h>
+#include <private/qsgshadereffectnode_p.h>
+#include "qsgshadereffectmesh_p.h"
+
+#include <QtCore/qpointer.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+const char *qtPositionAttributeName();
+const char *qtTexCoordAttributeName();
+
+class QSGContext;
+class QSignalMapper;
+class QSGCustomMaterialShader;
+
+class QSGShaderEffectItem : public QSGItem
+{
+ Q_OBJECT
+ Q_PROPERTY(QByteArray fragmentShader READ fragmentShader WRITE setFragmentShader NOTIFY fragmentShaderChanged)
+ Q_PROPERTY(QByteArray vertexShader READ vertexShader WRITE setVertexShader NOTIFY vertexShaderChanged)
+ Q_PROPERTY(bool blending READ blending WRITE setBlending NOTIFY blendingChanged)
+ Q_PROPERTY(QSGShaderEffectMesh *mesh READ mesh WRITE setMesh NOTIFY meshChanged)
+ Q_PROPERTY(CullMode culling READ cullMode WRITE setCullMode NOTIFY cullModeChanged)
+ Q_ENUMS(CullMode)
+
+public:
+ enum CullMode
+ {
+ NoCulling = QSGShaderEffectMaterial::NoCulling,
+ BackFaceCulling = QSGShaderEffectMaterial::BackFaceCulling,
+ FrontFaceCulling = QSGShaderEffectMaterial::FrontFaceCulling
+ };
+
+ QSGShaderEffectItem(QSGItem *parent = 0);
+ ~QSGShaderEffectItem();
+
+ virtual void componentComplete();
+
+ QByteArray fragmentShader() const { return m_source.fragmentCode; }
+ void setFragmentShader(const QByteArray &code);
+
+ QByteArray vertexShader() const { return m_source.vertexCode; }
+ void setVertexShader(const QByteArray &code);
+
+ bool blending() const { return m_blending; }
+ void setBlending(bool enable);
+
+ QSGShaderEffectMesh *mesh() const { return m_mesh; }
+ void setMesh(QSGShaderEffectMesh *mesh);
+
+ CullMode cullMode() const { return m_cullMode; }
+ void setCullMode(CullMode face);
+
+Q_SIGNALS:
+ void fragmentShaderChanged();
+ void vertexShaderChanged();
+ void blendingChanged();
+ void meshChanged();
+ void cullModeChanged();
+
+protected:
+ virtual void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry);
+ virtual QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *);
+
+private Q_SLOTS:
+ void changeSource(int index);
+ void updateData();
+ void updateGeometry();
+
+private:
+ friend class QSGCustomMaterialShader;
+ friend class QSGShaderEffectNode;
+
+ void setSource(const QVariant &var, int index);
+ void disconnectPropertySignals();
+ void connectPropertySignals();
+ void reset();
+ void updateProperties();
+ void lookThroughShaderCode(const QByteArray &code);
+
+ QSGShaderEffectProgram m_source;
+ QSGShaderEffectMesh *m_mesh;
+ QSGGridMesh m_defaultMesh;
+ CullMode m_cullMode;
+
+ struct SourceData
+ {
+ QSignalMapper *mapper;
+ QPointer<QSGItem> item;
+ QByteArray name;
+ };
+ QVector<SourceData> m_sources;
+ QSGShaderEffectMaterial m_material;
+
+ uint m_blending : 1;
+ uint m_dirtyData : 1;
+
+ uint m_programDirty : 1;
+ uint m_dirtyMesh : 1;
+ uint m_dirtyGeometry : 1;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // SHADEREFFECTITEM_H
diff --git a/src/declarative/items/qsgshadereffectmesh.cpp b/src/declarative/items/qsgshadereffectmesh.cpp
new file mode 100644
index 0000000000..4900755e46
--- /dev/null
+++ b/src/declarative/items/qsgshadereffectmesh.cpp
@@ -0,0 +1,218 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgshadereffectmesh_p.h"
+#include "qsggeometry.h"
+#include "qsgshadereffectitem_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QSGShaderEffectMesh::QSGShaderEffectMesh(QObject *parent)
+ : QObject(parent)
+{
+}
+
+/*!
+ \qmlclass GridMesh QSGGridMesh
+ \since 5.0
+ \ingroup qml-utility-elements
+ \brief GridMesh defines a mesh to be used with \l ShaderEffectItem.
+
+ GridMesh defines a rectangular mesh consisting of vertices arranged in an
+ evenly spaced grid. It can be assigned to the \l ShaderEffectItem's mesh
+ property. The grid resolution is specified with the \l resolution property.
+
+ \row
+ \o \image declarative-gridmesh.png
+ \o \qml
+ import QtQuick 2.0
+
+ ShaderEffectItem {
+ width: 200
+ height: 200
+ mesh: GridMesh { resolution: Qt.size(20, 20) }
+ property variant source: Image {
+ source: "qt-logo.png"
+ sourceSize {width: 200; height: 200 }
+ smooth: true
+ }
+ vertexShader: "
+ uniform highp mat4 qt_ModelViewProjectionMatrix;
+ attribute highp vec4 qt_Vertex;
+ attribute highp vec2 qt_MultiTexCoord0;
+ varying highp vec2 qt_TexCoord0;
+ uniform highp float width;
+ void main() {
+ highp vec4 pos = qt_Vertex;
+ highp float d = .5 * smoothstep(0., 1., qt_MultiTexCoord0.y);
+ pos.x = width * mix(d, 1.0 - d, qt_MultiTexCoord0.x);
+ gl_Position = qt_ModelViewProjectionMatrix * pos;
+ qt_TexCoord0 = qt_MultiTexCoord0;
+ }"
+ }
+ \endqml
+ \endrow
+
+*/
+
+QSGGridMesh::QSGGridMesh(QObject *parent)
+ : QSGShaderEffectMesh(parent)
+ , m_resolution(1, 1)
+{
+ connect(this, SIGNAL(resolutionChanged()), this, SIGNAL(geometryChanged()));
+}
+
+QSGGeometry *QSGGridMesh::updateGeometry(QSGGeometry *geometry, const QVector<QByteArray> &attributes, const QRectF &dstRect) const
+{
+ int vmesh = m_resolution.height();
+ int hmesh = m_resolution.width();
+ int attrCount = attributes.count();
+
+ if (!geometry) {
+ bool error = true;
+ switch (attrCount) {
+ case 0:
+ qWarning("QSGGridMesh:: No attributes specified.");
+ break;
+ case 1:
+ if (attributes.at(0) == qtPositionAttributeName()) {
+ error = false;
+ break;
+ }
+ qWarning("QSGGridMesh:: Missing \'%s\' attribute.",
+ qtPositionAttributeName());
+ break;
+ case 2:
+ if (attributes.contains(qtPositionAttributeName())
+ && attributes.contains(qtTexCoordAttributeName()))
+ {
+ error = false;
+ break;
+ }
+ qWarning("QSGGridMesh:: Missing \'%s\' or \'%s\' attribute.",
+ qtPositionAttributeName(), qtTexCoordAttributeName());
+ break;
+ default:
+ qWarning("QSGGridMesh:: Too many attributes specified.");
+ break;
+ }
+
+ if (error) {
+ delete geometry;
+ return 0;
+ }
+
+ geometry = new QSGGeometry(attrCount == 1
+ ? QSGGeometry::defaultAttributes_Point2D()
+ : QSGGeometry::defaultAttributes_TexturedPoint2D(),
+ (vmesh + 1) * (hmesh + 1), vmesh * 2 * (hmesh + 2),
+ GL_UNSIGNED_SHORT);
+
+ } else {
+ geometry->allocate((vmesh + 1) * (hmesh + 1), vmesh * 2 * (hmesh + 2));
+ }
+
+ QSGGeometry::Point2D *vdata = static_cast<QSGGeometry::Point2D *>(geometry->vertexData());
+
+ bool positionFirst = attributes.at(0) == qtPositionAttributeName();
+
+ QRectF srcRect(0, 0, 1, 1);
+ for (int iy = 0; iy <= vmesh; ++iy) {
+ float fy = iy / float(vmesh);
+ float y = float(dstRect.top()) + fy * float(dstRect.height());
+ float ty = float(srcRect.top()) + fy * float(srcRect.height());
+ for (int ix = 0; ix <= hmesh; ++ix) {
+ float fx = ix / float(hmesh);
+ for (int ia = 0; ia < attrCount; ++ia) {
+ if (positionFirst == (ia == 0)) {
+ vdata->x = float(dstRect.left()) + fx * float(dstRect.width());
+ vdata->y = y;
+ ++vdata;
+ } else {
+ vdata->x = float(srcRect.left()) + fx * float(srcRect.width());
+ vdata->y = ty;
+ ++vdata;
+ }
+ }
+ }
+ }
+
+ quint16 *indices = (quint16 *)geometry->indexDataAsUShort();
+ int i = 0;
+ for (int iy = 0; iy < vmesh; ++iy) {
+ *(indices++) = i + hmesh + 1;
+ for (int ix = 0; ix <= hmesh; ++ix, ++i) {
+ *(indices++) = i + hmesh + 1;
+ *(indices++) = i;
+ }
+ *(indices++) = i - 1;
+ }
+
+ return geometry;
+}
+
+/*!
+ \qmlproperty size GridMesh::resolution
+
+ This property holds the grid resolution. The resolution's width and height
+ specify the number of cells or spacings between vertices horizontally and
+ vertically respectively. The minimum and default is 1x1, which corresponds
+ to four vertices in total, one in each corner.
+*/
+
+void QSGGridMesh::setResolution(const QSize &res)
+{
+ if (res == m_resolution)
+ return;
+ if (res.width() < 1 || res.height() < 1) {
+ qWarning("QSGGridMesh: Resolution must be at least 1x1");
+ return;
+ }
+ m_resolution = res;
+ emit resolutionChanged();
+}
+
+QSize QSGGridMesh::resolution() const
+{
+ return m_resolution;
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/items/qsgshadereffectmesh_p.h b/src/declarative/items/qsgshadereffectmesh_p.h
new file mode 100644
index 0000000000..88198b5c40
--- /dev/null
+++ b/src/declarative/items/qsgshadereffectmesh_p.h
@@ -0,0 +1,102 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qdeclarativeparserstatus.h"
+
+#include <QtCore/qobject.h>
+#include <QtCore/qsize.h>
+#include <QtCore/qvariant.h>
+#include <QtOpenGL/qglfunctions.h>
+
+#ifndef SHADEREFFECTMESH_H
+#define SHADEREFFECTMESH_H
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QSGGeometry;
+class QRectF;
+
+class QSGShaderEffectMesh : public QObject
+{
+ Q_OBJECT
+public:
+ QSGShaderEffectMesh(QObject *parent = 0);
+ // If 'geometry' != 0, 'attributes' is the same as last time the function was called.
+ virtual QSGGeometry *updateGeometry(QSGGeometry *geometry, const QVector<QByteArray> &attributes, const QRectF &rect) const = 0;
+
+Q_SIGNALS:
+ // Emitted when the geometry needs to be updated.
+ void geometryChanged();
+};
+
+class QSGGridMesh : public QSGShaderEffectMesh
+{
+ Q_OBJECT
+ Q_PROPERTY(QSize resolution READ resolution WRITE setResolution NOTIFY resolutionChanged)
+public:
+ QSGGridMesh(QObject *parent = 0);
+ virtual QSGGeometry *updateGeometry(QSGGeometry *geometry, const QVector<QByteArray> &attributes, const QRectF &rect) const;
+
+ void setResolution(const QSize &res);
+ QSize resolution() const;
+
+Q_SIGNALS:
+ void resolutionChanged();
+
+private:
+ QSize m_resolution;
+};
+
+inline QColor qt_premultiply_color(const QColor &c)
+{
+ return QColor::fromRgbF(c.redF() * c.alphaF(), c.greenF() * c.alphaF(), c.blueF() * c.alphaF(), c.alphaF());
+}
+
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // SHADEREFFECTITEM_H
diff --git a/src/declarative/items/qsgshadereffectnode.cpp b/src/declarative/items/qsgshadereffectnode.cpp
new file mode 100644
index 0000000000..74cd995d0d
--- /dev/null
+++ b/src/declarative/items/qsgshadereffectnode.cpp
@@ -0,0 +1,322 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <private/qsgshadereffectnode_p.h>
+
+#include "qsgshadereffectmesh_p.h"
+#include <private/qsgtextureprovider_p.h>
+#include <private/qsgrenderer_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QSGCustomMaterialShader : public QSGMaterialShader
+{
+public:
+ QSGCustomMaterialShader(const QSGShaderEffectMaterialKey &key, const QVector<QByteArray> &attributes);
+ virtual void deactivate();
+ virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect);
+ virtual char const *const *attributeNames() const;
+
+protected:
+ friend class QSGShaderEffectNode;
+
+ virtual void initialize();
+ virtual const char *vertexShader() const;
+ virtual const char *fragmentShader() const;
+
+ const QSGShaderEffectMaterialKey m_key;
+ QVector<const char *> m_attributeNames;
+ const QVector<QByteArray> m_attributes;
+
+ QVector<int> m_uniformLocs;
+ int m_opacityLoc;
+ int m_matrixLoc;
+ uint m_textureIndicesSet;
+};
+
+QSGCustomMaterialShader::QSGCustomMaterialShader(const QSGShaderEffectMaterialKey &key, const QVector<QByteArray> &attributes)
+ : m_key(key)
+ , m_attributes(attributes)
+ , m_textureIndicesSet(false)
+{
+ for (int i = 0; i < attributes.count(); ++i)
+ m_attributeNames.append(attributes.at(i).constData());
+ m_attributeNames.append(0);
+}
+
+void QSGCustomMaterialShader::deactivate()
+{
+ glDisable(GL_CULL_FACE);
+}
+
+void QSGCustomMaterialShader::updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect)
+{
+ Q_ASSERT(newEffect != 0);
+
+ const QSGShaderEffectMaterial *material = static_cast<const QSGShaderEffectMaterial *>(newEffect);
+
+ if (!m_textureIndicesSet) {
+ for (int i = 0; i < material->m_textures.size(); ++i)
+ program()->setUniformValue(material->m_textures.at(i).first.constData(), i);
+ m_textureIndicesSet = true;
+ }
+
+ if (m_uniformLocs.size() != material->m_uniformValues.size()) {
+ m_uniformLocs.reserve(material->m_uniformValues.size());
+ for (int i = 0; i < material->m_uniformValues.size(); ++i) {
+ const QByteArray &name = material->m_uniformValues.at(i).first;
+ m_uniformLocs.append(program()->uniformLocation(name.constData()));
+ }
+ }
+
+ QGLFunctions *functions = state.context()->functions();
+ for (int i = material->m_textures.size() - 1; i >= 0; --i) {
+ QPointer<QSGItem> source = material->m_textures.at(i).second;
+ QSGTextureProvider *provider = QSGTextureProvider::from(source);
+ QSGTexture *texture = provider ? provider->texture() : 0;
+ if (!source || !provider || !texture) {
+ qWarning("ShaderEffectItem: source or provider missing when binding textures");
+ continue;
+ }
+ functions->glActiveTexture(GL_TEXTURE0 + i);
+ provider->texture()->bind();
+ }
+
+ if (material->m_source.respectsOpacity)
+ program()->setUniformValue(m_opacityLoc, state.opacity());
+
+ for (int i = 0; i < material->m_uniformValues.count(); ++i) {
+ const QVariant &v = material->m_uniformValues.at(i).second;
+
+ switch (v.type()) {
+ case QVariant::Color:
+ program()->setUniformValue(m_uniformLocs.at(i), qt_premultiply_color(qvariant_cast<QColor>(v)));
+ break;
+ case QVariant::Double:
+ program()->setUniformValue(m_uniformLocs.at(i), (float) qvariant_cast<double>(v));
+ break;
+ case QVariant::Transform:
+ program()->setUniformValue(m_uniformLocs.at(i), qvariant_cast<QTransform>(v));
+ break;
+ case QVariant::Int:
+ program()->setUniformValue(m_uniformLocs.at(i), v.toInt());
+ break;
+ case QVariant::Bool:
+ program()->setUniformValue(m_uniformLocs.at(i), GLint(v.toBool()));
+ break;
+ case QVariant::Size:
+ case QVariant::SizeF:
+ program()->setUniformValue(m_uniformLocs.at(i), v.toSizeF());
+ break;
+ case QVariant::Point:
+ case QVariant::PointF:
+ program()->setUniformValue(m_uniformLocs.at(i), v.toPointF());
+ break;
+ case QVariant::Rect:
+ case QVariant::RectF:
+ {
+ QRectF r = v.toRectF();
+ program()->setUniformValue(m_uniformLocs.at(i), r.x(), r.y(), r.width(), r.height());
+ }
+ break;
+ case QVariant::Vector3D:
+ program()->setUniformValue(m_uniformLocs.at(i), qvariant_cast<QVector3D>(v));
+ break;
+ default:
+ break;
+ }
+ }
+
+ const QSGShaderEffectMaterial *oldMaterial = static_cast<const QSGShaderEffectMaterial *>(oldEffect);
+ if (oldEffect == 0 || material->cullMode() != oldMaterial->cullMode()) {
+ switch (material->cullMode()) {
+ case QSGShaderEffectMaterial::FrontFaceCulling:
+ glEnable(GL_CULL_FACE);
+ glCullFace(GL_FRONT);
+ break;
+ case QSGShaderEffectMaterial::BackFaceCulling:
+ glEnable(GL_CULL_FACE);
+ glCullFace(GL_BACK);
+ break;
+ default:
+ glDisable(GL_CULL_FACE);
+ break;
+ }
+ }
+
+ if ((state.isMatrixDirty()) && material->m_source.respectsMatrix)
+ program()->setUniformValue(m_matrixLoc, state.combinedMatrix());
+}
+
+char const *const *QSGCustomMaterialShader::attributeNames() const
+{
+ return m_attributeNames.constData();
+}
+
+void QSGCustomMaterialShader::initialize()
+{
+ m_opacityLoc = program()->uniformLocation("qt_Opacity");
+ m_matrixLoc = program()->uniformLocation("qt_ModelViewProjectionMatrix");
+}
+
+const char *QSGCustomMaterialShader::vertexShader() const
+{
+ return m_key.vertexCode.constData();
+}
+
+const char *QSGCustomMaterialShader::fragmentShader() const
+{
+ return m_key.fragmentCode.constData();
+}
+
+
+bool QSGShaderEffectMaterialKey::operator == (const QSGShaderEffectMaterialKey &other) const
+{
+ return vertexCode == other.vertexCode && fragmentCode == other.fragmentCode && className == other.className;
+}
+
+uint qHash(const QSGShaderEffectMaterialKey &key)
+{
+ return qHash(qMakePair(qMakePair(key.vertexCode, key.fragmentCode), key.className));
+}
+
+
+QHash<QSGShaderEffectMaterialKey, QSharedPointer<QSGMaterialType> > QSGShaderEffectMaterial::materialMap;
+
+QSGShaderEffectMaterial::QSGShaderEffectMaterial()
+ : m_cullMode(NoCulling)
+{
+ setFlag(Blending, true);
+}
+
+QSGMaterialType *QSGShaderEffectMaterial::type() const
+{
+ return m_type.data();
+}
+
+QSGMaterialShader *QSGShaderEffectMaterial::createShader() const
+{
+ return new QSGCustomMaterialShader(m_source, m_source.attributeNames);
+}
+
+int QSGShaderEffectMaterial::compare(const QSGMaterial *other) const
+{
+ return this - static_cast<const QSGShaderEffectMaterial *>(other);
+}
+
+void QSGShaderEffectMaterial::setCullMode(QSGShaderEffectMaterial::CullMode face)
+{
+ m_cullMode = face;
+}
+
+QSGShaderEffectMaterial::CullMode QSGShaderEffectMaterial::cullMode() const
+{
+ return m_cullMode;
+}
+
+void QSGShaderEffectMaterial::setProgramSource(const QSGShaderEffectProgram &source)
+{
+ m_source = source;
+ m_type = materialMap.value(m_source);
+ if (m_type.isNull()) {
+ m_type = QSharedPointer<QSGMaterialType>(new QSGMaterialType);
+ materialMap.insert(m_source, m_type);
+ }
+}
+
+void QSGShaderEffectMaterial::setUniforms(const QVector<QPair<QByteArray, QVariant> > &uniformValues)
+{
+ m_uniformValues = uniformValues;
+}
+
+void QSGShaderEffectMaterial::setTextureProviders(const QVector<QPair<QByteArray, QPointer<QSGItem> > > &textures)
+{
+ m_textures = textures;
+}
+
+const QVector<QPair<QByteArray, QPointer<QSGItem> > > &QSGShaderEffectMaterial::textureProviders() const
+{
+ return m_textures;
+}
+
+void QSGShaderEffectMaterial::updateTextures() const
+{
+ for (int i = 0; i < m_textures.size(); ++i) {
+ QSGItem *item = m_textures.at(i).second;
+ if (item) {
+ QSGTextureProvider *provider = QSGTextureProvider::from(item);
+ if (provider) {
+ QSGTexture *texture = provider->texture();
+ if (!texture) {
+ qWarning("QSGShaderEffectMaterial: no texture from %s [%s]",
+ qPrintable(item->objectName()),
+ item->metaObject()->className());
+ }
+ if (QSGDynamicTexture *t = qobject_cast<QSGDynamicTexture *>(provider->texture())) {
+ t->updateTexture();
+ }
+ }
+ }
+ }
+}
+
+
+QSGShaderEffectNode::QSGShaderEffectNode()
+{
+ QSGNode::setFlag(UsePreprocess, true);
+}
+
+QSGShaderEffectNode::~QSGShaderEffectNode()
+{
+}
+
+void QSGShaderEffectNode::markDirtyTexture()
+{
+ markDirty(DirtyMaterial);
+}
+
+void QSGShaderEffectNode::preprocess()
+{
+ Q_ASSERT(material());
+ static_cast<QSGShaderEffectMaterial *>(material())->updateTextures();
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/items/qsgshadereffectnode_p.h b/src/declarative/items/qsgshadereffectnode_p.h
new file mode 100644
index 0000000000..0be4b36294
--- /dev/null
+++ b/src/declarative/items/qsgshadereffectnode_p.h
@@ -0,0 +1,148 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef SHADEREFFECTNODE_H
+#define SHADEREFFECTNODE_H
+
+#include "qsgnode.h"
+#include "qsgmaterial.h"
+#include <private/qsgtextureprovider_p.h>
+#include <qsgitem.h>
+
+#include <QtCore/qsharedpointer.h>
+#include <QtCore/qpointer.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+struct QSGShaderEffectMaterialKey {
+ QByteArray vertexCode;
+ QByteArray fragmentCode;
+ const char *className;
+
+ bool operator == (const QSGShaderEffectMaterialKey &other) const;
+};
+
+uint qHash(const QSGShaderEffectMaterialKey &key);
+
+// TODO: Implement support for multisampling.
+struct QSGShaderEffectProgram : public QSGShaderEffectMaterialKey
+{
+ QSGShaderEffectProgram() : respectsOpacity(false), respectsMatrix(false) {}
+
+ QVector<QByteArray> attributeNames;
+ QSet<QByteArray> uniformNames;
+
+ uint respectsOpacity : 1;
+ uint respectsMatrix : 1;
+};
+
+
+class QSGCustomMaterialShader;
+class QSGShaderEffectMaterial : public QSGMaterial
+{
+public:
+ enum CullMode
+ {
+ NoCulling,
+ BackFaceCulling,
+ FrontFaceCulling
+ };
+
+ QSGShaderEffectMaterial();
+ virtual QSGMaterialType *type() const;
+ virtual QSGMaterialShader *createShader() const;
+ virtual int compare(const QSGMaterial *other) const;
+
+ void setCullMode(CullMode face);
+ CullMode cullMode() const;
+
+ void setProgramSource(const QSGShaderEffectProgram &);
+ void setUniforms(const QVector<QPair<QByteArray, QVariant> > &uniformValues);
+ void setTextureProviders(const QVector<QPair<QByteArray, QPointer<QSGItem> > > &textures);
+ const QVector<QPair<QByteArray, QPointer<QSGItem> > > &textureProviders() const;
+ void updateTextures() const;
+
+protected:
+ friend class QSGShaderEffectItem;
+ friend class QSGCustomMaterialShader;
+
+ // The type pointer needs to be unique. It is not safe to let the type object be part of the
+ // QSGShaderEffectMaterial, since it can be deleted and a new one constructed on top of the old
+ // one. The new QSGShaderEffectMaterial would then get the same type pointer as the old one, and
+ // CustomMaterialShaders based on the old one would incorrectly be used together with the new
+ // one. To guarantee that the type pointer is unique, the type object must live as long as
+ // there are any CustomMaterialShaders of that type.
+ QSharedPointer<QSGMaterialType> m_type;
+
+ QSGShaderEffectProgram m_source;
+ QVector<QPair<QByteArray, QVariant> > m_uniformValues;
+ QVector<QPair<QByteArray, QPointer<QSGItem> > > m_textures;
+ CullMode m_cullMode;
+
+ static QHash<QSGShaderEffectMaterialKey, QSharedPointer<QSGMaterialType> > materialMap;
+};
+
+
+class QSGShaderEffectMesh;
+
+class QSGShaderEffectNode : public QObject, public QSGGeometryNode
+{
+ Q_OBJECT
+public:
+ QSGShaderEffectNode();
+ virtual ~QSGShaderEffectNode();
+
+ virtual void preprocess();
+
+private Q_SLOTS:
+ void markDirtyTexture();
+
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // SHADEREFFECTNODE_H
diff --git a/src/declarative/items/qsgshadereffectsource.cpp b/src/declarative/items/qsgshadereffectsource.cpp
new file mode 100644
index 0000000000..e2c50bb80e
--- /dev/null
+++ b/src/declarative/items/qsgshadereffectsource.cpp
@@ -0,0 +1,818 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgshadereffectsource_p.h"
+
+#include "qsgitem_p.h"
+#include "qsgcanvas_p.h"
+#include <private/qsgadaptationlayer_p.h>
+#include <private/qsgrenderer_p.h>
+
+#include "qglframebufferobject.h"
+#include "qmath.h"
+#include <private/qsgtexture_p.h>
+
+QT_BEGIN_NAMESPACE
+
+DEFINE_BOOL_CONFIG_OPTION(qmlFboOverlay, QML_FBO_OVERLAY)
+
+QSGShaderEffectSourceNode::QSGShaderEffectSourceNode()
+{
+ setFlag(UsePreprocess, true);
+}
+
+void QSGShaderEffectSourceNode::markDirtyTexture()
+{
+ markDirty(DirtyMaterial);
+}
+
+
+QSGShaderEffectTexture::QSGShaderEffectTexture(QSGItem *shaderSource)
+ : QSGDynamicTexture()
+ , m_item(0)
+ , m_format(GL_RGBA)
+ , m_shaderSource(shaderSource)
+ , m_renderer(0)
+ , m_fbo(0)
+ , m_secondaryFbo(0)
+#ifdef QSG_DEBUG_FBO_OVERLAY
+ , m_debugOverlay(0)
+#endif
+ , m_mipmap(false)
+ , m_live(true)
+ , m_recursive(false)
+ , m_dirtyTexture(true)
+ , m_multisamplingSupportChecked(false)
+ , m_multisampling(false)
+ , m_grab(false)
+{
+}
+
+QSGShaderEffectTexture::~QSGShaderEffectTexture()
+{
+ delete m_renderer;
+ delete m_fbo;
+ delete m_secondaryFbo;
+#ifdef QSG_DEBUG_FBO_OVERLAY
+ delete m_debugOverlay;
+#endif
+}
+
+
+int QSGShaderEffectTexture::textureId() const
+{
+ return m_fbo ? m_fbo->texture() : 0;
+}
+
+bool QSGShaderEffectTexture::hasAlphaChannel() const
+{
+ return m_format != GL_RGB;
+}
+
+bool QSGShaderEffectTexture::hasMipmaps() const
+{
+ return m_mipmap;
+}
+
+
+void QSGShaderEffectTexture::bind()
+{
+#ifndef QT_NO_DEBUG
+ if (!m_recursive && m_fbo && ((m_multisampling && m_secondaryFbo->isBound()) || m_fbo->isBound()))
+ qWarning("ShaderEffectSource: \'recursive\' must be set to true when rendering recursively.");
+#endif
+ glBindTexture(GL_TEXTURE_2D, m_fbo ? m_fbo->texture() : 0);
+ updateBindOptions();
+}
+
+bool QSGShaderEffectTexture::updateTexture()
+{
+ if ((m_live || m_grab) && m_dirtyTexture) {
+ grab();
+ m_grab = false;
+ return true;
+ }
+ return false;
+}
+
+void QSGShaderEffectTexture::setHasMipmaps(bool mipmap)
+{
+ if (mipmap == m_mipmap)
+ return;
+ m_mipmap = mipmap;
+ if (m_mipmap && m_fbo && !m_fbo->format().mipmap())
+ markDirtyTexture();
+}
+
+
+void QSGShaderEffectTexture::setItem(QSGNode *item)
+{
+ if (item == m_item)
+ return;
+ m_item = item;
+ markDirtyTexture();
+}
+
+void QSGShaderEffectTexture::setRect(const QRectF &rect)
+{
+ if (rect == m_rect)
+ return;
+ m_rect = rect;
+ markDirtyTexture();
+}
+
+void QSGShaderEffectTexture::setSize(const QSize &size)
+{
+ if (size == m_size)
+ return;
+ m_size = size;
+ markDirtyTexture();
+}
+
+void QSGShaderEffectTexture::setFormat(GLenum format)
+{
+ if (format == m_format)
+ return;
+ m_format = format;
+ markDirtyTexture();
+}
+
+void QSGShaderEffectTexture::setLive(bool live)
+{
+ if (live == m_live)
+ return;
+ m_live = live;
+ markDirtyTexture();
+}
+
+void QSGShaderEffectTexture::scheduleUpdate()
+{
+ if (m_grab)
+ return;
+ m_grab = true;
+ if (m_dirtyTexture)
+ emit textureChanged();
+}
+
+void QSGShaderEffectTexture::setRecursive(bool recursive)
+{
+ m_recursive = recursive;
+}
+
+void QSGShaderEffectTexture::markDirtyTexture()
+{
+ m_dirtyTexture = true;
+ if (m_live || m_grab)
+ emit textureChanged();
+}
+
+void QSGShaderEffectTexture::grab()
+{
+ if (!m_item || m_size.isNull()) {
+ delete m_fbo;
+ delete m_secondaryFbo;
+ m_fbo = m_secondaryFbo = 0;
+ m_dirtyTexture = false;
+ return;
+ }
+ QSGNode *root = m_item;
+ while (root->childCount() && root->type() != QSGNode::RootNodeType)
+ root = root->childAtIndex(0);
+ if (root->type() != QSGNode::RootNodeType)
+ return;
+
+ if (m_size.isEmpty()) {
+ delete m_fbo;
+ delete m_secondaryFbo;
+ m_secondaryFbo = m_fbo = 0;
+ return;
+ }
+
+ QSGContext *context = QSGItemPrivate::get(m_shaderSource)->sceneGraphContext();
+
+ if (!m_renderer) {
+ m_renderer = context->createRenderer();
+ connect(m_renderer, SIGNAL(sceneGraphChanged()), this, SLOT(markDirtyTexture()), Qt::DirectConnection);
+ }
+ m_renderer->setRootNode(static_cast<QSGRootNode *>(root));
+
+ bool deleteFboLater = false;
+ if (!m_fbo || m_fbo->size() != m_size || m_fbo->format().internalTextureFormat() != m_format
+ || (!m_fbo->format().mipmap() && m_mipmap))
+ {
+ if (!m_multisamplingSupportChecked) {
+ QList<QByteArray> extensions = QByteArray((const char *)glGetString(GL_EXTENSIONS)).split(' ');
+ m_multisampling = extensions.contains("GL_EXT_framebuffer_multisample")
+ && extensions.contains("GL_EXT_framebuffer_blit");
+ m_multisamplingSupportChecked = true;
+ }
+ if (m_multisampling) {
+ // Don't delete the FBO right away in case it is used recursively.
+ deleteFboLater = true;
+ delete m_secondaryFbo;
+ QGLFramebufferObjectFormat format;
+
+ format.setAttachment(QGLFramebufferObject::CombinedDepthStencil);
+ format.setInternalTextureFormat(m_format);
+ format.setSamples(8);
+ m_secondaryFbo = new QGLFramebufferObject(m_size, format);
+ } else {
+ QGLFramebufferObjectFormat format;
+ format.setAttachment(QGLFramebufferObject::CombinedDepthStencil);
+ format.setInternalTextureFormat(m_format);
+ format.setMipmap(m_mipmap);
+ if (m_recursive) {
+ deleteFboLater = true;
+ delete m_secondaryFbo;
+ m_secondaryFbo = new QGLFramebufferObject(m_size, format);
+ glBindTexture(GL_TEXTURE_2D, m_secondaryFbo->texture());
+ updateBindOptions(true);
+ } else {
+ delete m_fbo;
+ delete m_secondaryFbo;
+ m_fbo = new QGLFramebufferObject(m_size, format);
+ m_secondaryFbo = 0;
+ glBindTexture(GL_TEXTURE_2D, m_fbo->texture());
+ updateBindOptions(true);
+ }
+ }
+ }
+
+ if (m_recursive && !m_secondaryFbo) {
+ // m_fbo already created, m_recursive was just set.
+ Q_ASSERT(m_fbo);
+ Q_ASSERT(!m_multisampling);
+
+ m_secondaryFbo = new QGLFramebufferObject(m_size, m_fbo->format());
+ glBindTexture(GL_TEXTURE_2D, m_secondaryFbo->texture());
+ updateBindOptions(true);
+ }
+
+ // Render texture.
+ root->markDirty(QSGNode::DirtyForceUpdate); // Force matrix, clip and opacity update.
+ m_renderer->nodeChanged(root, QSGNode::DirtyForceUpdate); // Force render list update.
+
+#ifdef QSG_DEBUG_FBO_OVERLAY
+ if (qmlFboOverlay()) {
+ if (!m_debugOverlay)
+ m_debugOverlay = context->createRectangleNode();
+ m_debugOverlay->setRect(QRectF(0, 0, m_size.width(), m_size.height()));
+ m_debugOverlay->setColor(QColor(0xff, 0x00, 0x80, 0x40));
+ m_debugOverlay->setPenColor(QColor());
+ m_debugOverlay->setPenWidth(0);
+ m_debugOverlay->setRadius(0);
+ m_debugOverlay->update();
+ root->appendChildNode(m_debugOverlay);
+ }
+#endif
+
+ m_dirtyTexture = false;
+
+ const QGLContext *ctx = QGLContext::currentContext();
+ m_renderer->setDeviceRect(m_size);
+ m_renderer->setViewportRect(m_size);
+ QRectF mirrored(m_rect.left(), m_rect.bottom(), m_rect.width(), -m_rect.height());
+ m_renderer->setProjectMatrixToRect(mirrored);
+ m_renderer->setClearColor(Qt::transparent);
+
+ if (m_multisampling) {
+ m_renderer->renderScene(BindableFbo(m_secondaryFbo));
+
+ if (deleteFboLater) {
+ delete m_fbo;
+ QGLFramebufferObjectFormat format;
+ format.setInternalTextureFormat(m_format);
+ format.setAttachment(QGLFramebufferObject::NoAttachment);
+ format.setMipmap(m_mipmap);
+ format.setSamples(0);
+ m_fbo = new QGLFramebufferObject(m_size, format);
+ glBindTexture(GL_TEXTURE_2D, m_fbo->texture());
+ updateBindOptions(true);
+ }
+
+ QRect r(QPoint(), m_size);
+ QGLFramebufferObject::blitFramebuffer(m_fbo, r, m_secondaryFbo, r);
+ } else {
+ if (m_recursive) {
+ m_renderer->renderScene(BindableFbo(m_secondaryFbo));
+
+ if (deleteFboLater) {
+ delete m_fbo;
+ QGLFramebufferObjectFormat format;
+ format.setAttachment(QGLFramebufferObject::CombinedDepthStencil);
+ format.setInternalTextureFormat(m_format);
+ format.setMipmap(m_mipmap);
+ m_fbo = new QGLFramebufferObject(m_size, format);
+ glBindTexture(GL_TEXTURE_2D, m_fbo->texture());
+ updateBindOptions(true);
+ }
+ qSwap(m_fbo, m_secondaryFbo);
+ } else {
+ m_renderer->renderScene(BindableFbo(m_fbo));
+ }
+ }
+
+ if (m_mipmap) {
+ glBindTexture(GL_TEXTURE_2D, textureId());
+ ctx->functions()->glGenerateMipmap(GL_TEXTURE_2D);
+ }
+
+ root->markDirty(QSGNode::DirtyForceUpdate); // Force matrix, clip, opacity and render list update.
+
+#ifdef QSG_DEBUG_FBO_OVERLAY
+ if (qmlFboOverlay())
+ root->removeChildNode(m_debugOverlay);
+#endif
+ if (m_recursive)
+ markDirtyTexture(); // Continuously update if 'live' and 'recursive'.
+}
+
+/*!
+ \qmlclass ShaderEffectSource QSGShaderEffectSource
+ \since 5.0
+ \ingroup qml-basic-visual-elements
+ \brief The ShaderEffectSource element renders a QML element into a texture
+ and displays it.
+ \inherits Item
+
+ The ShaderEffectSource element renders \l sourceItem into a texture and
+ displays it in the scene. \l sourceItem is drawn into the texture as though
+ it was a fully opaque root element. Thus \l sourceItem itself can be
+ invisible, but still appear in the texture.
+
+ ShaderEffectSource can be used as:
+ \list
+ \o a texture source in a \l ShaderEffectItem.
+ This allows you to apply custom shader effects to any QML element.
+ \o a cache for a complex element.
+ The complex element can be rendered once into the texture, which can
+ then be animated freely without the need to render the complex element
+ again every frame.
+ \o an opacity layer.
+ ShaderEffectSource allows you to apply an opacity to elements as a group
+ rather than each element individually.
+ \endlist
+
+ \row
+ \o \image declarative-shadereffectsource.png
+ \o \qml
+ import QtQuick 2.0
+
+ Rectangle {
+ width: 200
+ height: 100
+ gradient: Gradient {
+ GradientStop { position: 0; color: "white" }
+ GradientStop { position: 1; color: "black" }
+ }
+ Row {
+ opacity: 0.5
+ Item {
+ id: foo
+ width: 100; height: 100
+ Rectangle { x: 5; y: 5; width: 60; height: 60; color: "red" }
+ Rectangle { x: 20; y: 20; width: 60; height: 60; color: "orange" }
+ Rectangle { x: 35; y: 35; width: 60; height: 60; color: "yellow" }
+ }
+ ShaderEffectSource {
+ width: 100; height: 100
+ sourceItem: foo
+ }
+ }
+ }
+ \endqml
+ \endrow
+
+ The ShaderEffectSource element does not redirect any mouse or keyboard
+ input to \l sourceItem. If you hide the \l sourceItem by setting
+ \l{Item::visible}{visible} to false or \l{Item::opacity}{opacity} to zero,
+ it will no longer react to input. In cases where the ShaderEffectSource is
+ meant to replace the \l sourceItem, you typically want to hide the
+ \l sourceItem while still handling input. For this, you can use
+ the \l hideSource property.
+
+ \note If \l sourceItem is a \l Rectangle with border, by default half the
+ border width falls outside the texture. To get the whole border, you can
+ extend the \l sourceRect.
+
+ \warning In most cases, using a ShaderEffectSource will decrease
+ performance, and in all cases, it will increase video memory usage.
+ Rendering through a ShaderEffectSource might also lead to lower quality
+ since some OpenGL implementations support multisampled backbuffer,
+ but not multisampled framebuffer objects.
+*/
+
+QSGShaderEffectSource::QSGShaderEffectSource(QSGItem *parent)
+ : QSGItem(parent)
+ , m_wrapMode(ClampToEdge)
+ , m_sourceItem(0)
+ , m_textureSize(0, 0)
+ , m_format(RGBA)
+ , m_live(true)
+ , m_hideSource(false)
+ , m_mipmap(false)
+ , m_recursive(false)
+ , m_grab(true)
+{
+ setFlag(ItemHasContents);
+ m_texture = new QSGShaderEffectTexture(this);
+ connect(m_texture, SIGNAL(textureChanged()), this, SIGNAL(textureChanged()), Qt::DirectConnection);
+ connect(m_texture, SIGNAL(textureChanged()), this, SLOT(update()));
+}
+
+QSGShaderEffectSource::~QSGShaderEffectSource()
+{
+ delete m_texture;
+ if (m_sourceItem)
+ QSGItemPrivate::get(m_sourceItem)->derefFromEffectItem(m_hideSource);
+}
+
+/*!
+ \qmlproperty enumeration ShaderEffectSource::wrapMode
+
+ This property defines the OpenGL wrap modes associated with the texture.
+ Modifying this property makes most sense when the element is used as a
+ source texture of a \l ShaderEffectItem.
+
+ \list
+ \o ShaderEffectSource.ClampToEdge - GL_CLAMP_TO_EDGE both horizontally and vertically
+ \o ShaderEffectSource.RepeatHorizontally - GL_REPEAT horizontally, GL_CLAMP_TO_EDGE vertically
+ \o ShaderEffectSource.RepeatVertically - GL_CLAMP_TO_EDGE horizontally, GL_REPEAT vertically
+ \o ShaderEffectSource.Repeat - GL_REPEAT both horizontally and vertically
+ \endlist
+
+ \note Some OpenGL ES 2 implementations do not support the GL_REPEAT
+ wrap mode with non-power-of-two textures.
+*/
+
+QSGShaderEffectSource::WrapMode QSGShaderEffectSource::wrapMode() const
+{
+ return m_wrapMode;
+}
+
+void QSGShaderEffectSource::setWrapMode(WrapMode mode)
+{
+ if (mode == m_wrapMode)
+ return;
+ m_wrapMode = mode;
+ update();
+ emit wrapModeChanged();
+}
+
+/*!
+ \qmlproperty Item ShaderEffectSource::sourceItem
+
+ This property holds the element to be rendered into the texture.
+*/
+
+QSGItem *QSGShaderEffectSource::sourceItem() const
+{
+ return m_sourceItem;
+}
+
+void QSGShaderEffectSource::setSourceItem(QSGItem *item)
+{
+ if (item == m_sourceItem)
+ return;
+ if (m_sourceItem)
+ QSGItemPrivate::get(m_sourceItem)->derefFromEffectItem(m_hideSource);
+ m_sourceItem = item;
+ if (m_sourceItem) {
+ // TODO: Find better solution.
+ // 'm_sourceItem' needs a canvas to get a scenegraph node.
+ // The easiest way to make sure it gets a canvas is to
+ // make it a part of the same item tree as 'this'.
+ if (m_sourceItem->parentItem() == 0) {
+ m_sourceItem->setParentItem(this);
+ m_sourceItem->setVisible(false);
+ }
+ QSGItemPrivate::get(m_sourceItem)->refFromEffectItem(m_hideSource);
+ }
+ update();
+ emit sourceItemChanged();
+}
+
+/*!
+ \qmlproperty rect ShaderEffectSource::sourceRect
+
+ This property defines which rectangular area of the \l sourceItem to
+ render into the texture. The source rectangle can be larger than
+ \l sourceItem itself. If the rectangle is null, which is the default,
+ the whole \l sourceItem is rendered to texture.
+*/
+
+QRectF QSGShaderEffectSource::sourceRect() const
+{
+ return m_sourceRect;
+}
+
+void QSGShaderEffectSource::setSourceRect(const QRectF &rect)
+{
+ if (rect == m_sourceRect)
+ return;
+ m_sourceRect = rect;
+ update();
+ emit sourceRectChanged();
+}
+
+/*!
+ \qmlproperty size ShaderEffectSource::textureSize
+
+ This property holds the size of the texture. If it is empty, which is the
+ default, the size of the source rectangle is used.
+*/
+
+QSize QSGShaderEffectSource::textureSize() const
+{
+ return m_textureSize;
+}
+
+void QSGShaderEffectSource::setTextureSize(const QSize &size)
+{
+ if (size == m_textureSize)
+ return;
+ m_textureSize = size;
+ update();
+ emit textureSizeChanged();
+}
+
+/*!
+ \qmlproperty enumeration ShaderEffectSource::format
+
+ This property defines the internal OpenGL format of the texture.
+ Modifying this property makes most sense when the element is used as a
+ source texture of a \l ShaderEffectItem. Depending on the OpenGL
+ implementation, this property might allow you to save some texture memory.
+
+ \list
+ \o ShaderEffectSource.Alpha - GL_ALPHA
+ \o ShaderEffectSource.RGB - GL_RGB
+ \o ShaderEffectSource.RGBA - GL_RGBA
+ \endlist
+
+ \note Some OpenGL implementations do not support the GL_ALPHA format.
+*/
+
+QSGShaderEffectSource::Format QSGShaderEffectSource::format() const
+{
+ return m_format;
+}
+
+void QSGShaderEffectSource::setFormat(QSGShaderEffectSource::Format format)
+{
+ if (format == m_format)
+ return;
+ m_format = format;
+ update();
+ emit formatChanged();
+}
+
+/*!
+ \qmlproperty bool ShaderEffectSource::live
+
+ If this property is true, the texture is updated whenever the
+ \l sourceItem changes. Otherwise, it will be a frozen image of the
+ \l sourceItem. The property is true by default.
+*/
+
+bool QSGShaderEffectSource::live() const
+{
+ return m_live;
+}
+
+void QSGShaderEffectSource::setLive(bool live)
+{
+ if (live == m_live)
+ return;
+ m_live = live;
+ update();
+ emit liveChanged();
+}
+
+/*!
+ \qmlproperty bool ShaderEffectSource::hideSource
+
+ If this property is true, the \l sourceItem is hidden, though it will still
+ be rendered into the texture. As opposed to hiding the \l sourceItem by
+ setting \l{Item::visible}{visible} to false, setting this property to true
+ will not prevent mouse or keyboard input from reaching \l sourceItem.
+ The property is useful when the ShaderEffectSource is anchored on top of,
+ and meant to replace the \l sourceItem.
+*/
+
+bool QSGShaderEffectSource::hideSource() const
+{
+ return m_hideSource;
+}
+
+void QSGShaderEffectSource::setHideSource(bool hide)
+{
+ if (hide == m_hideSource)
+ return;
+ if (m_sourceItem) {
+ QSGItemPrivate::get(m_sourceItem)->refFromEffectItem(hide);
+ QSGItemPrivate::get(m_sourceItem)->derefFromEffectItem(m_hideSource);
+ }
+ m_hideSource = hide;
+ update();
+ emit hideSourceChanged();
+}
+
+/*!
+ \qmlproperty bool ShaderEffectSource::mipmap
+
+ If this property is true, mipmaps are generated for the texture.
+
+ \note Some OpenGL ES 2 implementations do not support mipmapping of
+ non-power-of-two textures.
+*/
+
+bool QSGShaderEffectSource::mipmap() const
+{
+ return m_mipmap;
+}
+
+void QSGShaderEffectSource::setMipmap(bool enabled)
+{
+ if (enabled == m_mipmap)
+ return;
+ m_mipmap = enabled;
+ update();
+ emit mipmapChanged();
+}
+
+/*!
+ \qmlproperty bool ShaderEffectSource::recursive
+
+ Set this property to true if the ShaderEffectSource has a dependency on
+ itself. ShaderEffectSources form a dependency chain, where one
+ ShaderEffectSource can be part of the \l sourceItem of another.
+ If there is a loop in this chain, a ShaderEffectSource could end up trying
+ to render into the same texture it is using as source, which is not allowed
+ by OpenGL. When this property is set to true, an extra texture is allocated
+ so that ShaderEffectSource can keep a copy of the texture from the previous
+ frame. It can then render into one texture and use the texture from the
+ previous frame as source.
+
+ Setting both this property and \l live to true will cause the scene graph
+ to render continuously. Since the ShaderEffectSource depends on itself,
+ updating it means that it immediately becomes dirty again.
+*/
+
+bool QSGShaderEffectSource::recursive() const
+{
+ return m_recursive;
+}
+
+void QSGShaderEffectSource::setRecursive(bool enabled)
+{
+ if (enabled == m_recursive)
+ return;
+ m_recursive = enabled;
+ emit recursiveChanged();
+}
+
+/*!
+ \qmlmethod ShaderEffectSource::scheduleUpdate()
+
+ Schedules a re-rendering of the texture for the next frame.
+ Use this to update the texture when \l live is false.
+*/
+
+void QSGShaderEffectSource::scheduleUpdate()
+{
+ if (m_grab)
+ return;
+ m_grab = true;
+ update();
+}
+
+static void get_wrap_mode(QSGShaderEffectSource::WrapMode mode, QSGTexture::WrapMode *hWrap, QSGTexture::WrapMode *vWrap)
+{
+ switch (mode) {
+ case QSGShaderEffectSource::RepeatHorizontally:
+ *hWrap = QSGTexture::Repeat;
+ *vWrap = QSGTexture::ClampToEdge;
+ break;
+ case QSGShaderEffectSource::RepeatVertically:
+ *vWrap = QSGTexture::Repeat;
+ *hWrap = QSGTexture::ClampToEdge;
+ break;
+ case QSGShaderEffectSource::Repeat:
+ *hWrap = *vWrap = QSGTexture::Repeat;
+ break;
+ default:
+ // QSGShaderEffectSource::ClampToEdge
+ *hWrap = *vWrap = QSGTexture::ClampToEdge;
+ break;
+ }
+}
+
+
+QSGTexture *QSGShaderEffectSource::texture() const
+{
+ m_texture->setMipmapFiltering(m_mipmap ? QSGTexture::Linear : QSGTexture::None);
+ m_texture->setFiltering(QSGItemPrivate::get(this)->smooth ? QSGTexture::Linear : QSGTexture::Nearest);
+ QSGTexture::WrapMode h, v;
+ get_wrap_mode(m_wrapMode, &h, &v);
+ m_texture->setHorizontalWrapMode(h);
+ m_texture->setVerticalWrapMode(v);
+ return m_texture;
+}
+
+QSGNode *QSGShaderEffectSource::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
+{
+ if (!m_sourceItem) {
+ delete oldNode;
+ return 0;
+ }
+
+ QSGShaderEffectSourceNode *node = static_cast<QSGShaderEffectSourceNode *>(oldNode);
+ if (!node) {
+ node = new QSGShaderEffectSourceNode;
+ node->setTexture(m_texture);
+ connect(m_texture, SIGNAL(textureChanged()), node, SLOT(markDirtyTexture()), Qt::DirectConnection);
+ }
+
+ // If live and recursive, update continuously.
+ if (m_live && m_recursive)
+ node->markDirty(QSGNode::DirtyMaterial);
+
+ QSGShaderEffectTexture *tex = qobject_cast<QSGShaderEffectTexture *>(m_texture);
+
+ tex->setLive(m_live);
+ tex->setItem(QSGItemPrivate::get(m_sourceItem)->itemNode());
+ QRectF sourceRect = m_sourceRect.isNull()
+ ? QRectF(0, 0, m_sourceItem->width(), m_sourceItem->height())
+ : m_sourceRect;
+ tex->setRect(sourceRect);
+ QSize textureSize = m_textureSize.isEmpty()
+ ? QSize(qCeil(qAbs(sourceRect.width())), qCeil(qAbs(sourceRect.height())))
+ : m_textureSize;
+ tex->setSize(textureSize);
+ tex->setRecursive(m_recursive);
+ tex->setFormat(GLenum(m_format));
+ tex->setHasMipmaps(m_mipmap);
+
+ if (m_grab)
+ tex->scheduleUpdate();
+ m_grab = false;
+
+ QSGTexture::Filtering filtering = QSGItemPrivate::get(this)->smooth
+ ? QSGTexture::Linear
+ : QSGTexture::Nearest;
+ QSGTexture::Filtering mmFiltering = m_mipmap ? filtering : QSGTexture::None;
+ node->setMipmapFiltering(mmFiltering);
+ node->setFiltering(filtering);
+
+ QSGTexture::WrapMode hWrap, vWrap;
+ get_wrap_mode(m_wrapMode, &hWrap, &vWrap);
+
+ node->setHorizontalWrapMode(hWrap);
+ node->setVerticalWrapMode(vWrap);
+ node->setTargetRect(QRectF(0, 0, width(), height()));
+ node->setSourceRect(QRectF(0, 0, 1, 1));
+ node->update();
+
+ return node;
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/items/qsgshadereffectsource_p.h b/src/declarative/items/qsgshadereffectsource_p.h
new file mode 100644
index 0000000000..5842ec7295
--- /dev/null
+++ b/src/declarative/items/qsgshadereffectsource_p.h
@@ -0,0 +1,246 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef SHADEREFFECTSOURCE_H
+#define SHADEREFFECTSOURCE_H
+
+#include "qsgitem.h"
+#include <private/qsgtextureprovider_p.h>
+#include <private/qsgadaptationlayer_p.h>
+#include <private/qsgcontext_p.h>
+#include <private/qsgdefaultimagenode_p.h>
+
+#include "qpointer.h"
+#include "qsize.h"
+#include "qrect.h"
+
+#define QSG_DEBUG_FBO_OVERLAY
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QSGNode;
+class UpdatePaintNodeData;
+class QGLFramebufferObject;
+
+class QSGShaderEffectSourceNode : public QObject, public QSGDefaultImageNode
+{
+ Q_OBJECT
+
+public:
+ QSGShaderEffectSourceNode();
+
+private Q_SLOTS:
+ void markDirtyTexture();
+};
+
+class QSGShaderEffectTexture : public QSGDynamicTexture
+{
+ Q_OBJECT
+public:
+ QSGShaderEffectTexture(QSGItem *shaderSource);
+ ~QSGShaderEffectTexture();
+
+ virtual bool updateTexture();
+
+ // The item's "paint node", not effect node.
+ QSGNode *item() const { return m_item; }
+ void setItem(QSGNode *item);
+
+ QRectF rect() const { return m_rect; }
+ void setRect(const QRectF &rect);
+
+ QSize size() const { return m_size; }
+ void setSize(const QSize &size);
+
+ void setHasMipmaps(bool mipmap);
+
+ void bind();
+
+ bool hasAlphaChannel() const;
+ bool hasMipmaps() const;
+ int textureId() const;
+ QSize textureSize() const { return m_size; }
+
+ GLenum format() const { return m_format; }
+ void setFormat(GLenum format);
+
+ bool live() const { return bool(m_live); }
+ void setLive(bool live);
+
+ bool recursive() const { return bool(m_recursive); }
+ void setRecursive(bool recursive);
+
+ void scheduleUpdate();
+
+Q_SIGNALS:
+ void textureChanged();
+
+public Q_SLOTS:
+ void markDirtyTexture();
+
+private:
+ void grab();
+
+ QSGNode *m_item;
+ QRectF m_rect;
+ QSize m_size;
+ GLenum m_format;
+
+ QSGItem *m_shaderSource;
+ QSGRenderer *m_renderer;
+ QGLFramebufferObject *m_fbo;
+ QGLFramebufferObject *m_secondaryFbo;
+
+#ifdef QSG_DEBUG_FBO_OVERLAY
+ QSGRectangleNode *m_debugOverlay;
+#endif
+
+ uint m_mipmap : 1;
+ uint m_live : 1;
+ uint m_recursive : 1;
+ uint m_dirtyTexture : 1;
+ uint m_multisamplingSupportChecked : 1;
+ uint m_multisampling : 1;
+ uint m_grab : 1;
+};
+
+class QSGShaderEffectSource : public QSGItem, public QSGTextureProvider
+{
+ Q_OBJECT
+ Q_PROPERTY(WrapMode wrapMode READ wrapMode WRITE setWrapMode NOTIFY wrapModeChanged)
+ Q_PROPERTY(QSGItem *sourceItem READ sourceItem WRITE setSourceItem NOTIFY sourceItemChanged)
+ Q_PROPERTY(QRectF sourceRect READ sourceRect WRITE setSourceRect NOTIFY sourceRectChanged)
+ Q_PROPERTY(QSize textureSize READ textureSize WRITE setTextureSize NOTIFY textureSizeChanged)
+ Q_PROPERTY(Format format READ format WRITE setFormat NOTIFY formatChanged)
+ Q_PROPERTY(bool live READ live WRITE setLive NOTIFY liveChanged)
+ Q_PROPERTY(bool hideSource READ hideSource WRITE setHideSource NOTIFY hideSourceChanged)
+ Q_PROPERTY(bool mipmap READ mipmap WRITE setMipmap NOTIFY mipmapChanged)
+ Q_PROPERTY(bool recursive READ recursive WRITE setRecursive NOTIFY recursiveChanged)
+ Q_INTERFACES(QSGTextureProvider)
+ Q_ENUMS(Format WrapMode)
+public:
+ enum WrapMode {
+ ClampToEdge,
+ RepeatHorizontally,
+ RepeatVertically,
+ Repeat
+ };
+
+ enum Format {
+ Alpha = GL_ALPHA,
+ RGB = GL_RGB,
+ RGBA = GL_RGBA
+ };
+
+ QSGShaderEffectSource(QSGItem *parent = 0);
+ ~QSGShaderEffectSource();
+
+ WrapMode wrapMode() const;
+ void setWrapMode(WrapMode mode);
+
+ QSGItem *sourceItem() const;
+ void setSourceItem(QSGItem *item);
+
+ QRectF sourceRect() const;
+ void setSourceRect(const QRectF &rect);
+
+ QSize textureSize() const;
+ void setTextureSize(const QSize &size);
+
+ Format format() const;
+ void setFormat(Format format);
+
+ bool live() const;
+ void setLive(bool live);
+
+ bool hideSource() const;
+ void setHideSource(bool hide);
+
+ bool mipmap() const;
+ void setMipmap(bool enabled);
+
+ bool recursive() const;
+ void setRecursive(bool enabled);
+
+ QSGTexture *texture() const;
+ const char *textureChangedSignal() const { return SIGNAL(textureChanged()); }
+
+ Q_INVOKABLE void scheduleUpdate();
+
+Q_SIGNALS:
+ void wrapModeChanged();
+ void sourceItemChanged();
+ void sourceRectChanged();
+ void textureSizeChanged();
+ void formatChanged();
+ void liveChanged();
+ void hideSourceChanged();
+ void mipmapChanged();
+ void recursiveChanged();
+
+ void textureChanged();
+
+protected:
+ virtual QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *);
+
+private:
+ QSGTexture *m_texture;
+ WrapMode m_wrapMode;
+ QPointer<QSGItem> m_sourceItem;
+ QRectF m_sourceRect;
+ QSize m_textureSize;
+ Format m_format;
+ uint m_live : 1;
+ uint m_hideSource : 1;
+ uint m_mipmap : 1;
+ uint m_recursive : 1;
+ uint m_grab : 1;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // SHADEREFFECTSOURCE_H
diff --git a/src/declarative/items/qsgstateoperations.cpp b/src/declarative/items/qsgstateoperations.cpp
new file mode 100644
index 0000000000..5390440e39
--- /dev/null
+++ b/src/declarative/items/qsgstateoperations.cpp
@@ -0,0 +1,1347 @@
+// Commit: 726a8b16c52fe4608c89d740b47361a2b073ce01
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgstateoperations_p.h"
+#include "qsgitem_p.h"
+
+#include <private/qdeclarativestate_p_p.h>
+
+#include <QtDeclarative/qdeclarativeinfo.h>
+#include <QtCore/qmath.h>
+
+QT_BEGIN_NAMESPACE
+
+class QSGParentChangePrivate : public QDeclarativeStateOperationPrivate
+{
+ Q_DECLARE_PUBLIC(QSGParentChange)
+public:
+ QSGParentChangePrivate() : target(0), parent(0), origParent(0), origStackBefore(0),
+ rewindParent(0), rewindStackBefore(0) {}
+
+ QSGItem *target;
+ QDeclarativeGuard<QSGItem> parent;
+ QDeclarativeGuard<QSGItem> origParent;
+ QDeclarativeGuard<QSGItem> origStackBefore;
+ QSGItem *rewindParent;
+ QSGItem *rewindStackBefore;
+
+ QDeclarativeNullableValue<QDeclarativeScriptString> xString;
+ QDeclarativeNullableValue<QDeclarativeScriptString> yString;
+ QDeclarativeNullableValue<QDeclarativeScriptString> widthString;
+ QDeclarativeNullableValue<QDeclarativeScriptString> heightString;
+ QDeclarativeNullableValue<QDeclarativeScriptString> scaleString;
+ QDeclarativeNullableValue<QDeclarativeScriptString> rotationString;
+
+ void doChange(QSGItem *targetParent, QSGItem *stackBefore = 0);
+};
+
+void QSGParentChangePrivate::doChange(QSGItem *targetParent, QSGItem *stackBefore)
+{
+ if (targetParent && target && target->parentItem()) {
+ Q_Q(QSGParentChange);
+ bool ok;
+ const QTransform &transform = target->parentItem()->itemTransform(targetParent, &ok);
+ if (transform.type() >= QTransform::TxShear || !ok) {
+ qmlInfo(q) << QSGParentChange::tr("Unable to preserve appearance under complex transform");
+ ok = false;
+ }
+
+ qreal scale = 1;
+ qreal rotation = 0;
+ bool isRotate = (transform.type() == QTransform::TxRotate) || (transform.m11() < 0);
+ if (ok && !isRotate) {
+ if (transform.m11() == transform.m22())
+ scale = transform.m11();
+ else {
+ qmlInfo(q) << QSGParentChange::tr("Unable to preserve appearance under non-uniform scale");
+ ok = false;
+ }
+ } else if (ok && isRotate) {
+ if (transform.m11() == transform.m22())
+ scale = qSqrt(transform.m11()*transform.m11() + transform.m12()*transform.m12());
+ else {
+ qmlInfo(q) << QSGParentChange::tr("Unable to preserve appearance under non-uniform scale");
+ ok = false;
+ }
+
+ if (scale != 0)
+ rotation = atan2(transform.m12()/scale, transform.m11()/scale) * 180/M_PI;
+ else {
+ qmlInfo(q) << QSGParentChange::tr("Unable to preserve appearance under scale of 0");
+ ok = false;
+ }
+ }
+
+ const QPointF &point = transform.map(QPointF(target->x(),target->y()));
+ qreal x = point.x();
+ qreal y = point.y();
+
+ // setParentItem will update the transformOriginPoint if needed
+ target->setParentItem(targetParent);
+
+ if (ok && target->transformOrigin() != QSGItem::TopLeft) {
+ qreal tempxt = target->transformOriginPoint().x();
+ qreal tempyt = target->transformOriginPoint().y();
+ QTransform t;
+ t.translate(-tempxt, -tempyt);
+ t.rotate(rotation);
+ t.scale(scale, scale);
+ t.translate(tempxt, tempyt);
+ const QPointF &offset = t.map(QPointF(0,0));
+ x += offset.x();
+ y += offset.y();
+ }
+
+ if (ok) {
+ //qDebug() << x << y << rotation << scale;
+ target->setX(x);
+ target->setY(y);
+ target->setRotation(target->rotation() + rotation);
+ target->setScale(target->scale() * scale);
+ }
+ } else if (target) {
+ target->setParentItem(targetParent);
+ }
+
+ //restore the original stack position.
+ //### if stackBefore has also been reparented this won't work
+ if (stackBefore)
+ target->stackBefore(stackBefore);
+}
+
+QSGParentChange::QSGParentChange(QObject *parent)
+ : QDeclarativeStateOperation(*(new QSGParentChangePrivate), parent)
+{
+}
+
+QSGParentChange::~QSGParentChange()
+{
+}
+
+QDeclarativeScriptString QSGParentChange::x() const
+{
+ Q_D(const QSGParentChange);
+ return d->xString.value;
+}
+
+void QSGParentChange::setX(QDeclarativeScriptString x)
+{
+ Q_D(QSGParentChange);
+ d->xString = x;
+}
+
+bool QSGParentChange::xIsSet() const
+{
+ Q_D(const QSGParentChange);
+ return d->xString.isValid();
+}
+
+QDeclarativeScriptString QSGParentChange::y() const
+{
+ Q_D(const QSGParentChange);
+ return d->yString.value;
+}
+
+void QSGParentChange::setY(QDeclarativeScriptString y)
+{
+ Q_D(QSGParentChange);
+ d->yString = y;
+}
+
+bool QSGParentChange::yIsSet() const
+{
+ Q_D(const QSGParentChange);
+ return d->yString.isValid();
+}
+
+QDeclarativeScriptString QSGParentChange::width() const
+{
+ Q_D(const QSGParentChange);
+ return d->widthString.value;
+}
+
+void QSGParentChange::setWidth(QDeclarativeScriptString width)
+{
+ Q_D(QSGParentChange);
+ d->widthString = width;
+}
+
+bool QSGParentChange::widthIsSet() const
+{
+ Q_D(const QSGParentChange);
+ return d->widthString.isValid();
+}
+
+QDeclarativeScriptString QSGParentChange::height() const
+{
+ Q_D(const QSGParentChange);
+ return d->heightString.value;
+}
+
+void QSGParentChange::setHeight(QDeclarativeScriptString height)
+{
+ Q_D(QSGParentChange);
+ d->heightString = height;
+}
+
+bool QSGParentChange::heightIsSet() const
+{
+ Q_D(const QSGParentChange);
+ return d->heightString.isValid();
+}
+
+QDeclarativeScriptString QSGParentChange::scale() const
+{
+ Q_D(const QSGParentChange);
+ return d->scaleString.value;
+}
+
+void QSGParentChange::setScale(QDeclarativeScriptString scale)
+{
+ Q_D(QSGParentChange);
+ d->scaleString = scale;
+}
+
+bool QSGParentChange::scaleIsSet() const
+{
+ Q_D(const QSGParentChange);
+ return d->scaleString.isValid();
+}
+
+QDeclarativeScriptString QSGParentChange::rotation() const
+{
+ Q_D(const QSGParentChange);
+ return d->rotationString.value;
+}
+
+void QSGParentChange::setRotation(QDeclarativeScriptString rotation)
+{
+ Q_D(QSGParentChange);
+ d->rotationString = rotation;
+}
+
+bool QSGParentChange::rotationIsSet() const
+{
+ Q_D(const QSGParentChange);
+ return d->rotationString.isValid();
+}
+
+QSGItem *QSGParentChange::originalParent() const
+{
+ Q_D(const QSGParentChange);
+ return d->origParent;
+}
+
+QSGItem *QSGParentChange::object() const
+{
+ Q_D(const QSGParentChange);
+ return d->target;
+}
+
+void QSGParentChange::setObject(QSGItem *target)
+{
+ Q_D(QSGParentChange);
+ d->target = target;
+}
+
+QSGItem *QSGParentChange::parent() const
+{
+ Q_D(const QSGParentChange);
+ return d->parent;
+}
+
+void QSGParentChange::setParent(QSGItem *parent)
+{
+ Q_D(QSGParentChange);
+ d->parent = parent;
+}
+
+QDeclarativeStateOperation::ActionList QSGParentChange::actions()
+{
+ Q_D(QSGParentChange);
+ if (!d->target || !d->parent)
+ return ActionList();
+
+ ActionList actions;
+
+ QDeclarativeAction a;
+ a.event = this;
+ actions << a;
+
+ if (d->xString.isValid()) {
+ bool ok = false;
+ QString script = d->xString.value.script();
+ qreal x = script.toFloat(&ok);
+ if (ok) {
+ QDeclarativeAction xa(d->target, QLatin1String("x"), x);
+ actions << xa;
+ } else {
+ QDeclarativeBinding *newBinding = new QDeclarativeBinding(script, d->target, qmlContext(this));
+ newBinding->setTarget(QDeclarativeProperty(d->target, QLatin1String("x")));
+ QDeclarativeAction xa;
+ xa.property = newBinding->property();
+ xa.toBinding = newBinding;
+ xa.fromValue = xa.property.read();
+ xa.deletableToBinding = true;
+ actions << xa;
+ }
+ }
+
+ if (d->yString.isValid()) {
+ bool ok = false;
+ QString script = d->yString.value.script();
+ qreal y = script.toFloat(&ok);
+ if (ok) {
+ QDeclarativeAction ya(d->target, QLatin1String("y"), y);
+ actions << ya;
+ } else {
+ QDeclarativeBinding *newBinding = new QDeclarativeBinding(script, d->target, qmlContext(this));
+ newBinding->setTarget(QDeclarativeProperty(d->target, QLatin1String("y")));
+ QDeclarativeAction ya;
+ ya.property = newBinding->property();
+ ya.toBinding = newBinding;
+ ya.fromValue = ya.property.read();
+ ya.deletableToBinding = true;
+ actions << ya;
+ }
+ }
+
+ if (d->scaleString.isValid()) {
+ bool ok = false;
+ QString script = d->scaleString.value.script();
+ qreal scale = script.toFloat(&ok);
+ if (ok) {
+ QDeclarativeAction sa(d->target, QLatin1String("scale"), scale);
+ actions << sa;
+ } else {
+ QDeclarativeBinding *newBinding = new QDeclarativeBinding(script, d->target, qmlContext(this));
+ newBinding->setTarget(QDeclarativeProperty(d->target, QLatin1String("scale")));
+ QDeclarativeAction sa;
+ sa.property = newBinding->property();
+ sa.toBinding = newBinding;
+ sa.fromValue = sa.property.read();
+ sa.deletableToBinding = true;
+ actions << sa;
+ }
+ }
+
+ if (d->rotationString.isValid()) {
+ bool ok = false;
+ QString script = d->rotationString.value.script();
+ qreal rotation = script.toFloat(&ok);
+ if (ok) {
+ QDeclarativeAction ra(d->target, QLatin1String("rotation"), rotation);
+ actions << ra;
+ } else {
+ QDeclarativeBinding *newBinding = new QDeclarativeBinding(script, d->target, qmlContext(this));
+ newBinding->setTarget(QDeclarativeProperty(d->target, QLatin1String("rotation")));
+ QDeclarativeAction ra;
+ ra.property = newBinding->property();
+ ra.toBinding = newBinding;
+ ra.fromValue = ra.property.read();
+ ra.deletableToBinding = true;
+ actions << ra;
+ }
+ }
+
+ if (d->widthString.isValid()) {
+ bool ok = false;
+ QString script = d->widthString.value.script();
+ qreal width = script.toFloat(&ok);
+ if (ok) {
+ QDeclarativeAction wa(d->target, QLatin1String("width"), width);
+ actions << wa;
+ } else {
+ QDeclarativeBinding *newBinding = new QDeclarativeBinding(script, d->target, qmlContext(this));
+ newBinding->setTarget(QDeclarativeProperty(d->target, QLatin1String("width")));
+ QDeclarativeAction wa;
+ wa.property = newBinding->property();
+ wa.toBinding = newBinding;
+ wa.fromValue = wa.property.read();
+ wa.deletableToBinding = true;
+ actions << wa;
+ }
+ }
+
+ if (d->heightString.isValid()) {
+ bool ok = false;
+ QString script = d->heightString.value.script();
+ qreal height = script.toFloat(&ok);
+ if (ok) {
+ QDeclarativeAction ha(d->target, QLatin1String("height"), height);
+ actions << ha;
+ } else {
+ QDeclarativeBinding *newBinding = new QDeclarativeBinding(script, d->target, qmlContext(this));
+ newBinding->setTarget(QDeclarativeProperty(d->target, QLatin1String("height")));
+ QDeclarativeAction ha;
+ ha.property = newBinding->property();
+ ha.toBinding = newBinding;
+ ha.fromValue = ha.property.read();
+ ha.deletableToBinding = true;
+ actions << ha;
+ }
+ }
+
+ return actions;
+}
+
+void QSGParentChange::saveOriginals()
+{
+ Q_D(QSGParentChange);
+ saveCurrentValues();
+ d->origParent = d->rewindParent;
+ d->origStackBefore = d->rewindStackBefore;
+}
+
+/*void QSGParentChange::copyOriginals(QDeclarativeActionEvent *other)
+{
+ Q_D(QSGParentChange);
+ QSGParentChange *pc = static_cast<QSGParentChange*>(other);
+
+ d->origParent = pc->d_func()->rewindParent;
+ d->origStackBefore = pc->d_func()->rewindStackBefore;
+
+ saveCurrentValues();
+}*/
+
+void QSGParentChange::execute(Reason)
+{
+ Q_D(QSGParentChange);
+ d->doChange(d->parent);
+}
+
+bool QSGParentChange::isReversable()
+{
+ return true;
+}
+
+void QSGParentChange::reverse(Reason)
+{
+ Q_D(QSGParentChange);
+ d->doChange(d->origParent, d->origStackBefore);
+}
+
+QString QSGParentChange::typeName() const
+{
+ return QLatin1String("ParentChange");
+}
+
+bool QSGParentChange::override(QDeclarativeActionEvent*other)
+{
+ Q_D(QSGParentChange);
+ if (other->typeName() != QLatin1String("ParentChange"))
+ return false;
+ if (QSGParentChange *otherPC = static_cast<QSGParentChange*>(other))
+ return (d->target == otherPC->object());
+ return false;
+}
+
+void QSGParentChange::saveCurrentValues()
+{
+ Q_D(QSGParentChange);
+ if (!d->target) {
+ d->rewindParent = 0;
+ d->rewindStackBefore = 0;
+ return;
+ }
+
+ d->rewindParent = d->target->parentItem();
+ d->rewindStackBefore = 0;
+
+ if (!d->rewindParent)
+ return;
+
+ QList<QSGItem *> children = d->rewindParent->childItems();
+ for (int ii = 0; ii < children.count() - 1; ++ii) {
+ if (children.at(ii) == d->target) {
+ d->rewindStackBefore = children.at(ii + 1);
+ break;
+ }
+ }
+}
+
+void QSGParentChange::rewind()
+{
+ Q_D(QSGParentChange);
+ d->doChange(d->rewindParent, d->rewindStackBefore);
+}
+
+class QSGAnchorSetPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QSGAnchorSet)
+public:
+ QSGAnchorSetPrivate()
+ : usedAnchors(0), resetAnchors(0), fill(0),
+ centerIn(0)/*, leftMargin(0), rightMargin(0), topMargin(0), bottomMargin(0),
+ margins(0), vCenterOffset(0), hCenterOffset(0), baselineOffset(0)*/
+ {
+ }
+
+ QSGAnchors::Anchors usedAnchors;
+ QSGAnchors::Anchors resetAnchors;
+
+ QSGItem *fill;
+ QSGItem *centerIn;
+
+ QDeclarativeScriptString leftScript;
+ QDeclarativeScriptString rightScript;
+ QDeclarativeScriptString topScript;
+ QDeclarativeScriptString bottomScript;
+ QDeclarativeScriptString hCenterScript;
+ QDeclarativeScriptString vCenterScript;
+ QDeclarativeScriptString baselineScript;
+
+ /*qreal leftMargin;
+ qreal rightMargin;
+ qreal topMargin;
+ qreal bottomMargin;
+ qreal margins;
+ qreal vCenterOffset;
+ qreal hCenterOffset;
+ qreal baselineOffset;*/
+};
+
+QSGAnchorSet::QSGAnchorSet(QObject *parent)
+ : QObject(*new QSGAnchorSetPrivate, parent)
+{
+}
+
+QSGAnchorSet::~QSGAnchorSet()
+{
+}
+
+QDeclarativeScriptString QSGAnchorSet::top() const
+{
+ Q_D(const QSGAnchorSet);
+ return d->topScript;
+}
+
+void QSGAnchorSet::setTop(const QDeclarativeScriptString &edge)
+{
+ Q_D(QSGAnchorSet);
+ d->usedAnchors |= QSGAnchors::TopAnchor;
+ d->topScript = edge;
+ if (edge.script() == QLatin1String("undefined"))
+ resetTop();
+}
+
+void QSGAnchorSet::resetTop()
+{
+ Q_D(QSGAnchorSet);
+ d->usedAnchors &= ~QSGAnchors::TopAnchor;
+ d->topScript = QDeclarativeScriptString();
+ d->resetAnchors |= QSGAnchors::TopAnchor;
+}
+
+QDeclarativeScriptString QSGAnchorSet::bottom() const
+{
+ Q_D(const QSGAnchorSet);
+ return d->bottomScript;
+}
+
+void QSGAnchorSet::setBottom(const QDeclarativeScriptString &edge)
+{
+ Q_D(QSGAnchorSet);
+ d->usedAnchors |= QSGAnchors::BottomAnchor;
+ d->bottomScript = edge;
+ if (edge.script() == QLatin1String("undefined"))
+ resetBottom();
+}
+
+void QSGAnchorSet::resetBottom()
+{
+ Q_D(QSGAnchorSet);
+ d->usedAnchors &= ~QSGAnchors::BottomAnchor;
+ d->bottomScript = QDeclarativeScriptString();
+ d->resetAnchors |= QSGAnchors::BottomAnchor;
+}
+
+QDeclarativeScriptString QSGAnchorSet::verticalCenter() const
+{
+ Q_D(const QSGAnchorSet);
+ return d->vCenterScript;
+}
+
+void QSGAnchorSet::setVerticalCenter(const QDeclarativeScriptString &edge)
+{
+ Q_D(QSGAnchorSet);
+ d->usedAnchors |= QSGAnchors::VCenterAnchor;
+ d->vCenterScript = edge;
+ if (edge.script() == QLatin1String("undefined"))
+ resetVerticalCenter();
+}
+
+void QSGAnchorSet::resetVerticalCenter()
+{
+ Q_D(QSGAnchorSet);
+ d->usedAnchors &= ~QSGAnchors::VCenterAnchor;
+ d->vCenterScript = QDeclarativeScriptString();
+ d->resetAnchors |= QSGAnchors::VCenterAnchor;
+}
+
+QDeclarativeScriptString QSGAnchorSet::baseline() const
+{
+ Q_D(const QSGAnchorSet);
+ return d->baselineScript;
+}
+
+void QSGAnchorSet::setBaseline(const QDeclarativeScriptString &edge)
+{
+ Q_D(QSGAnchorSet);
+ d->usedAnchors |= QSGAnchors::BaselineAnchor;
+ d->baselineScript = edge;
+ if (edge.script() == QLatin1String("undefined"))
+ resetBaseline();
+}
+
+void QSGAnchorSet::resetBaseline()
+{
+ Q_D(QSGAnchorSet);
+ d->usedAnchors &= ~QSGAnchors::BaselineAnchor;
+ d->baselineScript = QDeclarativeScriptString();
+ d->resetAnchors |= QSGAnchors::BaselineAnchor;
+}
+
+QDeclarativeScriptString QSGAnchorSet::left() const
+{
+ Q_D(const QSGAnchorSet);
+ return d->leftScript;
+}
+
+void QSGAnchorSet::setLeft(const QDeclarativeScriptString &edge)
+{
+ Q_D(QSGAnchorSet);
+ d->usedAnchors |= QSGAnchors::LeftAnchor;
+ d->leftScript = edge;
+ if (edge.script() == QLatin1String("undefined"))
+ resetLeft();
+}
+
+void QSGAnchorSet::resetLeft()
+{
+ Q_D(QSGAnchorSet);
+ d->usedAnchors &= ~QSGAnchors::LeftAnchor;
+ d->leftScript = QDeclarativeScriptString();
+ d->resetAnchors |= QSGAnchors::LeftAnchor;
+}
+
+QDeclarativeScriptString QSGAnchorSet::right() const
+{
+ Q_D(const QSGAnchorSet);
+ return d->rightScript;
+}
+
+void QSGAnchorSet::setRight(const QDeclarativeScriptString &edge)
+{
+ Q_D(QSGAnchorSet);
+ d->usedAnchors |= QSGAnchors::RightAnchor;
+ d->rightScript = edge;
+ if (edge.script() == QLatin1String("undefined"))
+ resetRight();
+}
+
+void QSGAnchorSet::resetRight()
+{
+ Q_D(QSGAnchorSet);
+ d->usedAnchors &= ~QSGAnchors::RightAnchor;
+ d->rightScript = QDeclarativeScriptString();
+ d->resetAnchors |= QSGAnchors::RightAnchor;
+}
+
+QDeclarativeScriptString QSGAnchorSet::horizontalCenter() const
+{
+ Q_D(const QSGAnchorSet);
+ return d->hCenterScript;
+}
+
+void QSGAnchorSet::setHorizontalCenter(const QDeclarativeScriptString &edge)
+{
+ Q_D(QSGAnchorSet);
+ d->usedAnchors |= QSGAnchors::HCenterAnchor;
+ d->hCenterScript = edge;
+ if (edge.script() == QLatin1String("undefined"))
+ resetHorizontalCenter();
+}
+
+void QSGAnchorSet::resetHorizontalCenter()
+{
+ Q_D(QSGAnchorSet);
+ d->usedAnchors &= ~QSGAnchors::HCenterAnchor;
+ d->hCenterScript = QDeclarativeScriptString();
+ d->resetAnchors |= QSGAnchors::HCenterAnchor;
+}
+
+QSGItem *QSGAnchorSet::fill() const
+{
+ Q_D(const QSGAnchorSet);
+ return d->fill;
+}
+
+void QSGAnchorSet::setFill(QSGItem *f)
+{
+ Q_D(QSGAnchorSet);
+ d->fill = f;
+}
+
+void QSGAnchorSet::resetFill()
+{
+ setFill(0);
+}
+
+QSGItem *QSGAnchorSet::centerIn() const
+{
+ Q_D(const QSGAnchorSet);
+ return d->centerIn;
+}
+
+void QSGAnchorSet::setCenterIn(QSGItem* c)
+{
+ Q_D(QSGAnchorSet);
+ d->centerIn = c;
+}
+
+void QSGAnchorSet::resetCenterIn()
+{
+ setCenterIn(0);
+}
+
+
+class QSGAnchorChangesPrivate : public QDeclarativeStateOperationPrivate
+{
+public:
+ QSGAnchorChangesPrivate()
+ : target(0), anchorSet(new QSGAnchorSet),
+ leftBinding(0), rightBinding(0), hCenterBinding(0),
+ topBinding(0), bottomBinding(0), vCenterBinding(0), baselineBinding(0),
+ origLeftBinding(0), origRightBinding(0), origHCenterBinding(0),
+ origTopBinding(0), origBottomBinding(0), origVCenterBinding(0),
+ origBaselineBinding(0)
+ {
+
+ }
+ ~QSGAnchorChangesPrivate() { delete anchorSet; }
+
+ QSGItem *target;
+ QSGAnchorSet *anchorSet;
+
+ QDeclarativeBinding *leftBinding;
+ QDeclarativeBinding *rightBinding;
+ QDeclarativeBinding *hCenterBinding;
+ QDeclarativeBinding *topBinding;
+ QDeclarativeBinding *bottomBinding;
+ QDeclarativeBinding *vCenterBinding;
+ QDeclarativeBinding *baselineBinding;
+
+ QDeclarativeAbstractBinding *origLeftBinding;
+ QDeclarativeAbstractBinding *origRightBinding;
+ QDeclarativeAbstractBinding *origHCenterBinding;
+ QDeclarativeAbstractBinding *origTopBinding;
+ QDeclarativeAbstractBinding *origBottomBinding;
+ QDeclarativeAbstractBinding *origVCenterBinding;
+ QDeclarativeAbstractBinding *origBaselineBinding;
+
+ QSGAnchorLine rewindLeft;
+ QSGAnchorLine rewindRight;
+ QSGAnchorLine rewindHCenter;
+ QSGAnchorLine rewindTop;
+ QSGAnchorLine rewindBottom;
+ QSGAnchorLine rewindVCenter;
+ QSGAnchorLine rewindBaseline;
+
+ qreal fromX;
+ qreal fromY;
+ qreal fromWidth;
+ qreal fromHeight;
+
+ qreal toX;
+ qreal toY;
+ qreal toWidth;
+ qreal toHeight;
+
+ qreal rewindX;
+ qreal rewindY;
+ qreal rewindWidth;
+ qreal rewindHeight;
+
+ bool applyOrigLeft;
+ bool applyOrigRight;
+ bool applyOrigHCenter;
+ bool applyOrigTop;
+ bool applyOrigBottom;
+ bool applyOrigVCenter;
+ bool applyOrigBaseline;
+
+ QDeclarativeNullableValue<qreal> origWidth;
+ QDeclarativeNullableValue<qreal> origHeight;
+ qreal origX;
+ qreal origY;
+
+ QList<QDeclarativeAbstractBinding*> oldBindings;
+
+ QDeclarativeProperty leftProp;
+ QDeclarativeProperty rightProp;
+ QDeclarativeProperty hCenterProp;
+ QDeclarativeProperty topProp;
+ QDeclarativeProperty bottomProp;
+ QDeclarativeProperty vCenterProp;
+ QDeclarativeProperty baselineProp;
+};
+
+QSGAnchorChanges::QSGAnchorChanges(QObject *parent)
+ : QDeclarativeStateOperation(*(new QSGAnchorChangesPrivate), parent)
+{
+}
+
+QSGAnchorChanges::~QSGAnchorChanges()
+{
+}
+
+QSGAnchorChanges::ActionList QSGAnchorChanges::actions()
+{
+ Q_D(QSGAnchorChanges);
+ d->leftBinding = d->rightBinding = d->hCenterBinding = d->topBinding
+ = d->bottomBinding = d->vCenterBinding = d->baselineBinding = 0;
+
+ d->leftProp = QDeclarativeProperty(d->target, QLatin1String("anchors.left"));
+ d->rightProp = QDeclarativeProperty(d->target, QLatin1String("anchors.right"));
+ d->hCenterProp = QDeclarativeProperty(d->target, QLatin1String("anchors.horizontalCenter"));
+ d->topProp = QDeclarativeProperty(d->target, QLatin1String("anchors.top"));
+ d->bottomProp = QDeclarativeProperty(d->target, QLatin1String("anchors.bottom"));
+ d->vCenterProp = QDeclarativeProperty(d->target, QLatin1String("anchors.verticalCenter"));
+ d->baselineProp = QDeclarativeProperty(d->target, QLatin1String("anchors.baseline"));
+
+ if (d->anchorSet->d_func()->usedAnchors & QSGAnchors::LeftAnchor) {
+ d->leftBinding = new QDeclarativeBinding(d->anchorSet->d_func()->leftScript.script(), d->target, qmlContext(this));
+ d->leftBinding->setTarget(d->leftProp);
+ }
+ if (d->anchorSet->d_func()->usedAnchors & QSGAnchors::RightAnchor) {
+ d->rightBinding = new QDeclarativeBinding(d->anchorSet->d_func()->rightScript.script(), d->target, qmlContext(this));
+ d->rightBinding->setTarget(d->rightProp);
+ }
+ if (d->anchorSet->d_func()->usedAnchors & QSGAnchors::HCenterAnchor) {
+ d->hCenterBinding = new QDeclarativeBinding(d->anchorSet->d_func()->hCenterScript.script(), d->target, qmlContext(this));
+ d->hCenterBinding->setTarget(d->hCenterProp);
+ }
+ if (d->anchorSet->d_func()->usedAnchors & QSGAnchors::TopAnchor) {
+ d->topBinding = new QDeclarativeBinding(d->anchorSet->d_func()->topScript.script(), d->target, qmlContext(this));
+ d->topBinding->setTarget(d->topProp);
+ }
+ if (d->anchorSet->d_func()->usedAnchors & QSGAnchors::BottomAnchor) {
+ d->bottomBinding = new QDeclarativeBinding(d->anchorSet->d_func()->bottomScript.script(), d->target, qmlContext(this));
+ d->bottomBinding->setTarget(d->bottomProp);
+ }
+ if (d->anchorSet->d_func()->usedAnchors & QSGAnchors::VCenterAnchor) {
+ d->vCenterBinding = new QDeclarativeBinding(d->anchorSet->d_func()->vCenterScript.script(), d->target, qmlContext(this));
+ d->vCenterBinding->setTarget(d->vCenterProp);
+ }
+ if (d->anchorSet->d_func()->usedAnchors & QSGAnchors::BaselineAnchor) {
+ d->baselineBinding = new QDeclarativeBinding(d->anchorSet->d_func()->baselineScript.script(), d->target, qmlContext(this));
+ d->baselineBinding->setTarget(d->baselineProp);
+ }
+
+ QDeclarativeAction a;
+ a.event = this;
+ return ActionList() << a;
+}
+
+QSGAnchorSet *QSGAnchorChanges::anchors()
+{
+ Q_D(QSGAnchorChanges);
+ return d->anchorSet;
+}
+
+QSGItem *QSGAnchorChanges::object() const
+{
+ Q_D(const QSGAnchorChanges);
+ return d->target;
+}
+
+void QSGAnchorChanges::setObject(QSGItem *target)
+{
+ Q_D(QSGAnchorChanges);
+ d->target = target;
+}
+
+void QSGAnchorChanges::execute(Reason reason)
+{
+ Q_D(QSGAnchorChanges);
+ if (!d->target)
+ return;
+
+ QSGItemPrivate *targetPrivate = QSGItemPrivate::get(d->target);
+ //incorporate any needed "reverts"
+ if (d->applyOrigLeft) {
+ if (!d->origLeftBinding)
+ targetPrivate->anchors()->resetLeft();
+ QDeclarativePropertyPrivate::setBinding(d->leftProp, d->origLeftBinding);
+ }
+ if (d->applyOrigRight) {
+ if (!d->origRightBinding)
+ targetPrivate->anchors()->resetRight();
+ QDeclarativePropertyPrivate::setBinding(d->rightProp, d->origRightBinding);
+ }
+ if (d->applyOrigHCenter) {
+ if (!d->origHCenterBinding)
+ targetPrivate->anchors()->resetHorizontalCenter();
+ QDeclarativePropertyPrivate::setBinding(d->hCenterProp, d->origHCenterBinding);
+ }
+ if (d->applyOrigTop) {
+ if (!d->origTopBinding)
+ targetPrivate->anchors()->resetTop();
+ QDeclarativePropertyPrivate::setBinding(d->topProp, d->origTopBinding);
+ }
+ if (d->applyOrigBottom) {
+ if (!d->origBottomBinding)
+ targetPrivate->anchors()->resetBottom();
+ QDeclarativePropertyPrivate::setBinding(d->bottomProp, d->origBottomBinding);
+ }
+ if (d->applyOrigVCenter) {
+ if (!d->origVCenterBinding)
+ targetPrivate->anchors()->resetVerticalCenter();
+ QDeclarativePropertyPrivate::setBinding(d->vCenterProp, d->origVCenterBinding);
+ }
+ if (d->applyOrigBaseline) {
+ if (!d->origBaselineBinding)
+ targetPrivate->anchors()->resetBaseline();
+ QDeclarativePropertyPrivate::setBinding(d->baselineProp, d->origBaselineBinding);
+ }
+
+ //destroy old bindings
+ if (reason == ActualChange) {
+ for (int i = 0; i < d->oldBindings.size(); ++i) {
+ QDeclarativeAbstractBinding *binding = d->oldBindings.at(i);
+ if (binding)
+ binding->destroy();
+ }
+ d->oldBindings.clear();
+ }
+
+ //reset any anchors that have been specified as "undefined"
+ if (d->anchorSet->d_func()->resetAnchors & QSGAnchors::LeftAnchor) {
+ targetPrivate->anchors()->resetLeft();
+ QDeclarativePropertyPrivate::setBinding(d->leftProp, 0);
+ }
+ if (d->anchorSet->d_func()->resetAnchors & QSGAnchors::RightAnchor) {
+ targetPrivate->anchors()->resetRight();
+ QDeclarativePropertyPrivate::setBinding(d->rightProp, 0);
+ }
+ if (d->anchorSet->d_func()->resetAnchors & QSGAnchors::HCenterAnchor) {
+ targetPrivate->anchors()->resetHorizontalCenter();
+ QDeclarativePropertyPrivate::setBinding(d->hCenterProp, 0);
+ }
+ if (d->anchorSet->d_func()->resetAnchors & QSGAnchors::TopAnchor) {
+ targetPrivate->anchors()->resetTop();
+ QDeclarativePropertyPrivate::setBinding(d->topProp, 0);
+ }
+ if (d->anchorSet->d_func()->resetAnchors & QSGAnchors::BottomAnchor) {
+ targetPrivate->anchors()->resetBottom();
+ QDeclarativePropertyPrivate::setBinding(d->bottomProp, 0);
+ }
+ if (d->anchorSet->d_func()->resetAnchors & QSGAnchors::VCenterAnchor) {
+ targetPrivate->anchors()->resetVerticalCenter();
+ QDeclarativePropertyPrivate::setBinding(d->vCenterProp, 0);
+ }
+ if (d->anchorSet->d_func()->resetAnchors & QSGAnchors::BaselineAnchor) {
+ targetPrivate->anchors()->resetBaseline();
+ QDeclarativePropertyPrivate::setBinding(d->baselineProp, 0);
+ }
+
+ //set any anchors that have been specified
+ if (d->leftBinding)
+ QDeclarativePropertyPrivate::setBinding(d->leftBinding->property(), d->leftBinding);
+ if (d->rightBinding)
+ QDeclarativePropertyPrivate::setBinding(d->rightBinding->property(), d->rightBinding);
+ if (d->hCenterBinding)
+ QDeclarativePropertyPrivate::setBinding(d->hCenterBinding->property(), d->hCenterBinding);
+ if (d->topBinding)
+ QDeclarativePropertyPrivate::setBinding(d->topBinding->property(), d->topBinding);
+ if (d->bottomBinding)
+ QDeclarativePropertyPrivate::setBinding(d->bottomBinding->property(), d->bottomBinding);
+ if (d->vCenterBinding)
+ QDeclarativePropertyPrivate::setBinding(d->vCenterBinding->property(), d->vCenterBinding);
+ if (d->baselineBinding)
+ QDeclarativePropertyPrivate::setBinding(d->baselineBinding->property(), d->baselineBinding);
+}
+
+bool QSGAnchorChanges::isReversable()
+{
+ return true;
+}
+
+void QSGAnchorChanges::reverse(Reason reason)
+{
+ Q_D(QSGAnchorChanges);
+ if (!d->target)
+ return;
+
+ QSGItemPrivate *targetPrivate = QSGItemPrivate::get(d->target);
+ //reset any anchors set by the state
+ if (d->leftBinding) {
+ targetPrivate->anchors()->resetLeft();
+ QDeclarativePropertyPrivate::setBinding(d->leftBinding->property(), 0);
+ if (reason == ActualChange) {
+ d->leftBinding->destroy(); d->leftBinding = 0;
+ }
+ }
+ if (d->rightBinding) {
+ targetPrivate->anchors()->resetRight();
+ QDeclarativePropertyPrivate::setBinding(d->rightBinding->property(), 0);
+ if (reason == ActualChange) {
+ d->rightBinding->destroy(); d->rightBinding = 0;
+ }
+ }
+ if (d->hCenterBinding) {
+ targetPrivate->anchors()->resetHorizontalCenter();
+ QDeclarativePropertyPrivate::setBinding(d->hCenterBinding->property(), 0);
+ if (reason == ActualChange) {
+ d->hCenterBinding->destroy(); d->hCenterBinding = 0;
+ }
+ }
+ if (d->topBinding) {
+ targetPrivate->anchors()->resetTop();
+ QDeclarativePropertyPrivate::setBinding(d->topBinding->property(), 0);
+ if (reason == ActualChange) {
+ d->topBinding->destroy(); d->topBinding = 0;
+ }
+ }
+ if (d->bottomBinding) {
+ targetPrivate->anchors()->resetBottom();
+ QDeclarativePropertyPrivate::setBinding(d->bottomBinding->property(), 0);
+ if (reason == ActualChange) {
+ d->bottomBinding->destroy(); d->bottomBinding = 0;
+ }
+ }
+ if (d->vCenterBinding) {
+ targetPrivate->anchors()->resetVerticalCenter();
+ QDeclarativePropertyPrivate::setBinding(d->vCenterBinding->property(), 0);
+ if (reason == ActualChange) {
+ d->vCenterBinding->destroy(); d->vCenterBinding = 0;
+ }
+ }
+ if (d->baselineBinding) {
+ targetPrivate->anchors()->resetBaseline();
+ QDeclarativePropertyPrivate::setBinding(d->baselineBinding->property(), 0);
+ if (reason == ActualChange) {
+ d->baselineBinding->destroy(); d->baselineBinding = 0;
+ }
+ }
+
+ //restore previous anchors
+ if (d->origLeftBinding)
+ QDeclarativePropertyPrivate::setBinding(d->leftProp, d->origLeftBinding);
+ if (d->origRightBinding)
+ QDeclarativePropertyPrivate::setBinding(d->rightProp, d->origRightBinding);
+ if (d->origHCenterBinding)
+ QDeclarativePropertyPrivate::setBinding(d->hCenterProp, d->origHCenterBinding);
+ if (d->origTopBinding)
+ QDeclarativePropertyPrivate::setBinding(d->topProp, d->origTopBinding);
+ if (d->origBottomBinding)
+ QDeclarativePropertyPrivate::setBinding(d->bottomProp, d->origBottomBinding);
+ if (d->origVCenterBinding)
+ QDeclarativePropertyPrivate::setBinding(d->vCenterProp, d->origVCenterBinding);
+ if (d->origBaselineBinding)
+ QDeclarativePropertyPrivate::setBinding(d->baselineProp, d->origBaselineBinding);
+
+ //restore any absolute geometry changed by the state's anchors
+ QSGAnchors::Anchors stateVAnchors = d->anchorSet->d_func()->usedAnchors & QSGAnchors::Vertical_Mask;
+ QSGAnchors::Anchors origVAnchors = targetPrivate->anchors()->usedAnchors() & QSGAnchors::Vertical_Mask;
+ QSGAnchors::Anchors stateHAnchors = d->anchorSet->d_func()->usedAnchors & QSGAnchors::Horizontal_Mask;
+ QSGAnchors::Anchors origHAnchors = targetPrivate->anchors()->usedAnchors() & QSGAnchors::Horizontal_Mask;
+
+ bool stateSetWidth = (stateHAnchors &&
+ stateHAnchors != QSGAnchors::LeftAnchor &&
+ stateHAnchors != QSGAnchors::RightAnchor &&
+ stateHAnchors != QSGAnchors::HCenterAnchor);
+ bool origSetWidth = (origHAnchors &&
+ origHAnchors != QSGAnchors::LeftAnchor &&
+ origHAnchors != QSGAnchors::RightAnchor &&
+ origHAnchors != QSGAnchors::HCenterAnchor);
+ if (d->origWidth.isValid() && stateSetWidth && !origSetWidth)
+ d->target->setWidth(d->origWidth.value);
+
+ bool stateSetHeight = (stateVAnchors &&
+ stateVAnchors != QSGAnchors::TopAnchor &&
+ stateVAnchors != QSGAnchors::BottomAnchor &&
+ stateVAnchors != QSGAnchors::VCenterAnchor &&
+ stateVAnchors != QSGAnchors::BaselineAnchor);
+ bool origSetHeight = (origVAnchors &&
+ origVAnchors != QSGAnchors::TopAnchor &&
+ origVAnchors != QSGAnchors::BottomAnchor &&
+ origVAnchors != QSGAnchors::VCenterAnchor &&
+ origVAnchors != QSGAnchors::BaselineAnchor);
+ if (d->origHeight.isValid() && stateSetHeight && !origSetHeight)
+ d->target->setHeight(d->origHeight.value);
+
+ if (stateHAnchors && !origHAnchors)
+ d->target->setX(d->origX);
+
+ if (stateVAnchors && !origVAnchors)
+ d->target->setY(d->origY);
+}
+
+QString QSGAnchorChanges::typeName() const
+{
+ return QLatin1String("AnchorChanges");
+}
+
+QList<QDeclarativeAction> QSGAnchorChanges::additionalActions()
+{
+ Q_D(QSGAnchorChanges);
+ QList<QDeclarativeAction> extra;
+
+ QSGAnchors::Anchors combined = d->anchorSet->d_func()->usedAnchors | d->anchorSet->d_func()->resetAnchors;
+ bool hChange = combined & QSGAnchors::Horizontal_Mask;
+ bool vChange = combined & QSGAnchors::Vertical_Mask;
+
+ if (d->target) {
+ QDeclarativeAction a;
+ if (hChange && d->fromX != d->toX) {
+ a.property = QDeclarativeProperty(d->target, QLatin1String("x"));
+ a.toValue = d->toX;
+ extra << a;
+ }
+ if (vChange && d->fromY != d->toY) {
+ a.property = QDeclarativeProperty(d->target, QLatin1String("y"));
+ a.toValue = d->toY;
+ extra << a;
+ }
+ if (hChange && d->fromWidth != d->toWidth) {
+ a.property = QDeclarativeProperty(d->target, QLatin1String("width"));
+ a.toValue = d->toWidth;
+ extra << a;
+ }
+ if (vChange && d->fromHeight != d->toHeight) {
+ a.property = QDeclarativeProperty(d->target, QLatin1String("height"));
+ a.toValue = d->toHeight;
+ extra << a;
+ }
+ }
+
+ return extra;
+}
+
+bool QSGAnchorChanges::changesBindings()
+{
+ return true;
+}
+
+void QSGAnchorChanges::saveOriginals()
+{
+ Q_D(QSGAnchorChanges);
+ if (!d->target)
+ return;
+
+ d->origLeftBinding = QDeclarativePropertyPrivate::binding(d->leftProp);
+ d->origRightBinding = QDeclarativePropertyPrivate::binding(d->rightProp);
+ d->origHCenterBinding = QDeclarativePropertyPrivate::binding(d->hCenterProp);
+ d->origTopBinding = QDeclarativePropertyPrivate::binding(d->topProp);
+ d->origBottomBinding = QDeclarativePropertyPrivate::binding(d->bottomProp);
+ d->origVCenterBinding = QDeclarativePropertyPrivate::binding(d->vCenterProp);
+ d->origBaselineBinding = QDeclarativePropertyPrivate::binding(d->baselineProp);
+
+ QSGItemPrivate *targetPrivate = QSGItemPrivate::get(d->target);
+ if (targetPrivate->widthValid)
+ d->origWidth = d->target->width();
+ if (targetPrivate->heightValid)
+ d->origHeight = d->target->height();
+ d->origX = d->target->x();
+ d->origY = d->target->y();
+
+ d->applyOrigLeft = d->applyOrigRight = d->applyOrigHCenter = d->applyOrigTop
+ = d->applyOrigBottom = d->applyOrigVCenter = d->applyOrigBaseline = false;
+
+ saveCurrentValues();
+}
+
+void QSGAnchorChanges::copyOriginals(QDeclarativeActionEvent *other)
+{
+ Q_D(QSGAnchorChanges);
+ QSGAnchorChanges *ac = static_cast<QSGAnchorChanges*>(other);
+ QSGAnchorChangesPrivate *acp = ac->d_func();
+
+ QSGAnchors::Anchors combined = acp->anchorSet->d_func()->usedAnchors |
+ acp->anchorSet->d_func()->resetAnchors;
+
+ //probably also need to revert some things
+ d->applyOrigLeft = (combined & QSGAnchors::LeftAnchor);
+ d->applyOrigRight = (combined & QSGAnchors::RightAnchor);
+ d->applyOrigHCenter = (combined & QSGAnchors::HCenterAnchor);
+ d->applyOrigTop = (combined & QSGAnchors::TopAnchor);
+ d->applyOrigBottom = (combined & QSGAnchors::BottomAnchor);
+ d->applyOrigVCenter = (combined & QSGAnchors::VCenterAnchor);
+ d->applyOrigBaseline = (combined & QSGAnchors::BaselineAnchor);
+
+ d->origLeftBinding = acp->origLeftBinding;
+ d->origRightBinding = acp->origRightBinding;
+ d->origHCenterBinding = acp->origHCenterBinding;
+ d->origTopBinding = acp->origTopBinding;
+ d->origBottomBinding = acp->origBottomBinding;
+ d->origVCenterBinding = acp->origVCenterBinding;
+ d->origBaselineBinding = acp->origBaselineBinding;
+
+ d->origWidth = acp->origWidth;
+ d->origHeight = acp->origHeight;
+ d->origX = acp->origX;
+ d->origY = acp->origY;
+
+ d->oldBindings.clear();
+ d->oldBindings << acp->leftBinding << acp->rightBinding << acp->hCenterBinding
+ << acp->topBinding << acp->bottomBinding << acp->baselineBinding;
+
+ saveCurrentValues();
+}
+
+void QSGAnchorChanges::clearBindings()
+{
+ Q_D(QSGAnchorChanges);
+ if (!d->target)
+ return;
+
+ //### should this (saving "from" values) be moved to saveCurrentValues()?
+ d->fromX = d->target->x();
+ d->fromY = d->target->y();
+ d->fromWidth = d->target->width();
+ d->fromHeight = d->target->height();
+
+ QSGItemPrivate *targetPrivate = QSGItemPrivate::get(d->target);
+ //reset any anchors with corresponding reverts
+ //reset any anchors that have been specified as "undefined"
+ //reset any anchors that we'll be setting in the state
+ QSGAnchors::Anchors combined = d->anchorSet->d_func()->resetAnchors |
+ d->anchorSet->d_func()->usedAnchors;
+ if (d->applyOrigLeft || (combined & QSGAnchors::LeftAnchor)) {
+ targetPrivate->anchors()->resetLeft();
+ QDeclarativePropertyPrivate::setBinding(d->leftProp, 0);
+ }
+ if (d->applyOrigRight || (combined & QSGAnchors::RightAnchor)) {
+ targetPrivate->anchors()->resetRight();
+ QDeclarativePropertyPrivate::setBinding(d->rightProp, 0);
+ }
+ if (d->applyOrigHCenter || (combined & QSGAnchors::HCenterAnchor)) {
+ targetPrivate->anchors()->resetHorizontalCenter();
+ QDeclarativePropertyPrivate::setBinding(d->hCenterProp, 0);
+ }
+ if (d->applyOrigTop || (combined & QSGAnchors::TopAnchor)) {
+ targetPrivate->anchors()->resetTop();
+ QDeclarativePropertyPrivate::setBinding(d->topProp, 0);
+ }
+ if (d->applyOrigBottom || (combined & QSGAnchors::BottomAnchor)) {
+ targetPrivate->anchors()->resetBottom();
+ QDeclarativePropertyPrivate::setBinding(d->bottomProp, 0);
+ }
+ if (d->applyOrigVCenter || (combined & QSGAnchors::VCenterAnchor)) {
+ targetPrivate->anchors()->resetVerticalCenter();
+ QDeclarativePropertyPrivate::setBinding(d->vCenterProp, 0);
+ }
+ if (d->applyOrigBaseline || (combined & QSGAnchors::BaselineAnchor)) {
+ targetPrivate->anchors()->resetBaseline();
+ QDeclarativePropertyPrivate::setBinding(d->baselineProp, 0);
+ }
+}
+
+bool QSGAnchorChanges::override(QDeclarativeActionEvent*other)
+{
+ if (other->typeName() != QLatin1String("AnchorChanges"))
+ return false;
+ if (static_cast<QDeclarativeActionEvent*>(this) == other)
+ return true;
+ if (static_cast<QSGAnchorChanges*>(other)->object() == object())
+ return true;
+ return false;
+}
+
+void QSGAnchorChanges::rewind()
+{
+ Q_D(QSGAnchorChanges);
+ if (!d->target)
+ return;
+
+ QSGItemPrivate *targetPrivate = QSGItemPrivate::get(d->target);
+
+ //restore previous values (but not previous bindings, i.e. anchors)
+ d->target->setX(d->rewindX);
+ d->target->setY(d->rewindY);
+ if (targetPrivate->widthValid) {
+ d->target->setWidth(d->rewindWidth);
+ }
+ if (targetPrivate->heightValid) {
+ d->target->setHeight(d->rewindHeight);
+ }
+}
+
+void QSGAnchorChanges::saveCurrentValues()
+{
+ Q_D(QSGAnchorChanges);
+ if (!d->target)
+ return;
+
+ QSGItemPrivate *targetPrivate = QSGItemPrivate::get(d->target);
+ d->rewindLeft = targetPrivate->anchors()->left();
+ d->rewindRight = targetPrivate->anchors()->right();
+ d->rewindHCenter = targetPrivate->anchors()->horizontalCenter();
+ d->rewindTop = targetPrivate->anchors()->top();
+ d->rewindBottom = targetPrivate->anchors()->bottom();
+ d->rewindVCenter = targetPrivate->anchors()->verticalCenter();
+ d->rewindBaseline = targetPrivate->anchors()->baseline();
+
+ d->rewindX = d->target->x();
+ d->rewindY = d->target->y();
+ d->rewindWidth = d->target->width();
+ d->rewindHeight = d->target->height();
+}
+
+void QSGAnchorChanges::saveTargetValues()
+{
+ Q_D(QSGAnchorChanges);
+ if (!d->target)
+ return;
+
+ d->toX = d->target->x();
+ d->toY = d->target->y();
+ d->toWidth = d->target->width();
+ d->toHeight = d->target->height();
+}
+
+#include <moc_qsgstateoperations_p.cpp>
+
+QT_END_NAMESPACE
+
diff --git a/src/declarative/items/qsgstateoperations_p.h b/src/declarative/items/qsgstateoperations_p.h
new file mode 100644
index 0000000000..f816e36b82
--- /dev/null
+++ b/src/declarative/items/qsgstateoperations_p.h
@@ -0,0 +1,275 @@
+// Commit: 84c47bbb133304d7ef35642fa1fbb17619d4a43d
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGSTATEOPERATIONS_H
+#define QSGSTATEOPERATIONS_H
+
+#include "qsgitem.h"
+#include "qsganchors_p.h"
+
+#include <private/qdeclarativestate_p.h>
+
+#include <QtDeclarative/qdeclarativescriptstring.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QSGParentChangePrivate;
+class Q_AUTOTEST_EXPORT QSGParentChange : public QDeclarativeStateOperation, public QDeclarativeActionEvent
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QSGParentChange)
+
+ Q_PROPERTY(QSGItem *target READ object WRITE setObject)
+ Q_PROPERTY(QSGItem *parent READ parent WRITE setParent)
+ Q_PROPERTY(QDeclarativeScriptString x READ x WRITE setX)
+ Q_PROPERTY(QDeclarativeScriptString y READ y WRITE setY)
+ Q_PROPERTY(QDeclarativeScriptString width READ width WRITE setWidth)
+ Q_PROPERTY(QDeclarativeScriptString height READ height WRITE setHeight)
+ Q_PROPERTY(QDeclarativeScriptString scale READ scale WRITE setScale)
+ Q_PROPERTY(QDeclarativeScriptString rotation READ rotation WRITE setRotation)
+public:
+ QSGParentChange(QObject *parent=0);
+ ~QSGParentChange();
+
+ QSGItem *object() const;
+ void setObject(QSGItem *);
+
+ QSGItem *parent() const;
+ void setParent(QSGItem *);
+
+ QSGItem *originalParent() const;
+
+ QDeclarativeScriptString x() const;
+ void setX(QDeclarativeScriptString x);
+ bool xIsSet() const;
+
+ QDeclarativeScriptString y() const;
+ void setY(QDeclarativeScriptString y);
+ bool yIsSet() const;
+
+ QDeclarativeScriptString width() const;
+ void setWidth(QDeclarativeScriptString width);
+ bool widthIsSet() const;
+
+ QDeclarativeScriptString height() const;
+ void setHeight(QDeclarativeScriptString height);
+ bool heightIsSet() const;
+
+ QDeclarativeScriptString scale() const;
+ void setScale(QDeclarativeScriptString scale);
+ bool scaleIsSet() const;
+
+ QDeclarativeScriptString rotation() const;
+ void setRotation(QDeclarativeScriptString rotation);
+ bool rotationIsSet() const;
+
+ virtual ActionList actions();
+
+ virtual void saveOriginals();
+ //virtual void copyOriginals(QDeclarativeActionEvent*);
+ virtual void execute(Reason reason = ActualChange);
+ virtual bool isReversable();
+ virtual void reverse(Reason reason = ActualChange);
+ virtual QString typeName() const;
+ virtual bool override(QDeclarativeActionEvent*other);
+ virtual void rewind();
+ virtual void saveCurrentValues();
+};
+
+class QSGAnchorChanges;
+class QSGAnchorSetPrivate;
+class Q_AUTOTEST_EXPORT QSGAnchorSet : public QObject
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QDeclarativeScriptString left READ left WRITE setLeft RESET resetLeft)
+ Q_PROPERTY(QDeclarativeScriptString right READ right WRITE setRight RESET resetRight)
+ Q_PROPERTY(QDeclarativeScriptString horizontalCenter READ horizontalCenter WRITE setHorizontalCenter RESET resetHorizontalCenter)
+ Q_PROPERTY(QDeclarativeScriptString top READ top WRITE setTop RESET resetTop)
+ Q_PROPERTY(QDeclarativeScriptString bottom READ bottom WRITE setBottom RESET resetBottom)
+ Q_PROPERTY(QDeclarativeScriptString verticalCenter READ verticalCenter WRITE setVerticalCenter RESET resetVerticalCenter)
+ Q_PROPERTY(QDeclarativeScriptString baseline READ baseline WRITE setBaseline RESET resetBaseline)
+ //Q_PROPERTY(QSGItem *fill READ fill WRITE setFill RESET resetFill)
+ //Q_PROPERTY(QSGItem *centerIn READ centerIn WRITE setCenterIn RESET resetCenterIn)
+
+ /*Q_PROPERTY(qreal margins READ margins WRITE setMargins NOTIFY marginsChanged)
+ Q_PROPERTY(qreal leftMargin READ leftMargin WRITE setLeftMargin NOTIFY leftMarginChanged)
+ Q_PROPERTY(qreal rightMargin READ rightMargin WRITE setRightMargin NOTIFY rightMarginChanged)
+ Q_PROPERTY(qreal horizontalCenterOffset READ horizontalCenterOffset WRITE setHorizontalCenterOffset NOTIFY horizontalCenterOffsetChanged())
+ Q_PROPERTY(qreal topMargin READ topMargin WRITE setTopMargin NOTIFY topMarginChanged)
+ Q_PROPERTY(qreal bottomMargin READ bottomMargin WRITE setBottomMargin NOTIFY bottomMarginChanged)
+ Q_PROPERTY(qreal verticalCenterOffset READ verticalCenterOffset WRITE setVerticalCenterOffset NOTIFY verticalCenterOffsetChanged())
+ Q_PROPERTY(qreal baselineOffset READ baselineOffset WRITE setBaselineOffset NOTIFY baselineOffsetChanged())*/
+
+public:
+ QSGAnchorSet(QObject *parent=0);
+ virtual ~QSGAnchorSet();
+
+ QDeclarativeScriptString left() const;
+ void setLeft(const QDeclarativeScriptString &edge);
+ void resetLeft();
+
+ QDeclarativeScriptString right() const;
+ void setRight(const QDeclarativeScriptString &edge);
+ void resetRight();
+
+ QDeclarativeScriptString horizontalCenter() const;
+ void setHorizontalCenter(const QDeclarativeScriptString &edge);
+ void resetHorizontalCenter();
+
+ QDeclarativeScriptString top() const;
+ void setTop(const QDeclarativeScriptString &edge);
+ void resetTop();
+
+ QDeclarativeScriptString bottom() const;
+ void setBottom(const QDeclarativeScriptString &edge);
+ void resetBottom();
+
+ QDeclarativeScriptString verticalCenter() const;
+ void setVerticalCenter(const QDeclarativeScriptString &edge);
+ void resetVerticalCenter();
+
+ QDeclarativeScriptString baseline() const;
+ void setBaseline(const QDeclarativeScriptString &edge);
+ void resetBaseline();
+
+ QSGItem *fill() const;
+ void setFill(QSGItem *);
+ void resetFill();
+
+ QSGItem *centerIn() const;
+ void setCenterIn(QSGItem *);
+ void resetCenterIn();
+
+ /*qreal leftMargin() const;
+ void setLeftMargin(qreal);
+
+ qreal rightMargin() const;
+ void setRightMargin(qreal);
+
+ qreal horizontalCenterOffset() const;
+ void setHorizontalCenterOffset(qreal);
+
+ qreal topMargin() const;
+ void setTopMargin(qreal);
+
+ qreal bottomMargin() const;
+ void setBottomMargin(qreal);
+
+ qreal margins() const;
+ void setMargins(qreal);
+
+ qreal verticalCenterOffset() const;
+ void setVerticalCenterOffset(qreal);
+
+ qreal baselineOffset() const;
+ void setBaselineOffset(qreal);*/
+
+ QSGAnchors::Anchors usedAnchors() const;
+
+/*Q_SIGNALS:
+ void leftMarginChanged();
+ void rightMarginChanged();
+ void topMarginChanged();
+ void bottomMarginChanged();
+ void marginsChanged();
+ void verticalCenterOffsetChanged();
+ void horizontalCenterOffsetChanged();
+ void baselineOffsetChanged();*/
+
+private:
+ friend class QSGAnchorChanges;
+ Q_DISABLE_COPY(QSGAnchorSet)
+ Q_DECLARE_PRIVATE(QSGAnchorSet)
+};
+
+class QSGAnchorChangesPrivate;
+class Q_AUTOTEST_EXPORT QSGAnchorChanges : public QDeclarativeStateOperation, public QDeclarativeActionEvent
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QSGAnchorChanges)
+
+ Q_PROPERTY(QSGItem *target READ object WRITE setObject)
+ Q_PROPERTY(QSGAnchorSet *anchors READ anchors CONSTANT)
+
+public:
+ QSGAnchorChanges(QObject *parent=0);
+ ~QSGAnchorChanges();
+
+ virtual ActionList actions();
+
+ QSGAnchorSet *anchors();
+
+ QSGItem *object() const;
+ void setObject(QSGItem *);
+
+ virtual void execute(Reason reason = ActualChange);
+ virtual bool isReversable();
+ virtual void reverse(Reason reason = ActualChange);
+ virtual QString typeName() const;
+ virtual bool override(QDeclarativeActionEvent*other);
+ virtual bool changesBindings();
+ virtual void saveOriginals();
+ virtual bool needsCopy() { return true; }
+ virtual void copyOriginals(QDeclarativeActionEvent*);
+ virtual void clearBindings();
+ virtual void rewind();
+ virtual void saveCurrentValues();
+
+ QList<QDeclarativeAction> additionalActions();
+ virtual void saveTargetValues();
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QSGParentChange)
+QML_DECLARE_TYPE(QSGAnchorSet)
+QML_DECLARE_TYPE(QSGAnchorChanges)
+
+QT_END_HEADER
+
+#endif // QSGSTATEOPERATIONS_H
+
diff --git a/src/declarative/items/qsgtext.cpp b/src/declarative/items/qsgtext.cpp
new file mode 100644
index 0000000000..e7e655d591
--- /dev/null
+++ b/src/declarative/items/qsgtext.cpp
@@ -0,0 +1,1255 @@
+// Commit: cce89db1e2555cbca8fc28072e1c6dd737cec6c4
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgtext_p.h"
+#include "qsgtext_p_p.h"
+
+#include <private/qsgdistancefieldglyphcache_p.h>
+#include <private/qsgcontext_p.h>
+#include <private/qsgadaptationlayer_p.h>
+#include "qsgtextnode_p.h"
+#include "qsgimage_p_p.h"
+#include <private/qsgtexture_p.h>
+
+#include <QtDeclarative/qdeclarativeinfo.h>
+#include <QtGui/qgraphicssceneevent.h>
+#include <QtGui/qabstracttextdocumentlayout.h>
+#include <QtGui/qpainter.h>
+#include <QtGui/qtextdocument.h>
+#include <QtGui/qtextobject.h>
+#include <QtGui/qtextcursor.h>
+#include <QtGui/qapplication.h>
+
+#include <private/qdeclarativestyledtext_p.h>
+#include <private/qdeclarativepixmapcache_p.h>
+
+#include <qmath.h>
+#include <limits.h>
+
+QT_BEGIN_NAMESPACE
+
+extern Q_GUI_EXPORT bool qt_applefontsmoothing_enabled;
+
+class QSGTextDocumentWithImageResources : public QTextDocument {
+ Q_OBJECT
+
+public:
+ QSGTextDocumentWithImageResources(QSGText *parent);
+ virtual ~QSGTextDocumentWithImageResources();
+
+ void setText(const QString &);
+ int resourcesLoading() const { return outstanding; }
+
+protected:
+ QVariant loadResource(int type, const QUrl &name);
+
+private slots:
+ void requestFinished();
+
+private:
+ QHash<QUrl, QDeclarativePixmap *> m_resources;
+
+ int outstanding;
+ static QSet<QUrl> errors;
+};
+
+DEFINE_BOOL_CONFIG_OPTION(enableImageCache, QML_ENABLE_TEXT_IMAGE_CACHE);
+
+QString QSGTextPrivate::elideChar = QString(0x2026);
+
+QSGTextPrivate::QSGTextPrivate()
+: color((QRgb)0), style(QSGText::Normal), hAlign(QSGText::AlignLeft),
+ vAlign(QSGText::AlignTop), elideMode(QSGText::ElideNone),
+ format(QSGText::AutoText), wrapMode(QSGText::NoWrap), lineHeight(1),
+ lineHeightMode(QSGText::ProportionalHeight), lineCount(1), maximumLineCount(INT_MAX),
+ maximumLineCountValid(false),
+ texture(0),
+ imageCacheDirty(true), updateOnComponentComplete(true),
+ richText(false), singleline(false), cacheAllTextAsImage(true), internalWidthUpdate(false),
+ requireImplicitWidth(false), truncated(false), hAlignImplicit(true), rightToLeftText(false),
+ layoutTextElided(false), naturalWidth(0), doc(0), layoutThread(0), nodeType(NodeIsNull)
+{
+ cacheAllTextAsImage = enableImageCache();
+}
+
+void QSGTextPrivate::init()
+{
+ Q_Q(QSGText);
+ q->setAcceptedMouseButtons(Qt::LeftButton);
+ q->setFlag(QSGItem::ItemHasContents);
+}
+
+QSGTextDocumentWithImageResources::QSGTextDocumentWithImageResources(QSGText *parent)
+: QTextDocument(parent), outstanding(0)
+{
+ setUndoRedoEnabled(false);
+}
+
+QSGTextDocumentWithImageResources::~QSGTextDocumentWithImageResources()
+{
+ if (!m_resources.isEmpty())
+ qDeleteAll(m_resources);
+}
+
+QVariant QSGTextDocumentWithImageResources::loadResource(int type, const QUrl &name)
+{
+ QDeclarativeContext *context = qmlContext(parent());
+ QUrl url = context->resolvedUrl(name);
+
+ if (type == QTextDocument::ImageResource) {
+ QHash<QUrl, QDeclarativePixmap *>::Iterator iter = m_resources.find(url);
+
+ if (iter == m_resources.end()) {
+ QDeclarativePixmap *p = new QDeclarativePixmap(context->engine(), url);
+ iter = m_resources.insert(name, p);
+
+ if (p->isLoading()) {
+ p->connectFinished(this, SLOT(requestFinished()));
+ outstanding++;
+ }
+ }
+
+ QDeclarativePixmap *p = *iter;
+ if (p->isReady()) {
+ return p->pixmap();
+ } else if (p->isError()) {
+ if (!errors.contains(url)) {
+ errors.insert(url);
+ qmlInfo(parent()) << p->error();
+ }
+ }
+ }
+
+ return QTextDocument::loadResource(type,url); // The *resolved* URL
+}
+
+void QSGTextDocumentWithImageResources::requestFinished()
+{
+ outstanding--;
+ if (outstanding == 0) {
+ QSGText *textItem = static_cast<QSGText*>(parent());
+ QString text = textItem->text();
+#ifndef QT_NO_TEXTHTMLPARSER
+ setHtml(text);
+#else
+ setPlainText(text);
+#endif
+ QSGTextPrivate *d = QSGTextPrivate::get(textItem);
+ d->updateLayout();
+ }
+}
+
+void QSGTextDocumentWithImageResources::setText(const QString &text)
+{
+ if (!m_resources.isEmpty()) {
+ qDeleteAll(m_resources);
+ m_resources.clear();
+ outstanding = 0;
+ }
+
+#ifndef QT_NO_TEXTHTMLPARSER
+ setHtml(text);
+#else
+ setPlainText(text);
+#endif
+}
+
+QSet<QUrl> QSGTextDocumentWithImageResources::errors;
+
+QSGTextPrivate::~QSGTextPrivate()
+{
+}
+
+qreal QSGTextPrivate::getImplicitWidth() const
+{
+ if (!requireImplicitWidth) {
+ // We don't calculate implicitWidth unless it is required.
+ // We need to force a size update now to ensure implicitWidth is calculated
+ QSGTextPrivate *me = const_cast<QSGTextPrivate*>(this);
+ me->requireImplicitWidth = true;
+ me->updateSize();
+ }
+ return implicitWidth;
+}
+
+void QSGTextPrivate::updateLayout()
+{
+ Q_Q(QSGText);
+ if (!q->isComponentComplete()) {
+ updateOnComponentComplete = true;
+ return;
+ }
+
+ layoutTextElided = false;
+ // Setup instance of QTextLayout for all cases other than richtext
+ if (!richText) {
+ layout.clearLayout();
+ layout.setFont(font);
+ if (format != QSGText::StyledText) {
+ QString tmp = text;
+ tmp.replace(QLatin1Char('\n'), QChar::LineSeparator);
+ singleline = !tmp.contains(QChar::LineSeparator);
+ if (singleline && !maximumLineCountValid && elideMode != QSGText::ElideNone && q->widthValid()) {
+ QFontMetrics fm(font);
+ tmp = fm.elidedText(tmp,(Qt::TextElideMode)elideMode,q->width());
+ if (tmp != text) {
+ layoutTextElided = true;
+ if (!truncated) {
+ truncated = true;
+ emit q->truncatedChanged();
+ }
+ }
+ }
+ layout.setText(tmp);
+ } else {
+ singleline = false;
+ QDeclarativeStyledText::parse(text, layout);
+ }
+ } else {
+ ensureDoc();
+ QTextBlockFormat::LineHeightTypes type;
+ type = lineHeightMode == QSGText::FixedHeight ? QTextBlockFormat::FixedHeight : QTextBlockFormat::ProportionalHeight;
+ QTextBlockFormat blockFormat;
+ blockFormat.setLineHeight((lineHeightMode == QSGText::FixedHeight ? lineHeight : lineHeight * 100), type);
+ for (QTextBlock it = doc->begin(); it != doc->end(); it = it.next()) {
+ QTextCursor cursor(it);
+ cursor.setBlockFormat(blockFormat);
+ }
+ }
+
+ updateSize();
+}
+
+void QSGTextPrivate::updateSize()
+{
+ Q_Q(QSGText);
+
+ if (!q->isComponentComplete()) {
+ updateOnComponentComplete = true;
+ return;
+ }
+
+ if (!requireImplicitWidth) {
+ emit q->implicitWidthChanged();
+ // if the implicitWidth is used, then updateSize() has already been called (recursively)
+ if (requireImplicitWidth)
+ return;
+ }
+
+ invalidateImageCache();
+
+ QFontMetrics fm(font);
+ if (text.isEmpty()) {
+ q->setImplicitWidth(0);
+ q->setImplicitHeight(fm.height());
+ paintedSize = QSize(0, fm.height());
+ emit q->paintedSizeChanged();
+ q->update();
+ return;
+ }
+
+ int dy = q->height();
+ QSize size(0, 0);
+
+ //setup instance of QTextLayout for all cases other than richtext
+ if (!richText) {
+ QRect textRect = setupTextLayout();
+ layedOutTextRect = textRect;
+ size = textRect.size();
+ dy -= size.height();
+ } else {
+ singleline = false; // richtext can't elide or be optimized for single-line case
+ ensureDoc();
+ doc->setDefaultFont(font);
+ QSGText::HAlignment horizontalAlignment = q->effectiveHAlign();
+ if (rightToLeftText) {
+ if (horizontalAlignment == QSGText::AlignLeft)
+ horizontalAlignment = QSGText::AlignRight;
+ else if (horizontalAlignment == QSGText::AlignRight)
+ horizontalAlignment = QSGText::AlignLeft;
+ }
+ QTextOption option;
+ option.setAlignment((Qt::Alignment)int(horizontalAlignment | vAlign));
+ option.setWrapMode(QTextOption::WrapMode(wrapMode));
+ doc->setDefaultTextOption(option);
+ if (requireImplicitWidth && q->widthValid()) {
+ doc->setTextWidth(-1);
+ naturalWidth = doc->idealWidth();
+ }
+ if (wrapMode != QSGText::NoWrap && q->widthValid())
+ doc->setTextWidth(q->width());
+ else
+ doc->setTextWidth(doc->idealWidth()); // ### Text does not align if width is not set (QTextDoc bug)
+ dy -= (int)doc->size().height();
+ QSize dsize = doc->size().toSize();
+ layedOutTextRect = QRect(QPoint(0,0), dsize);
+ size = QSize(int(doc->idealWidth()),dsize.height());
+ }
+ int yoff = 0;
+
+ if (q->heightValid()) {
+ if (vAlign == QSGText::AlignBottom)
+ yoff = dy;
+ else if (vAlign == QSGText::AlignVCenter)
+ yoff = dy/2;
+ }
+ q->setBaselineOffset(fm.ascent() + yoff);
+
+ //### need to comfirm cost of always setting these for richText
+ internalWidthUpdate = true;
+ if (!q->widthValid())
+ q->setImplicitWidth(size.width());
+ else if (requireImplicitWidth)
+ q->setImplicitWidth(naturalWidth);
+ internalWidthUpdate = false;
+
+ q->setImplicitHeight(size.height());
+ if (paintedSize != size) {
+ paintedSize = size;
+ emit q->paintedSizeChanged();
+ }
+ q->update();
+}
+
+/*!
+ Lays out the QSGTextPrivate::layout QTextLayout in the constraints of the QSGText.
+
+ Returns the size of the final text. This can be used to position the text vertically (the text is
+ already absolutely positioned horizontally).
+*/
+QRect QSGTextPrivate::setupTextLayout()
+{
+ // ### text layout handling should be profiled and optimized as needed
+ // what about QStackTextEngine engine(tmp, d->font.font()); QTextLayout textLayout(&engine);
+ Q_Q(QSGText);
+ layout.setCacheEnabled(true);
+
+ qreal lineWidth = 0;
+ int visibleCount = 0;
+
+ //set manual width
+ if (q->widthValid())
+ lineWidth = q->width();
+
+ QTextOption textOption = layout.textOption();
+ textOption.setAlignment(Qt::Alignment(q->effectiveHAlign()));
+ textOption.setWrapMode(QTextOption::WrapMode(wrapMode));
+ layout.setTextOption(textOption);
+
+ bool elideText = false;
+ bool truncate = false;
+
+ layoutThread = QThread::currentThread();
+
+ QFontMetrics fm(layout.font());
+ elidePos = QPointF();
+
+ if (requireImplicitWidth && q->widthValid()) {
+ // requires an extra layout
+ QString elidedText;
+ if (layoutTextElided) {
+ // We have provided elided text to the layout, but we must calculate unelided width.
+ elidedText = layout.text();
+ layout.setText(text);
+ }
+ layout.beginLayout();
+ forever {
+ QTextLine line = layout.createLine();
+ if (!line.isValid())
+ break;
+ }
+ layout.endLayout();
+ QRectF br;
+ for (int i = 0; i < layout.lineCount(); ++i) {
+ QTextLine line = layout.lineAt(i);
+ br = br.united(line.naturalTextRect());
+ }
+ naturalWidth = br.width();
+ if (layoutTextElided)
+ layout.setText(elidedText);
+ }
+
+ if (maximumLineCountValid) {
+ layout.beginLayout();
+ if (!lineWidth)
+ lineWidth = INT_MAX;
+ int linesLeft = maximumLineCount;
+ int visibleTextLength = 0;
+ while (linesLeft > 0) {
+ QTextLine line = layout.createLine();
+ if (!line.isValid())
+ break;
+
+ visibleCount++;
+ if (lineWidth)
+ line.setLineWidth(lineWidth);
+ visibleTextLength += line.textLength();
+
+ if (--linesLeft == 0) {
+ if (visibleTextLength < text.length()) {
+ truncate = true;
+ if (elideMode==QSGText::ElideRight && q->widthValid()) {
+ qreal elideWidth = fm.width(elideChar);
+ // Need to correct for alignment
+ line.setLineWidth(lineWidth-elideWidth);
+ if (layout.text().mid(line.textStart(), line.textLength()).isRightToLeft()) {
+ line.setPosition(QPointF(line.position().x() + elideWidth, line.position().y()));
+ elidePos.setX(line.naturalTextRect().left() - elideWidth);
+ } else {
+ elidePos.setX(line.naturalTextRect().right());
+ }
+ elideText = true;
+ }
+ }
+ }
+ }
+ layout.endLayout();
+
+ //Update truncated
+ if (truncated != truncate) {
+ truncated = truncate;
+ emit q->truncatedChanged();
+ }
+ } else {
+ layout.beginLayout();
+ forever {
+ QTextLine line = layout.createLine();
+ if (!line.isValid())
+ break;
+ visibleCount++;
+ if (lineWidth)
+ line.setLineWidth(lineWidth);
+ }
+ layout.endLayout();
+ }
+
+ qreal height = 0;
+ QRectF br;
+ for (int i = 0; i < layout.lineCount(); ++i) {
+ QTextLine line = layout.lineAt(i);
+ // set line spacing
+ line.setPosition(QPointF(line.position().x(), height));
+ if (elideText && i == layout.lineCount()-1) {
+ elidePos.setY(height + fm.ascent());
+ br = br.united(QRectF(elidePos, QSizeF(fm.width(elideChar), fm.ascent())));
+ }
+ br = br.united(line.naturalTextRect());
+ height += (lineHeightMode == QSGText::FixedHeight) ? lineHeight : line.height() * lineHeight;
+ }
+ br.setHeight(height);
+
+ if (!q->widthValid())
+ naturalWidth = br.width();
+
+ //Update the number of visible lines
+ if (lineCount != visibleCount) {
+ lineCount = visibleCount;
+ emit q->lineCountChanged();
+ }
+
+ return QRect(qRound(br.x()), qRound(br.y()), qCeil(br.width()), qCeil(br.height()));
+}
+
+/*!
+ Returns a painted version of the QSGTextPrivate::layout QTextLayout.
+ If \a drawStyle is true, the style color overrides all colors in the document.
+*/
+QPixmap QSGTextPrivate::textLayoutImage(bool drawStyle)
+{
+ QSize size = layedOutTextRect.size();
+
+ //paint text
+ QPixmap img(size);
+ if (!size.isEmpty()) {
+ img.fill(Qt::transparent);
+#ifdef Q_WS_MAC
+ bool oldSmooth = qt_applefontsmoothing_enabled;
+ qt_applefontsmoothing_enabled = false;
+#endif
+ QPainter p(&img);
+#ifdef Q_WS_MAC
+ qt_applefontsmoothing_enabled = oldSmooth;
+#endif
+ drawTextLayout(&p, QPointF(-layedOutTextRect.x(),0), drawStyle);
+ }
+ return img;
+}
+
+/*!
+ Paints the QSGTextPrivate::layout QTextLayout into \a painter at \a pos. If
+ \a drawStyle is true, the style color overrides all colors in the document.
+*/
+void QSGTextPrivate::drawTextLayout(QPainter *painter, const QPointF &pos, bool drawStyle)
+{
+ if (drawStyle)
+ painter->setPen(styleColor);
+ else
+ painter->setPen(color);
+ painter->setFont(font);
+ layout.draw(painter, pos);
+ if (!elidePos.isNull())
+ painter->drawText(pos + elidePos, elideChar);
+}
+
+/*!
+ Returns a painted version of the QSGTextPrivate::doc QTextDocument.
+ If \a drawStyle is true, the style color overrides all colors in the document.
+*/
+QPixmap QSGTextPrivate::textDocumentImage(bool drawStyle)
+{
+ QSize size = doc->size().toSize();
+
+ //paint text
+ QPixmap img(size);
+ img.fill(Qt::transparent);
+#ifdef Q_WS_MAC
+ bool oldSmooth = qt_applefontsmoothing_enabled;
+ qt_applefontsmoothing_enabled = false;
+#endif
+ QPainter p(&img);
+#ifdef Q_WS_MAC
+ qt_applefontsmoothing_enabled = oldSmooth;
+#endif
+
+ QAbstractTextDocumentLayout::PaintContext context;
+
+ QTextOption oldOption(doc->defaultTextOption());
+ if (drawStyle) {
+ context.palette.setColor(QPalette::Text, styleColor);
+ QTextOption colorOption(doc->defaultTextOption());
+ colorOption.setFlags(QTextOption::SuppressColors);
+ doc->setDefaultTextOption(colorOption);
+ } else {
+ context.palette.setColor(QPalette::Text, color);
+ }
+ doc->documentLayout()->draw(&p, context);
+ if (drawStyle)
+ doc->setDefaultTextOption(oldOption);
+ return img;
+}
+
+/*!
+ Mark the image cache as dirty.
+*/
+void QSGTextPrivate::invalidateImageCache()
+{
+ Q_Q(QSGText);
+
+ if(cacheAllTextAsImage || (!QSGDistanceFieldGlyphCache::distanceFieldEnabled() && style != QSGText::Normal)){//If actually using the image cache
+ if (imageCacheDirty)
+ return;
+
+ imageCacheDirty = true;
+ imageCache = QPixmap();
+ }
+ if (q->isComponentComplete())
+ q->update();
+}
+
+/*!
+ Tests if the image cache is dirty, and repaints it if it is.
+*/
+void QSGTextPrivate::checkImageCache()
+{
+ if (!imageCacheDirty)
+ return;
+
+ if (text.isEmpty()) {
+
+ imageCache = QPixmap();
+
+ } else {
+
+ QPixmap textImage;
+ QPixmap styledImage;
+
+ if (richText) {
+ textImage = textDocumentImage(false);
+ if (style != QSGText::Normal)
+ styledImage = textDocumentImage(true); //### should use styleColor
+ } else {
+ textImage = textLayoutImage(false);
+ if (style != QSGText::Normal)
+ styledImage = textLayoutImage(true); //### should use styleColor
+ }
+
+ switch (style) {
+ case QSGText::Outline:
+ imageCache = drawOutline(textImage, styledImage);
+ break;
+ case QSGText::Sunken:
+ imageCache = drawOutline(textImage, styledImage, -1);
+ break;
+ case QSGText::Raised:
+ imageCache = drawOutline(textImage, styledImage, 1);
+ break;
+ default:
+ imageCache = textImage;
+ break;
+ }
+
+ }
+
+ imageCacheDirty = false;
+}
+
+/*!
+ Ensures the QSGTextPrivate::doc variable is set to a valid text document
+*/
+void QSGTextPrivate::ensureDoc()
+{
+ if (!doc) {
+ Q_Q(QSGText);
+ doc = new QSGTextDocumentWithImageResources(q);
+ doc->setDocumentMargin(0);
+ }
+}
+
+/*!
+ Draw \a styleSource as an outline around \a source and return the new image.
+*/
+QPixmap QSGTextPrivate::drawOutline(const QPixmap &source, const QPixmap &styleSource)
+{
+ QPixmap img = QPixmap(styleSource.width() + 2, styleSource.height() + 2);
+ img.fill(Qt::transparent);
+
+ QPainter ppm(&img);
+
+ QPoint pos(0, 0);
+ pos += QPoint(-1, 0);
+ ppm.drawPixmap(pos, styleSource);
+ pos += QPoint(2, 0);
+ ppm.drawPixmap(pos, styleSource);
+ pos += QPoint(-1, -1);
+ ppm.drawPixmap(pos, styleSource);
+ pos += QPoint(0, 2);
+ ppm.drawPixmap(pos, styleSource);
+
+ pos += QPoint(0, -1);
+ ppm.drawPixmap(pos, source);
+ ppm.end();
+
+ return img;
+}
+
+/*!
+ Draw \a styleSource below \a source at \a yOffset and return the new image.
+*/
+QPixmap QSGTextPrivate::drawOutline(const QPixmap &source, const QPixmap &styleSource, int yOffset)
+{
+ QPixmap img = QPixmap(styleSource.width() + 2, styleSource.height() + 2);
+ img.fill(Qt::transparent);
+
+ QPainter ppm(&img);
+
+ ppm.drawPixmap(QPoint(0, yOffset), styleSource);
+ ppm.drawPixmap(0, 0, source);
+
+ ppm.end();
+
+ return img;
+}
+
+QSGText::QSGText(QSGItem *parent)
+: QSGImplicitSizeItem(*(new QSGTextPrivate), parent)
+{
+ Q_D(QSGText);
+ d->init();
+}
+
+QSGText::~QSGText()
+{
+}
+
+QFont QSGText::font() const
+{
+ Q_D(const QSGText);
+ return d->sourceFont;
+}
+
+void QSGText::setFont(const QFont &font)
+{
+ Q_D(QSGText);
+ if (d->sourceFont == font)
+ return;
+
+ d->sourceFont = font;
+ QFont oldFont = d->font;
+ d->font = font;
+ if (QSGDistanceFieldGlyphCache::distanceFieldEnabled())
+ d->font.setHintingPreference(QFont::PreferNoHinting);
+
+ if (d->font.pointSizeF() != -1) {
+ // 0.5pt resolution
+ qreal size = qRound(d->font.pointSizeF()*2.0);
+ d->font.setPointSizeF(size/2.0);
+ }
+
+ if (oldFont != d->font)
+ d->updateLayout();
+
+ emit fontChanged(d->sourceFont);
+}
+
+QString QSGText::text() const
+{
+ Q_D(const QSGText);
+ return d->text;
+}
+
+void QSGText::setText(const QString &n)
+{
+ Q_D(QSGText);
+ if (d->text == n)
+ return;
+
+ d->richText = d->format == RichText || (d->format == AutoText && Qt::mightBeRichText(n));
+ d->text = n;
+ if (isComponentComplete()) {
+ if (d->richText) {
+ d->ensureDoc();
+ d->doc->setText(n);
+ d->rightToLeftText = d->doc->toPlainText().isRightToLeft();
+ } else {
+ d->rightToLeftText = d->text.isRightToLeft();
+ }
+ d->determineHorizontalAlignment();
+ }
+ d->updateLayout();
+ emit textChanged(d->text);
+}
+
+QColor QSGText::color() const
+{
+ Q_D(const QSGText);
+ return d->color;
+}
+
+void QSGText::setColor(const QColor &color)
+{
+ Q_D(QSGText);
+ if (d->color == color)
+ return;
+
+ d->color = color;
+ d->invalidateImageCache();
+ emit colorChanged(d->color);
+}
+
+QSGText::TextStyle QSGText::style() const
+{
+ Q_D(const QSGText);
+ return d->style;
+}
+
+void QSGText::setStyle(QSGText::TextStyle style)
+{
+ Q_D(QSGText);
+ if (d->style == style)
+ return;
+
+ // changing to/from Normal requires the boundingRect() to change
+ if (isComponentComplete() && (d->style == Normal || style == Normal))
+ update();
+ d->style = style;
+ d->invalidateImageCache();
+ emit styleChanged(d->style);
+}
+
+QColor QSGText::styleColor() const
+{
+ Q_D(const QSGText);
+ return d->styleColor;
+}
+
+void QSGText::setStyleColor(const QColor &color)
+{
+ Q_D(QSGText);
+ if (d->styleColor == color)
+ return;
+
+ d->styleColor = color;
+ d->invalidateImageCache();
+ emit styleColorChanged(d->styleColor);
+}
+
+QSGText::HAlignment QSGText::hAlign() const
+{
+ Q_D(const QSGText);
+ return d->hAlign;
+}
+
+void QSGText::setHAlign(HAlignment align)
+{
+ Q_D(QSGText);
+ bool forceAlign = d->hAlignImplicit && d->effectiveLayoutMirror;
+ d->hAlignImplicit = false;
+ if (d->setHAlign(align, forceAlign) && isComponentComplete())
+ d->updateLayout();
+}
+
+void QSGText::resetHAlign()
+{
+ Q_D(QSGText);
+ d->hAlignImplicit = true;
+ if (d->determineHorizontalAlignment() && isComponentComplete())
+ d->updateLayout();
+}
+
+QSGText::HAlignment QSGText::effectiveHAlign() const
+{
+ Q_D(const QSGText);
+ QSGText::HAlignment effectiveAlignment = d->hAlign;
+ if (!d->hAlignImplicit && d->effectiveLayoutMirror) {
+ switch (d->hAlign) {
+ case QSGText::AlignLeft:
+ effectiveAlignment = QSGText::AlignRight;
+ break;
+ case QSGText::AlignRight:
+ effectiveAlignment = QSGText::AlignLeft;
+ break;
+ default:
+ break;
+ }
+ }
+ return effectiveAlignment;
+}
+
+bool QSGTextPrivate::setHAlign(QSGText::HAlignment alignment, bool forceAlign)
+{
+ Q_Q(QSGText);
+ if (hAlign != alignment || forceAlign) {
+ QSGText::HAlignment oldEffectiveHAlign = q->effectiveHAlign();
+ hAlign = alignment;
+
+ emit q->horizontalAlignmentChanged(hAlign);
+ if (oldEffectiveHAlign != q->effectiveHAlign())
+ emit q->effectiveHorizontalAlignmentChanged();
+ return true;
+ }
+ return false;
+}
+
+bool QSGTextPrivate::determineHorizontalAlignment()
+{
+ Q_Q(QSGText);
+ if (hAlignImplicit && q->isComponentComplete()) {
+ bool alignToRight = text.isEmpty() ? QApplication::keyboardInputDirection() == Qt::RightToLeft : rightToLeftText;
+ return setHAlign(alignToRight ? QSGText::AlignRight : QSGText::AlignLeft);
+ }
+ return false;
+}
+
+void QSGTextPrivate::mirrorChange()
+{
+ Q_Q(QSGText);
+ if (q->isComponentComplete()) {
+ if (!hAlignImplicit && (hAlign == QSGText::AlignRight || hAlign == QSGText::AlignLeft)) {
+ updateLayout();
+ emit q->effectiveHorizontalAlignmentChanged();
+ }
+ }
+}
+
+QTextDocument *QSGTextPrivate::textDocument()
+{
+ return doc;
+}
+
+QSGText::VAlignment QSGText::vAlign() const
+{
+ Q_D(const QSGText);
+ return d->vAlign;
+}
+
+void QSGText::setVAlign(VAlignment align)
+{
+ Q_D(QSGText);
+ if (d->vAlign == align)
+ return;
+
+ d->vAlign = align;
+ emit verticalAlignmentChanged(align);
+}
+
+QSGText::WrapMode QSGText::wrapMode() const
+{
+ Q_D(const QSGText);
+ return d->wrapMode;
+}
+
+void QSGText::setWrapMode(WrapMode mode)
+{
+ Q_D(QSGText);
+ if (mode == d->wrapMode)
+ return;
+
+ d->wrapMode = mode;
+ d->updateLayout();
+
+ emit wrapModeChanged();
+}
+
+int QSGText::lineCount() const
+{
+ Q_D(const QSGText);
+ return d->lineCount;
+}
+
+bool QSGText::truncated() const
+{
+ Q_D(const QSGText);
+ return d->truncated;
+}
+
+int QSGText::maximumLineCount() const
+{
+ Q_D(const QSGText);
+ return d->maximumLineCount;
+}
+
+void QSGText::setMaximumLineCount(int lines)
+{
+ Q_D(QSGText);
+
+ d->maximumLineCountValid = lines==INT_MAX ? false : true;
+ if (d->maximumLineCount != lines) {
+ d->maximumLineCount = lines;
+ d->updateLayout();
+ emit maximumLineCountChanged();
+ }
+}
+
+void QSGText::resetMaximumLineCount()
+{
+ Q_D(QSGText);
+ setMaximumLineCount(INT_MAX);
+ d->elidePos = QPointF();
+ if (d->truncated != false) {
+ d->truncated = false;
+ emit truncatedChanged();
+ }
+}
+
+QSGText::TextFormat QSGText::textFormat() const
+{
+ Q_D(const QSGText);
+ return d->format;
+}
+
+void QSGText::setTextFormat(TextFormat format)
+{
+ Q_D(QSGText);
+ if (format == d->format)
+ return;
+ d->format = format;
+ bool wasRich = d->richText;
+ d->richText = format == RichText || (format == AutoText && Qt::mightBeRichText(d->text));
+
+ if (!wasRich && d->richText && isComponentComplete()) {
+ d->ensureDoc();
+ d->doc->setText(d->text);
+ }
+
+ d->updateLayout();
+
+ emit textFormatChanged(d->format);
+}
+
+QSGText::TextElideMode QSGText::elideMode() const
+{
+ Q_D(const QSGText);
+ return d->elideMode;
+}
+
+void QSGText::setElideMode(QSGText::TextElideMode mode)
+{
+ Q_D(QSGText);
+ if (mode == d->elideMode)
+ return;
+
+ d->elideMode = mode;
+ d->updateLayout();
+
+ emit elideModeChanged(d->elideMode);
+}
+
+/*! \internal */
+QRectF QSGText::boundingRect() const
+{
+ Q_D(const QSGText);
+
+ QRect rect = d->layedOutTextRect;
+ if (d->style != Normal)
+ rect.adjust(-1, 0, 1, 2);
+
+ // Could include font max left/right bearings to either side of rectangle.
+
+ int h = height();
+ switch (d->vAlign) {
+ case AlignTop:
+ break;
+ case AlignBottom:
+ rect.moveTop(h - rect.height());
+ break;
+ case AlignVCenter:
+ rect.moveTop((h - rect.height()) / 2);
+ break;
+ }
+
+ return QRectF(rect);
+}
+
+/*! \internal */
+void QSGText::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
+{
+ Q_D(QSGText);
+ if ((!d->internalWidthUpdate && newGeometry.width() != oldGeometry.width())
+ && (d->wrapMode != QSGText::NoWrap
+ || d->elideMode != QSGText::ElideNone
+ || d->hAlign != QSGText::AlignLeft)) {
+ if ((d->singleline || d->maximumLineCountValid) && d->elideMode != QSGText::ElideNone && widthValid()) {
+ // We need to re-elide
+ d->updateLayout();
+ } else {
+ // We just need to re-layout
+ d->updateSize();
+ }
+ }
+
+ QSGItem::geometryChanged(newGeometry, oldGeometry);
+}
+
+QSGNode *QSGText::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data)
+{
+ Q_UNUSED(data);
+ Q_D(QSGText);
+
+ bool richTextAsImage = false;
+ if (d->richText) {
+ d->ensureDoc();
+ richTextAsImage = QSGTextNode::isComplexRichText(d->doc);
+ }
+
+ QRectF bounds = boundingRect();
+
+ // We need to make sure the layout is done in the current thread
+ if (d->layoutThread != QThread::currentThread())
+ d->updateLayout();
+
+ // XXX todo - some styled text can be done by the QSGTextNode
+ if (richTextAsImage || d->cacheAllTextAsImage || (!QSGDistanceFieldGlyphCache::distanceFieldEnabled() && d->style != Normal)) {
+ bool wasDirty = d->imageCacheDirty;
+
+ d->checkImageCache();
+
+ if (d->imageCache.isNull()) {
+ delete oldNode;
+ return 0;
+ }
+
+ QSGImageNode *node = 0;
+ if (!oldNode || d->nodeType != QSGTextPrivate::NodeIsTexture) {
+ delete oldNode;
+ node = QSGItemPrivate::get(this)->sceneGraphContext()->createImageNode();
+ d->texture = new QSGPlainTexture();
+ wasDirty = true;
+ d->nodeType = QSGTextPrivate::NodeIsTexture;
+ } else {
+ node = static_cast<QSGImageNode *>(oldNode);
+ Q_ASSERT(d->texture);
+ }
+
+ if (wasDirty) {
+ qobject_cast<QSGPlainTexture *>(d->texture)->setImage(d->imageCache.toImage());
+ node->setTexture(0);
+ node->setTexture(d->texture);
+ }
+
+ node->setTargetRect(QRectF(bounds.x(), bounds.y(), d->imageCache.width(), d->imageCache.height()));
+ node->setSourceRect(QRectF(0, 0, 1, 1));
+ node->setHorizontalWrapMode(QSGTexture::ClampToEdge);
+ node->setVerticalWrapMode(QSGTexture::ClampToEdge);
+ node->setFiltering(QSGTexture::Linear); // Nonsmooth text just ugly, so don't do that..
+ node->update();
+
+ return node;
+
+ } else {
+ QSGTextNode *node = 0;
+ if (!oldNode || d->nodeType != QSGTextPrivate::NodeIsText) {
+ delete oldNode;
+ node = new QSGTextNode(QSGItemPrivate::get(this)->sceneGraphContext());
+ d->nodeType = QSGTextPrivate::NodeIsText;
+ } else {
+ node = static_cast<QSGTextNode *>(oldNode);
+ }
+
+ node->deleteContent();
+ node->setMatrix(QMatrix4x4());
+
+ if (d->richText) {
+
+ d->ensureDoc();
+ node->addTextDocument(bounds.topLeft(), d->doc, QColor(), d->style, d->styleColor);
+
+ } else {
+ node->addTextLayout(QPoint(0, bounds.y()), &d->layout, d->color, d->style, d->styleColor);
+ }
+
+ return node;
+ }
+}
+
+qreal QSGText::paintedWidth() const
+{
+ Q_D(const QSGText);
+ return d->paintedSize.width();
+}
+
+qreal QSGText::paintedHeight() const
+{
+ Q_D(const QSGText);
+ return d->paintedSize.height();
+}
+
+qreal QSGText::lineHeight() const
+{
+ Q_D(const QSGText);
+ return d->lineHeight;
+}
+
+void QSGText::setLineHeight(qreal lineHeight)
+{
+ Q_D(QSGText);
+
+ if ((d->lineHeight == lineHeight) || (lineHeight < 0.0))
+ return;
+
+ d->lineHeight = lineHeight;
+ d->updateLayout();
+ emit lineHeightChanged(lineHeight);
+}
+
+QSGText::LineHeightMode QSGText::lineHeightMode() const
+{
+ Q_D(const QSGText);
+ return d->lineHeightMode;
+}
+
+void QSGText::setLineHeightMode(LineHeightMode mode)
+{
+ Q_D(QSGText);
+ if (mode == d->lineHeightMode)
+ return;
+
+ d->lineHeightMode = mode;
+ d->updateLayout();
+
+ emit lineHeightModeChanged(mode);
+}
+
+/*!
+ Returns the number of resources (images) that are being loaded asynchronously.
+*/
+int QSGText::resourcesLoading() const
+{
+ Q_D(const QSGText);
+ return d->doc ? d->doc->resourcesLoading() : 0;
+}
+
+/*! \internal */
+void QSGText::componentComplete()
+{
+ Q_D(QSGText);
+ QSGItem::componentComplete();
+ if (d->updateOnComponentComplete) {
+ d->updateOnComponentComplete = false;
+ if (d->richText) {
+ d->ensureDoc();
+ d->doc->setText(d->text);
+ d->rightToLeftText = d->doc->toPlainText().isRightToLeft();
+ } else {
+ d->rightToLeftText = d->text.isRightToLeft();
+ }
+ d->determineHorizontalAlignment();
+ d->updateLayout();
+ }
+}
+
+/*! \internal */
+void QSGText::mousePressEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(QSGText);
+
+ if (!d->richText || !d->doc || d->doc->documentLayout()->anchorAt(event->pos()).isEmpty()) {
+ event->setAccepted(false);
+ d->activeLink.clear();
+ } else {
+ d->activeLink = d->doc->documentLayout()->anchorAt(event->pos());
+ }
+
+ // ### may malfunction if two of the same links are clicked & dragged onto each other)
+
+ if (!event->isAccepted())
+ QSGItem::mousePressEvent(event);
+
+}
+
+/*! \internal */
+void QSGText::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(QSGText);
+
+ // ### confirm the link, and send a signal out
+ if (d->richText && d->doc && d->activeLink == d->doc->documentLayout()->anchorAt(event->pos()))
+ emit linkActivated(d->activeLink);
+ else
+ event->setAccepted(false);
+
+ if (!event->isAccepted())
+ QSGItem::mouseReleaseEvent(event);
+}
+
+QT_END_NAMESPACE
+
+#include "qsgtext.moc"
diff --git a/src/declarative/items/qsgtext_p.h b/src/declarative/items/qsgtext_p.h
new file mode 100644
index 0000000000..090a2b0e67
--- /dev/null
+++ b/src/declarative/items/qsgtext_p.h
@@ -0,0 +1,214 @@
+// Commit: 27e4302b7f45f22180693d26747f419177c81e27
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGTEXT_P_H
+#define QSGTEXT_P_H
+
+#include "qsgimplicitsizeitem_p.h"
+
+#include <private/qdeclarativeglobal_p.h>
+
+#include <QtGui/qtextoption.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+class QSGTextPrivate;
+class Q_DECLARATIVE_PRIVATE_EXPORT QSGText : public QSGImplicitSizeItem
+{
+ Q_OBJECT
+ Q_ENUMS(HAlignment)
+ Q_ENUMS(VAlignment)
+ Q_ENUMS(TextStyle)
+ Q_ENUMS(TextFormat)
+ Q_ENUMS(TextElideMode)
+ Q_ENUMS(WrapMode)
+ Q_ENUMS(LineHeightMode)
+
+ Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged)
+ Q_PROPERTY(QFont font READ font WRITE setFont NOTIFY fontChanged)
+ Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged)
+ Q_PROPERTY(TextStyle style READ style WRITE setStyle NOTIFY styleChanged)
+ Q_PROPERTY(QColor styleColor READ styleColor WRITE setStyleColor NOTIFY styleColorChanged)
+ Q_PROPERTY(HAlignment horizontalAlignment READ hAlign WRITE setHAlign RESET resetHAlign NOTIFY horizontalAlignmentChanged)
+ Q_PROPERTY(HAlignment effectiveHorizontalAlignment READ effectiveHAlign NOTIFY effectiveHorizontalAlignmentChanged)
+ Q_PROPERTY(VAlignment verticalAlignment READ vAlign WRITE setVAlign NOTIFY verticalAlignmentChanged)
+ Q_PROPERTY(WrapMode wrapMode READ wrapMode WRITE setWrapMode NOTIFY wrapModeChanged)
+ Q_PROPERTY(int lineCount READ lineCount NOTIFY lineCountChanged)
+ Q_PROPERTY(bool truncated READ truncated NOTIFY truncatedChanged)
+ Q_PROPERTY(int maximumLineCount READ maximumLineCount WRITE setMaximumLineCount NOTIFY maximumLineCountChanged RESET resetMaximumLineCount)
+
+ Q_PROPERTY(TextFormat textFormat READ textFormat WRITE setTextFormat NOTIFY textFormatChanged)
+ Q_PROPERTY(TextElideMode elide READ elideMode WRITE setElideMode NOTIFY elideModeChanged) //### elideMode?
+ Q_PROPERTY(qreal paintedWidth READ paintedWidth NOTIFY paintedSizeChanged)
+ Q_PROPERTY(qreal paintedHeight READ paintedHeight NOTIFY paintedSizeChanged)
+ Q_PROPERTY(qreal lineHeight READ lineHeight WRITE setLineHeight NOTIFY lineHeightChanged)
+ Q_PROPERTY(LineHeightMode lineHeightMode READ lineHeightMode WRITE setLineHeightMode NOTIFY lineHeightModeChanged)
+
+public:
+ QSGText(QSGItem *parent=0);
+ ~QSGText();
+
+ enum HAlignment { AlignLeft = Qt::AlignLeft,
+ AlignRight = Qt::AlignRight,
+ AlignHCenter = Qt::AlignHCenter,
+ AlignJustify = Qt::AlignJustify };
+ enum VAlignment { AlignTop = Qt::AlignTop,
+ AlignBottom = Qt::AlignBottom,
+ AlignVCenter = Qt::AlignVCenter };
+ enum TextStyle { Normal,
+ Outline,
+ Raised,
+ Sunken };
+ enum TextFormat { PlainText = Qt::PlainText,
+ RichText = Qt::RichText,
+ AutoText = Qt::AutoText,
+ StyledText = 4 };
+ enum TextElideMode { ElideLeft = Qt::ElideLeft,
+ ElideRight = Qt::ElideRight,
+ ElideMiddle = Qt::ElideMiddle,
+ ElideNone = Qt::ElideNone };
+
+ enum WrapMode { NoWrap = QTextOption::NoWrap,
+ WordWrap = QTextOption::WordWrap,
+ WrapAnywhere = QTextOption::WrapAnywhere,
+ WrapAtWordBoundaryOrAnywhere = QTextOption::WrapAtWordBoundaryOrAnywhere, // COMPAT
+ Wrap = QTextOption::WrapAtWordBoundaryOrAnywhere
+ };
+
+ enum LineHeightMode { ProportionalHeight, FixedHeight };
+
+ QString text() const;
+ void setText(const QString &);
+
+ QFont font() const;
+ void setFont(const QFont &font);
+
+ QColor color() const;
+ void setColor(const QColor &c);
+
+ TextStyle style() const;
+ void setStyle(TextStyle style);
+
+ QColor styleColor() const;
+ void setStyleColor(const QColor &c);
+
+ HAlignment hAlign() const;
+ void setHAlign(HAlignment align);
+ void resetHAlign();
+ HAlignment effectiveHAlign() const;
+
+ VAlignment vAlign() const;
+ void setVAlign(VAlignment align);
+
+ WrapMode wrapMode() const;
+ void setWrapMode(WrapMode w);
+
+ int lineCount() const;
+ bool truncated() const;
+
+ int maximumLineCount() const;
+ void setMaximumLineCount(int lines);
+ void resetMaximumLineCount();
+
+ TextFormat textFormat() const;
+ void setTextFormat(TextFormat format);
+
+ TextElideMode elideMode() const;
+ void setElideMode(TextElideMode);
+
+ qreal lineHeight() const;
+ void setLineHeight(qreal lineHeight);
+
+ LineHeightMode lineHeightMode() const;
+ void setLineHeightMode(LineHeightMode);
+
+ virtual void componentComplete();
+
+ int resourcesLoading() const; // mainly for testing
+
+ qreal paintedWidth() const;
+ qreal paintedHeight() const;
+
+ QRectF boundingRect() const;
+
+Q_SIGNALS:
+ void textChanged(const QString &text);
+ void linkActivated(const QString &link);
+ void fontChanged(const QFont &font);
+ void colorChanged(const QColor &color);
+ void styleChanged(TextStyle style);
+ void styleColorChanged(const QColor &color);
+ void horizontalAlignmentChanged(HAlignment alignment);
+ void verticalAlignmentChanged(VAlignment alignment);
+ void wrapModeChanged();
+ void lineCountChanged();
+ void truncatedChanged();
+ void maximumLineCountChanged();
+ void textFormatChanged(TextFormat textFormat);
+ void elideModeChanged(TextElideMode mode);
+ void paintedSizeChanged();
+ void lineHeightChanged(qreal lineHeight);
+ void lineHeightModeChanged(LineHeightMode mode);
+ void effectiveHorizontalAlignmentChanged();
+
+protected:
+ void mousePressEvent(QGraphicsSceneMouseEvent *event);
+ void mouseReleaseEvent(QGraphicsSceneMouseEvent *event);
+ virtual void geometryChanged(const QRectF &newGeometry,
+ const QRectF &oldGeometry);
+ virtual QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *);
+
+private:
+ Q_DISABLE_COPY(QSGText)
+ Q_DECLARE_PRIVATE(QSGText)
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QSGText)
+
+QT_END_HEADER
+
+#endif // QSGTEXT_P_H
diff --git a/src/declarative/items/qsgtext_p_p.h b/src/declarative/items/qsgtext_p_p.h
new file mode 100644
index 0000000000..a3836a19f8
--- /dev/null
+++ b/src/declarative/items/qsgtext_p_p.h
@@ -0,0 +1,156 @@
+// Commit: 6e5a642c9484536fc173714f560f739944368cf5
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGTEXT_P_P_H
+#define QSGTEXT_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 "qsgitem.h"
+#include "qsgimplicitsizeitem_p_p.h"
+
+#include <QtDeclarative/qdeclarative.h>
+#include <QtGui/qtextlayout.h>
+
+#include <private/qdeclarativetextlayout_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QTextLayout;
+class QSGTextDocumentWithImageResources;
+class QSGPlainTexture;
+
+class Q_AUTOTEST_EXPORT QSGTextPrivate : public QSGImplicitSizeItemPrivate
+{
+ Q_DECLARE_PUBLIC(QSGText)
+public:
+ QSGTextPrivate();
+ ~QSGTextPrivate();
+ void init();
+
+ void updateSize();
+ void updateLayout();
+ bool determineHorizontalAlignment();
+ bool setHAlign(QSGText::HAlignment, bool forceAlign = false);
+ void mirrorChange();
+ QTextDocument *textDocument();
+
+ QString text;
+ QFont font;
+ QFont sourceFont;
+ QColor color;
+ QSGText::TextStyle style;
+ QColor styleColor;
+ QString activeLink;
+ QSGText::HAlignment hAlign;
+ QSGText::VAlignment vAlign;
+ QSGText::TextElideMode elideMode;
+ QSGText::TextFormat format;
+ QSGText::WrapMode wrapMode;
+ qreal lineHeight;
+ QSGText::LineHeightMode lineHeightMode;
+ int lineCount;
+ int maximumLineCount;
+ int maximumLineCountValid;
+ QPointF elidePos;
+
+ static QString elideChar;
+
+ void invalidateImageCache();
+ void checkImageCache();
+ QPixmap imageCache;
+ QSGTexture *texture;
+
+ bool imageCacheDirty:1;
+ bool updateOnComponentComplete:1;
+ bool richText:1;
+ bool singleline:1;
+ bool cacheAllTextAsImage:1;
+ bool internalWidthUpdate:1;
+ bool requireImplicitWidth:1;
+ bool truncated:1;
+ bool hAlignImplicit:1;
+ bool rightToLeftText:1;
+ bool layoutTextElided:1;
+
+ QRect layedOutTextRect;
+ QSize paintedSize;
+ qreal naturalWidth;
+ virtual qreal getImplicitWidth() const;
+
+ void ensureDoc();
+ QPixmap textDocumentImage(bool drawStyle);
+ QSGTextDocumentWithImageResources *doc;
+
+ QRect setupTextLayout();
+ QPixmap textLayoutImage(bool drawStyle);
+ void drawTextLayout(QPainter *p, const QPointF &pos, bool drawStyle);
+ QTextLayout layout;
+ QThread *layoutThread;
+
+ static QPixmap drawOutline(const QPixmap &source, const QPixmap &styleSource);
+ static QPixmap drawOutline(const QPixmap &source, const QPixmap &styleSource, int yOffset);
+
+ static inline QSGTextPrivate *get(QSGText *t) {
+ return t->d_func();
+ }
+
+ enum NodeType {
+ NodeIsNull,
+ NodeIsTexture,
+ NodeIsText,
+ };
+ NodeType nodeType;
+};
+
+QT_END_NAMESPACE
+
+#endif // QSGTEXT_P_P_H
diff --git a/src/declarative/items/qsgtextedit.cpp b/src/declarative/items/qsgtextedit.cpp
new file mode 100644
index 0000000000..1c199ecc28
--- /dev/null
+++ b/src/declarative/items/qsgtextedit.cpp
@@ -0,0 +1,1232 @@
+// Commit: ec40dd2bb51868bca10dbd0c9116f3224ff2b29b
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgtextedit_p.h"
+#include "qsgtextedit_p_p.h"
+#include "qsgevents_p_p.h"
+#include "qsgcanvas.h"
+
+#include <QtDeclarative/qdeclarativeinfo.h>
+#include <QtGui/qapplication.h>
+#include <QtGui/qgraphicssceneevent.h>
+#include <QtGui/qpainter.h>
+#include <QtGui/qtextobject.h>
+#include <QtCore/qmath.h>
+
+#include <private/qdeclarativeglobal_p.h>
+#include <private/qtextcontrol_p.h>
+#include <private/qtextengine_p.h>
+#include <private/qwidget_p.h>
+
+QT_BEGIN_NAMESPACE
+
+QWidgetPrivate *qt_widget_private(QWidget *widget);
+
+QSGTextEdit::QSGTextEdit(QSGItem *parent)
+: QSGImplicitSizePaintedItem(*(new QSGTextEditPrivate), parent)
+{
+ Q_D(QSGTextEdit);
+ d->init();
+}
+
+QString QSGTextEdit::text() const
+{
+ Q_D(const QSGTextEdit);
+
+#ifndef QT_NO_TEXTHTMLPARSER
+ if (d->richText)
+ return d->document->toHtml();
+ else
+#endif
+ return d->document->toPlainText();
+}
+
+void QSGTextEdit::setText(const QString &text)
+{
+ Q_D(QSGTextEdit);
+ if (QSGTextEdit::text() == text)
+ return;
+
+ d->richText = d->format == RichText || (d->format == AutoText && Qt::mightBeRichText(text));
+ if (d->richText) {
+#ifndef QT_NO_TEXTHTMLPARSER
+ d->control->setHtml(text);
+#else
+ d->control->setPlainText(text);
+#endif
+ } else {
+ d->control->setPlainText(text);
+ }
+ q_textChanged();
+}
+
+QSGTextEdit::TextFormat QSGTextEdit::textFormat() const
+{
+ Q_D(const QSGTextEdit);
+ return d->format;
+}
+
+void QSGTextEdit::setTextFormat(TextFormat format)
+{
+ Q_D(QSGTextEdit);
+ if (format == d->format)
+ return;
+ bool wasRich = d->richText;
+ d->richText = format == RichText || (format == AutoText && Qt::mightBeRichText(d->text));
+
+ if (wasRich && !d->richText) {
+ d->control->setPlainText(d->text);
+ updateSize();
+ } else if (!wasRich && d->richText) {
+#ifndef QT_NO_TEXTHTMLPARSER
+ d->control->setHtml(d->text);
+#else
+ d->control->setPlainText(d->text);
+#endif
+ updateSize();
+ }
+ d->format = format;
+ d->control->setAcceptRichText(d->format != PlainText);
+ emit textFormatChanged(d->format);
+}
+
+QFont QSGTextEdit::font() const
+{
+ Q_D(const QSGTextEdit);
+ return d->sourceFont;
+}
+
+void QSGTextEdit::setFont(const QFont &font)
+{
+ Q_D(QSGTextEdit);
+ if (d->sourceFont == font)
+ return;
+
+ d->sourceFont = font;
+ QFont oldFont = d->font;
+ d->font = font;
+ if (d->font.pointSizeF() != -1) {
+ // 0.5pt resolution
+ qreal size = qRound(d->font.pointSizeF()*2.0);
+ d->font.setPointSizeF(size/2.0);
+ }
+
+ if (oldFont != d->font) {
+ d->document->setDefaultFont(d->font);
+ if(d->cursor){
+ d->cursor->setHeight(QFontMetrics(d->font).height());
+ moveCursorDelegate();
+ }
+ updateSize();
+ update();
+ }
+ emit fontChanged(d->sourceFont);
+}
+
+QColor QSGTextEdit::color() const
+{
+ Q_D(const QSGTextEdit);
+ return d->color;
+}
+
+void QSGTextEdit::setColor(const QColor &color)
+{
+ Q_D(QSGTextEdit);
+ if (d->color == color)
+ return;
+
+ d->color = color;
+ QPalette pal = d->control->palette();
+ pal.setColor(QPalette::Text, color);
+ d->control->setPalette(pal);
+ update();
+ emit colorChanged(d->color);
+}
+
+QColor QSGTextEdit::selectionColor() const
+{
+ Q_D(const QSGTextEdit);
+ return d->selectionColor;
+}
+
+void QSGTextEdit::setSelectionColor(const QColor &color)
+{
+ Q_D(QSGTextEdit);
+ if (d->selectionColor == color)
+ return;
+
+ d->selectionColor = color;
+ QPalette pal = d->control->palette();
+ pal.setColor(QPalette::Highlight, color);
+ d->control->setPalette(pal);
+ update();
+ emit selectionColorChanged(d->selectionColor);
+}
+
+QColor QSGTextEdit::selectedTextColor() const
+{
+ Q_D(const QSGTextEdit);
+ return d->selectedTextColor;
+}
+
+void QSGTextEdit::setSelectedTextColor(const QColor &color)
+{
+ Q_D(QSGTextEdit);
+ if (d->selectedTextColor == color)
+ return;
+
+ d->selectedTextColor = color;
+ QPalette pal = d->control->palette();
+ pal.setColor(QPalette::HighlightedText, color);
+ d->control->setPalette(pal);
+ update();
+ emit selectedTextColorChanged(d->selectedTextColor);
+}
+
+QSGTextEdit::HAlignment QSGTextEdit::hAlign() const
+{
+ Q_D(const QSGTextEdit);
+ return d->hAlign;
+}
+
+void QSGTextEdit::setHAlign(HAlignment align)
+{
+ Q_D(QSGTextEdit);
+ bool forceAlign = d->hAlignImplicit && d->effectiveLayoutMirror;
+ d->hAlignImplicit = false;
+ if (d->setHAlign(align, forceAlign) && isComponentComplete()) {
+ d->updateDefaultTextOption();
+ updateSize();
+ }
+}
+
+void QSGTextEdit::resetHAlign()
+{
+ Q_D(QSGTextEdit);
+ d->hAlignImplicit = true;
+ if (d->determineHorizontalAlignment() && isComponentComplete()) {
+ d->updateDefaultTextOption();
+ updateSize();
+ }
+}
+
+QSGTextEdit::HAlignment QSGTextEdit::effectiveHAlign() const
+{
+ Q_D(const QSGTextEdit);
+ QSGTextEdit::HAlignment effectiveAlignment = d->hAlign;
+ if (!d->hAlignImplicit && d->effectiveLayoutMirror) {
+ switch (d->hAlign) {
+ case QSGTextEdit::AlignLeft:
+ effectiveAlignment = QSGTextEdit::AlignRight;
+ break;
+ case QSGTextEdit::AlignRight:
+ effectiveAlignment = QSGTextEdit::AlignLeft;
+ break;
+ default:
+ break;
+ }
+ }
+ return effectiveAlignment;
+}
+
+bool QSGTextEditPrivate::setHAlign(QSGTextEdit::HAlignment alignment, bool forceAlign)
+{
+ Q_Q(QSGTextEdit);
+ if (hAlign != alignment || forceAlign) {
+ QSGTextEdit::HAlignment oldEffectiveHAlign = q->effectiveHAlign();
+ hAlign = alignment;
+ emit q->horizontalAlignmentChanged(alignment);
+ if (oldEffectiveHAlign != q->effectiveHAlign())
+ emit q->effectiveHorizontalAlignmentChanged();
+ return true;
+ }
+ return false;
+}
+
+bool QSGTextEditPrivate::determineHorizontalAlignment()
+{
+ Q_Q(QSGTextEdit);
+ if (hAlignImplicit && q->isComponentComplete()) {
+ bool alignToRight = text.isEmpty() ? QApplication::keyboardInputDirection() == Qt::RightToLeft : rightToLeftText;
+ return setHAlign(alignToRight ? QSGTextEdit::AlignRight : QSGTextEdit::AlignLeft);
+ }
+ return false;
+}
+
+void QSGTextEditPrivate::mirrorChange()
+{
+ Q_Q(QSGTextEdit);
+ if (q->isComponentComplete()) {
+ if (!hAlignImplicit && (hAlign == QSGTextEdit::AlignRight || hAlign == QSGTextEdit::AlignLeft)) {
+ updateDefaultTextOption();
+ q->updateSize();
+ emit q->effectiveHorizontalAlignmentChanged();
+ }
+ }
+}
+
+QSGTextEdit::VAlignment QSGTextEdit::vAlign() const
+{
+ Q_D(const QSGTextEdit);
+ return d->vAlign;
+}
+
+void QSGTextEdit::setVAlign(QSGTextEdit::VAlignment alignment)
+{
+ Q_D(QSGTextEdit);
+ if (alignment == d->vAlign)
+ return;
+ d->vAlign = alignment;
+ d->updateDefaultTextOption();
+ updateSize();
+ moveCursorDelegate();
+ emit verticalAlignmentChanged(d->vAlign);
+}
+
+QSGTextEdit::WrapMode QSGTextEdit::wrapMode() const
+{
+ Q_D(const QSGTextEdit);
+ return d->wrapMode;
+}
+
+void QSGTextEdit::setWrapMode(WrapMode mode)
+{
+ Q_D(QSGTextEdit);
+ if (mode == d->wrapMode)
+ return;
+ d->wrapMode = mode;
+ d->updateDefaultTextOption();
+ updateSize();
+ emit wrapModeChanged();
+}
+
+int QSGTextEdit::lineCount() const
+{
+ Q_D(const QSGTextEdit);
+ return d->lineCount;
+}
+
+qreal QSGTextEdit::paintedWidth() const
+{
+ Q_D(const QSGTextEdit);
+ return d->paintedSize.width();
+}
+
+qreal QSGTextEdit::paintedHeight() const
+{
+ Q_D(const QSGTextEdit);
+ return d->paintedSize.height();
+}
+
+QRectF QSGTextEdit::positionToRectangle(int pos) const
+{
+ Q_D(const QSGTextEdit);
+ QTextCursor c(d->document);
+ c.setPosition(pos);
+ return d->control->cursorRect(c);
+
+}
+
+int QSGTextEdit::positionAt(int x, int y) const
+{
+ Q_D(const QSGTextEdit);
+ int r = d->document->documentLayout()->hitTest(QPoint(x,y-d->yoff), Qt::FuzzyHit);
+ QTextCursor cursor = d->control->textCursor();
+ if (r > cursor.position()) {
+ // The cursor position includes positions within the preedit text, but only positions in the
+ // same text block are offset so it is possible to get a position that is either part of the
+ // preedit or the next text block.
+ QTextLayout *layout = cursor.block().layout();
+ const int preeditLength = layout
+ ? layout->preeditAreaText().length()
+ : 0;
+ if (preeditLength > 0
+ && d->document->documentLayout()->blockBoundingRect(cursor.block()).contains(x,y-d->yoff)) {
+ r = r > cursor.position() + preeditLength
+ ? r - preeditLength
+ : cursor.position();
+ }
+ }
+ return r;
+}
+
+void QSGTextEdit::moveCursorSelection(int pos)
+{
+ //Note that this is the same as setCursorPosition but with the KeepAnchor flag set
+ Q_D(QSGTextEdit);
+ QTextCursor cursor = d->control->textCursor();
+ if (cursor.position() == pos)
+ return;
+ cursor.setPosition(pos, QTextCursor::KeepAnchor);
+ d->control->setTextCursor(cursor);
+}
+
+void QSGTextEdit::moveCursorSelection(int pos, SelectionMode mode)
+{
+ Q_D(QSGTextEdit);
+ QTextCursor cursor = d->control->textCursor();
+ if (cursor.position() == pos)
+ return;
+ if (mode == SelectCharacters) {
+ cursor.setPosition(pos, QTextCursor::KeepAnchor);
+ } else if (cursor.anchor() < pos || (cursor.anchor() == pos && cursor.position() < pos)) {
+ if (cursor.anchor() > cursor.position()) {
+ cursor.setPosition(cursor.anchor(), QTextCursor::MoveAnchor);
+ cursor.movePosition(QTextCursor::StartOfWord, QTextCursor::KeepAnchor);
+ if (cursor.position() == cursor.anchor())
+ cursor.movePosition(QTextCursor::PreviousWord, QTextCursor::MoveAnchor);
+ else
+ cursor.setPosition(cursor.position(), QTextCursor::MoveAnchor);
+ } else {
+ cursor.setPosition(cursor.anchor(), QTextCursor::MoveAnchor);
+ cursor.movePosition(QTextCursor::StartOfWord, QTextCursor::MoveAnchor);
+ }
+
+ cursor.setPosition(pos, QTextCursor::KeepAnchor);
+ cursor.movePosition(QTextCursor::StartOfWord, QTextCursor::KeepAnchor);
+ if (cursor.position() != pos)
+ cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor);
+ } else if (cursor.anchor() > pos || (cursor.anchor() == pos && cursor.position() > pos)) {
+ if (cursor.anchor() < cursor.position()) {
+ cursor.setPosition(cursor.anchor(), QTextCursor::MoveAnchor);
+ cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::MoveAnchor);
+ } else {
+ cursor.setPosition(cursor.anchor(), QTextCursor::MoveAnchor);
+ cursor.movePosition(QTextCursor::PreviousCharacter, QTextCursor::KeepAnchor);
+ cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor);
+ if (cursor.position() != cursor.anchor()) {
+ cursor.setPosition(cursor.anchor(), QTextCursor::MoveAnchor);
+ cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::MoveAnchor);
+ }
+ }
+
+ cursor.setPosition(pos, QTextCursor::KeepAnchor);
+ cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor);
+ if (cursor.position() != pos) {
+ cursor.movePosition(QTextCursor::PreviousCharacter, QTextCursor::KeepAnchor);
+ cursor.movePosition(QTextCursor::StartOfWord, QTextCursor::KeepAnchor);
+ }
+ }
+ d->control->setTextCursor(cursor);
+}
+
+bool QSGTextEdit::isCursorVisible() const
+{
+ Q_D(const QSGTextEdit);
+ return d->cursorVisible;
+}
+
+void QSGTextEdit::setCursorVisible(bool on)
+{
+ Q_D(QSGTextEdit);
+ if (d->cursorVisible == on)
+ return;
+ d->cursorVisible = on;
+ QFocusEvent focusEvent(on ? QEvent::FocusIn : QEvent::FocusOut);
+ if (!on && !d->persistentSelection)
+ d->control->setCursorIsFocusIndicator(true);
+ d->control->processEvent(&focusEvent, QPointF(0, -d->yoff));
+ emit cursorVisibleChanged(d->cursorVisible);
+}
+
+int QSGTextEdit::cursorPosition() const
+{
+ Q_D(const QSGTextEdit);
+ return d->control->textCursor().position();
+}
+
+void QSGTextEdit::setCursorPosition(int pos)
+{
+ Q_D(QSGTextEdit);
+ if (pos < 0 || pos > d->text.length())
+ return;
+ QTextCursor cursor = d->control->textCursor();
+ if (cursor.position() == pos && cursor.anchor() == pos)
+ return;
+ cursor.setPosition(pos);
+ d->control->setTextCursor(cursor);
+}
+
+QDeclarativeComponent* QSGTextEdit::cursorDelegate() const
+{
+ Q_D(const QSGTextEdit);
+ return d->cursorComponent;
+}
+
+void QSGTextEdit::setCursorDelegate(QDeclarativeComponent* c)
+{
+ Q_D(QSGTextEdit);
+ if(d->cursorComponent){
+ if(d->cursor){
+ d->control->setCursorWidth(-1);
+ update(cursorRectangle());
+ delete d->cursor;
+ d->cursor = 0;
+ }
+ }
+ d->cursorComponent = c;
+ if(c && c->isReady()){
+ loadCursorDelegate();
+ }else{
+ if(c)
+ connect(c, SIGNAL(statusChanged()),
+ this, SLOT(loadCursorDelegate()));
+ }
+
+ emit cursorDelegateChanged();
+}
+
+void QSGTextEdit::loadCursorDelegate()
+{
+ Q_D(QSGTextEdit);
+ if(d->cursorComponent->isLoading())
+ return;
+ d->cursor = qobject_cast<QSGItem*>(d->cursorComponent->create(qmlContext(this)));
+ if(d->cursor){
+ d->control->setCursorWidth(0);
+ update(cursorRectangle());
+ QDeclarative_setParent_noEvent(d->cursor, this);
+ d->cursor->setParentItem(this);
+ d->cursor->setHeight(QFontMetrics(d->font).height());
+ moveCursorDelegate();
+ }else{
+ qmlInfo(this) << "Error loading cursor delegate.";
+ }
+}
+
+int QSGTextEdit::selectionStart() const
+{
+ Q_D(const QSGTextEdit);
+ return d->control->textCursor().selectionStart();
+}
+
+int QSGTextEdit::selectionEnd() const
+{
+ Q_D(const QSGTextEdit);
+ return d->control->textCursor().selectionEnd();
+}
+
+QString QSGTextEdit::selectedText() const
+{
+ Q_D(const QSGTextEdit);
+ return d->control->textCursor().selectedText();
+}
+
+bool QSGTextEdit::focusOnPress() const
+{
+ Q_D(const QSGTextEdit);
+ return d->focusOnPress;
+}
+
+void QSGTextEdit::setFocusOnPress(bool on)
+{
+ Q_D(QSGTextEdit);
+ if (d->focusOnPress == on)
+ return;
+ d->focusOnPress = on;
+ emit activeFocusOnPressChanged(d->focusOnPress);
+}
+
+bool QSGTextEdit::persistentSelection() const
+{
+ Q_D(const QSGTextEdit);
+ return d->persistentSelection;
+}
+
+void QSGTextEdit::setPersistentSelection(bool on)
+{
+ Q_D(QSGTextEdit);
+ if (d->persistentSelection == on)
+ return;
+ d->persistentSelection = on;
+ emit persistentSelectionChanged(d->persistentSelection);
+}
+
+qreal QSGTextEdit::textMargin() const
+{
+ Q_D(const QSGTextEdit);
+ return d->textMargin;
+}
+
+void QSGTextEdit::setTextMargin(qreal margin)
+{
+ Q_D(QSGTextEdit);
+ if (d->textMargin == margin)
+ return;
+ d->textMargin = margin;
+ d->document->setDocumentMargin(d->textMargin);
+ emit textMarginChanged(d->textMargin);
+}
+
+void QSGTextEdit::geometryChanged(const QRectF &newGeometry,
+ const QRectF &oldGeometry)
+{
+ if (newGeometry.width() != oldGeometry.width())
+ updateSize();
+ QSGPaintedItem::geometryChanged(newGeometry, oldGeometry);
+}
+
+void QSGTextEdit::componentComplete()
+{
+ Q_D(QSGTextEdit);
+ QSGPaintedItem::componentComplete();
+ if (d->dirty) {
+ d->determineHorizontalAlignment();
+ d->updateDefaultTextOption();
+ updateSize();
+ d->dirty = false;
+ }
+}
+
+bool QSGTextEdit::selectByMouse() const
+{
+ Q_D(const QSGTextEdit);
+ return d->selectByMouse;
+}
+
+void QSGTextEdit::setSelectByMouse(bool on)
+{
+ Q_D(QSGTextEdit);
+ if (d->selectByMouse != on) {
+ d->selectByMouse = on;
+ setKeepMouseGrab(on);
+ if (on)
+ setTextInteractionFlags(d->control->textInteractionFlags() | Qt::TextSelectableByMouse);
+ else
+ setTextInteractionFlags(d->control->textInteractionFlags() & ~Qt::TextSelectableByMouse);
+ emit selectByMouseChanged(on);
+ }
+}
+
+QSGTextEdit::SelectionMode QSGTextEdit::mouseSelectionMode() const
+{
+ Q_D(const QSGTextEdit);
+ return d->mouseSelectionMode;
+}
+
+void QSGTextEdit::setMouseSelectionMode(SelectionMode mode)
+{
+ Q_D(QSGTextEdit);
+ if (d->mouseSelectionMode != mode) {
+ d->mouseSelectionMode = mode;
+ d->control->setWordSelectionEnabled(mode == SelectWords);
+ emit mouseSelectionModeChanged(mode);
+ }
+}
+
+void QSGTextEdit::setReadOnly(bool r)
+{
+ Q_D(QSGTextEdit);
+ if (r == isReadOnly())
+ return;
+
+ setFlag(QSGItem::ItemAcceptsInputMethod, !r);
+ Qt::TextInteractionFlags flags = Qt::LinksAccessibleByMouse;
+ if (d->selectByMouse)
+ flags = flags | Qt::TextSelectableByMouse;
+ if (!r)
+ flags = flags | Qt::TextSelectableByKeyboard | Qt::TextEditable;
+ d->control->setTextInteractionFlags(flags);
+ if (!r)
+ d->control->moveCursor(QTextCursor::End);
+
+ emit readOnlyChanged(r);
+}
+
+bool QSGTextEdit::isReadOnly() const
+{
+ Q_D(const QSGTextEdit);
+ return !(d->control->textInteractionFlags() & Qt::TextEditable);
+}
+
+void QSGTextEdit::setTextInteractionFlags(Qt::TextInteractionFlags flags)
+{
+ Q_D(QSGTextEdit);
+ d->control->setTextInteractionFlags(flags);
+}
+
+Qt::TextInteractionFlags QSGTextEdit::textInteractionFlags() const
+{
+ Q_D(const QSGTextEdit);
+ return d->control->textInteractionFlags();
+}
+
+QRect QSGTextEdit::cursorRectangle() const
+{
+ Q_D(const QSGTextEdit);
+ return d->control->cursorRect().toRect().translated(0,d->yoff);
+}
+
+bool QSGTextEdit::event(QEvent *event)
+{
+ Q_D(QSGTextEdit);
+ if (event->type() == QEvent::ShortcutOverride) {
+ d->control->processEvent(event, QPointF(0, -d->yoff));
+ return event->isAccepted();
+ }
+ return QSGPaintedItem::event(event);
+}
+
+/*!
+\overload
+Handles the given key \a event.
+*/
+void QSGTextEdit::keyPressEvent(QKeyEvent *event)
+{
+ Q_D(QSGTextEdit);
+ d->control->processEvent(event, QPointF(0, -d->yoff));
+ if (!event->isAccepted())
+ QSGPaintedItem::keyPressEvent(event);
+}
+
+/*!
+\overload
+Handles the given key \a event.
+*/
+void QSGTextEdit::keyReleaseEvent(QKeyEvent *event)
+{
+ Q_D(QSGTextEdit);
+ d->control->processEvent(event, QPointF(0, -d->yoff));
+ if (!event->isAccepted())
+ QSGPaintedItem::keyReleaseEvent(event);
+}
+
+void QSGTextEdit::deselect()
+{
+ Q_D(QSGTextEdit);
+ QTextCursor c = d->control->textCursor();
+ c.clearSelection();
+ d->control->setTextCursor(c);
+}
+
+void QSGTextEdit::selectAll()
+{
+ Q_D(QSGTextEdit);
+ d->control->selectAll();
+}
+
+void QSGTextEdit::selectWord()
+{
+ Q_D(QSGTextEdit);
+ QTextCursor c = d->control->textCursor();
+ c.select(QTextCursor::WordUnderCursor);
+ d->control->setTextCursor(c);
+}
+
+void QSGTextEdit::select(int start, int end)
+{
+ Q_D(QSGTextEdit);
+ if (start < 0 || end < 0 || start > d->text.length() || end > d->text.length())
+ return;
+ QTextCursor cursor = d->control->textCursor();
+ cursor.beginEditBlock();
+ cursor.setPosition(start, QTextCursor::MoveAnchor);
+ cursor.setPosition(end, QTextCursor::KeepAnchor);
+ cursor.endEditBlock();
+ d->control->setTextCursor(cursor);
+
+ // QTBUG-11100
+ updateSelectionMarkers();
+}
+
+bool QSGTextEdit::isRightToLeft(int start, int end)
+{
+ Q_D(QSGTextEdit);
+ if (start > end) {
+ qmlInfo(this) << "isRightToLeft(start, end) called with the end property being smaller than the start.";
+ return false;
+ } else {
+ return d->text.mid(start, end - start).isRightToLeft();
+ }
+}
+
+#ifndef QT_NO_CLIPBOARD
+void QSGTextEdit::cut()
+{
+ Q_D(QSGTextEdit);
+ d->control->cut();
+}
+
+void QSGTextEdit::copy()
+{
+ Q_D(QSGTextEdit);
+ d->control->copy();
+}
+
+void QSGTextEdit::paste()
+{
+ Q_D(QSGTextEdit);
+ d->control->paste();
+}
+#endif // QT_NO_CLIPBOARD
+
+/*!
+\overload
+Handles the given mouse \a event.
+*/
+void QSGTextEdit::mousePressEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(QSGTextEdit);
+ if (d->focusOnPress){
+ bool hadActiveFocus = hasActiveFocus();
+ forceActiveFocus();
+ if (d->showInputPanelOnFocus) {
+ if (hasActiveFocus() && hadActiveFocus && !isReadOnly()) {
+ // re-open input panel on press if already focused
+ openSoftwareInputPanel();
+ }
+ } else { // show input panel on click
+ if (hasActiveFocus() && !hadActiveFocus) {
+ d->clickCausedFocus = true;
+ }
+ }
+ }
+ d->control->processEvent(event, QPointF(0, -d->yoff));
+ if (!event->isAccepted())
+ QSGPaintedItem::mousePressEvent(event);
+}
+
+/*!
+\overload
+Handles the given mouse \a event.
+*/
+void QSGTextEdit::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(QSGTextEdit);
+ d->control->processEvent(event, QPointF(0, -d->yoff));
+ if (!d->showInputPanelOnFocus) { // input panel on click
+ if (d->focusOnPress && !isReadOnly() && boundingRect().contains(event->pos())) {
+ if (canvas() && canvas() == qApp->focusWidget()) {
+ qt_widget_private(canvas())->handleSoftwareInputPanel(event->button(), d->clickCausedFocus);
+ }
+ }
+ }
+ d->clickCausedFocus = false;
+
+ if (!event->isAccepted())
+ QSGPaintedItem::mouseReleaseEvent(event);
+}
+
+/*!
+\overload
+Handles the given mouse \a event.
+*/
+void QSGTextEdit::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(QSGTextEdit);
+ d->control->processEvent(event, QPointF(0, -d->yoff));
+ if (!event->isAccepted())
+ QSGPaintedItem::mouseDoubleClickEvent(event);
+}
+
+/*!
+\overload
+Handles the given mouse \a event.
+*/
+void QSGTextEdit::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(QSGTextEdit);
+ d->control->processEvent(event, QPointF(0, -d->yoff));
+ if (!event->isAccepted())
+ QSGPaintedItem::mouseMoveEvent(event);
+}
+
+/*!
+\overload
+Handles the given input method \a event.
+*/
+void QSGTextEdit::inputMethodEvent(QInputMethodEvent *event)
+{
+ Q_D(QSGTextEdit);
+ const bool wasComposing = isInputMethodComposing();
+ d->control->processEvent(event, QPointF(0, -d->yoff));
+ if (wasComposing != isInputMethodComposing())
+ emit inputMethodComposingChanged();
+}
+
+void QSGTextEdit::itemChange(ItemChange change, const ItemChangeData &value)
+{
+ Q_D(QSGTextEdit);
+ if (change == ItemActiveFocusHasChanged) {
+ setCursorVisible(value.boolValue && d->canvas && d->canvas->hasFocus());
+ }
+ QSGItem::itemChange(change, value);
+}
+
+/*!
+\overload
+Returns the value of the given \a property.
+*/
+QVariant QSGTextEdit::inputMethodQuery(Qt::InputMethodQuery property) const
+{
+ Q_D(const QSGTextEdit);
+ return d->control->inputMethodQuery(property);
+}
+
+/*!
+Draws the contents of the text edit using the given \a painter within
+the given \a bounds.
+*/
+void QSGTextEdit::paint(QPainter *painter)
+{
+ // XXX todo
+ QRect bounds(0, 0, width(), height());
+ Q_D(QSGTextEdit);
+
+ painter->setRenderHint(QPainter::TextAntialiasing, true);
+ painter->translate(0,d->yoff);
+
+ d->control->drawContents(painter, bounds.translated(0,-d->yoff));
+
+ painter->translate(0,-d->yoff);
+}
+
+void QSGTextEdit::updateImgCache(const QRectF &rf)
+{
+ Q_D(const QSGTextEdit);
+ QRect r;
+ if (!rf.isValid()) {
+ r = QRect(0,0,INT_MAX,INT_MAX);
+ } else {
+ r = rf.toRect();
+ if (r.height() > INT_MAX/2) {
+ // Take care of overflow when translating "everything"
+ r.setTop(r.y() + d->yoff);
+ r.setBottom(INT_MAX/2);
+ } else {
+ r = r.translated(0,d->yoff);
+ }
+ }
+ update(r);
+}
+
+bool QSGTextEdit::canPaste() const
+{
+ Q_D(const QSGTextEdit);
+ return d->canPaste;
+}
+
+bool QSGTextEdit::isInputMethodComposing() const
+{
+ Q_D(const QSGTextEdit);
+ if (QTextLayout *layout = d->control->textCursor().block().layout())
+ return layout->preeditAreaText().length() > 0;
+ return false;
+}
+
+void QSGTextEditPrivate::init()
+{
+ Q_Q(QSGTextEdit);
+
+ q->setSmooth(smooth);
+ q->setAcceptedMouseButtons(Qt::LeftButton);
+ q->setFlag(QSGItem::ItemAcceptsInputMethod);
+
+ control = new QTextControl(q);
+ control->setIgnoreUnusedNavigationEvents(true);
+ control->setTextInteractionFlags(Qt::LinksAccessibleByMouse | Qt::TextSelectableByKeyboard | Qt::TextEditable);
+ control->setDragEnabled(false);
+
+ // QTextControl follows the default text color
+ // defined by the platform, declarative text
+ // should be black by default
+ QPalette pal = control->palette();
+ if (pal.color(QPalette::Text) != color) {
+ pal.setColor(QPalette::Text, color);
+ control->setPalette(pal);
+ }
+
+ QObject::connect(control, SIGNAL(updateRequest(QRectF)), q, SLOT(updateImgCache(QRectF)));
+
+ QObject::connect(control, SIGNAL(textChanged()), q, SLOT(q_textChanged()));
+ QObject::connect(control, SIGNAL(selectionChanged()), q, SIGNAL(selectionChanged()));
+ QObject::connect(control, SIGNAL(selectionChanged()), q, SLOT(updateSelectionMarkers()));
+ QObject::connect(control, SIGNAL(cursorPositionChanged()), q, SLOT(updateSelectionMarkers()));
+ QObject::connect(control, SIGNAL(cursorPositionChanged()), q, SIGNAL(cursorPositionChanged()));
+ QObject::connect(control, SIGNAL(microFocusChanged()), q, SLOT(moveCursorDelegate()));
+ QObject::connect(control, SIGNAL(linkActivated(QString)), q, SIGNAL(linkActivated(QString)));
+#ifndef QT_NO_CLIPBOARD
+ QObject::connect(q, SIGNAL(readOnlyChanged(bool)), q, SLOT(q_canPasteChanged()));
+ QObject::connect(QApplication::clipboard(), SIGNAL(dataChanged()), q, SLOT(q_canPasteChanged()));
+ canPaste = control->canPaste();
+#endif
+
+ document = control->document();
+ document->setDefaultFont(font);
+ document->setDocumentMargin(textMargin);
+ document->setUndoRedoEnabled(false); // flush undo buffer.
+ document->setUndoRedoEnabled(true);
+ updateDefaultTextOption();
+}
+
+void QSGTextEdit::q_textChanged()
+{
+ Q_D(QSGTextEdit);
+ d->text = text();
+ d->rightToLeftText = d->document->begin().layout()->engine()->isRightToLeft();
+ d->determineHorizontalAlignment();
+ d->updateDefaultTextOption();
+ updateSize();
+ updateTotalLines();
+ emit textChanged(d->text);
+}
+
+void QSGTextEdit::moveCursorDelegate()
+{
+ Q_D(QSGTextEdit);
+ updateMicroFocus();
+ emit cursorRectangleChanged();
+ if(!d->cursor)
+ return;
+ QRectF cursorRect = cursorRectangle();
+ d->cursor->setX(cursorRect.x());
+ d->cursor->setY(cursorRect.y());
+}
+
+void QSGTextEditPrivate::updateSelection()
+{
+ Q_Q(QSGTextEdit);
+ QTextCursor cursor = control->textCursor();
+ bool startChange = (lastSelectionStart != cursor.selectionStart());
+ bool endChange = (lastSelectionEnd != cursor.selectionEnd());
+ cursor.beginEditBlock();
+ cursor.setPosition(lastSelectionStart, QTextCursor::MoveAnchor);
+ cursor.setPosition(lastSelectionEnd, QTextCursor::KeepAnchor);
+ cursor.endEditBlock();
+ control->setTextCursor(cursor);
+ if(startChange)
+ q->selectionStartChanged();
+ if(endChange)
+ q->selectionEndChanged();
+}
+
+void QSGTextEdit::updateSelectionMarkers()
+{
+ Q_D(QSGTextEdit);
+ if(d->lastSelectionStart != d->control->textCursor().selectionStart()){
+ d->lastSelectionStart = d->control->textCursor().selectionStart();
+ emit selectionStartChanged();
+ }
+ if(d->lastSelectionEnd != d->control->textCursor().selectionEnd()){
+ d->lastSelectionEnd = d->control->textCursor().selectionEnd();
+ emit selectionEndChanged();
+ }
+}
+
+QRectF QSGTextEdit::boundingRect() const
+{
+ Q_D(const QSGTextEdit);
+ QRectF r = QSGPaintedItem::boundingRect();
+ int cursorWidth = 1;
+ if(d->cursor)
+ cursorWidth = d->cursor->width();
+ if(!d->document->isEmpty())
+ cursorWidth += 3;// ### Need a better way of accounting for space between char and cursor
+
+ // Could include font max left/right bearings to either side of rectangle.
+
+ r.setRight(r.right() + cursorWidth);
+ return r.translated(0,d->yoff);
+}
+
+qreal QSGTextEditPrivate::getImplicitWidth() const
+{
+ Q_Q(const QSGTextEdit);
+ if (!requireImplicitWidth) {
+ // We don't calculate implicitWidth unless it is required.
+ // We need to force a size update now to ensure implicitWidth is calculated
+ const_cast<QSGTextEditPrivate*>(this)->requireImplicitWidth = true;
+ const_cast<QSGTextEdit*>(q)->updateSize();
+ }
+ return implicitWidth;
+}
+
+//### we should perhaps be a bit smarter here -- depending on what has changed, we shouldn't
+// need to do all the calculations each time
+void QSGTextEdit::updateSize()
+{
+ Q_D(QSGTextEdit);
+ if (isComponentComplete()) {
+ qreal naturalWidth = d->implicitWidth;
+ // ### assumes that if the width is set, the text will fill to edges
+ // ### (unless wrap is false, then clipping will occur)
+ if (widthValid()) {
+ if (!d->requireImplicitWidth) {
+ emit implicitWidthChanged();
+ // if the implicitWidth is used, then updateSize() has already been called (recursively)
+ if (d->requireImplicitWidth)
+ return;
+ }
+ if (d->requireImplicitWidth) {
+ d->document->setTextWidth(-1);
+ naturalWidth = d->document->idealWidth();
+ }
+ if (d->document->textWidth() != width())
+ d->document->setTextWidth(width());
+ } else {
+ d->document->setTextWidth(-1);
+ }
+ QFontMetrics fm = QFontMetrics(d->font);
+ int dy = height();
+ dy -= (int)d->document->size().height();
+
+ int nyoff;
+ if (heightValid()) {
+ if (d->vAlign == AlignBottom)
+ nyoff = dy;
+ else if (d->vAlign == AlignVCenter)
+ nyoff = dy/2;
+ else
+ nyoff = 0;
+ } else {
+ nyoff = 0;
+ }
+ if (nyoff != d->yoff)
+ d->yoff = nyoff;
+ setBaselineOffset(fm.ascent() + d->yoff + d->textMargin);
+
+ //### need to comfirm cost of always setting these
+ int newWidth = qCeil(d->document->idealWidth());
+ if (!widthValid() && d->document->textWidth() != newWidth)
+ d->document->setTextWidth(newWidth); // ### Text does not align if width is not set (QTextDoc bug)
+ // ### Setting the implicitWidth triggers another updateSize(), and unless there are bindings nothing has changed.
+ if (!widthValid())
+ setImplicitWidth(newWidth);
+ else if (d->requireImplicitWidth)
+ setImplicitWidth(naturalWidth);
+ qreal newHeight = d->document->isEmpty() ? fm.height() : (int)d->document->size().height();
+ setImplicitHeight(newHeight);
+
+ d->paintedSize = QSize(newWidth, newHeight);
+ setContentsSize(d->paintedSize);
+ emit paintedSizeChanged();
+ } else {
+ d->dirty = true;
+ }
+ update();
+}
+
+void QSGTextEdit::updateTotalLines()
+{
+ Q_D(QSGTextEdit);
+
+ int subLines = 0;
+
+ for (QTextBlock it = d->document->begin(); it != d->document->end(); it = it.next()) {
+ QTextLayout *layout = it.layout();
+ if (!layout)
+ continue;
+ subLines += layout->lineCount()-1;
+ }
+
+ int newTotalLines = d->document->lineCount() + subLines;
+ if (d->lineCount != newTotalLines) {
+ d->lineCount = newTotalLines;
+ emit lineCountChanged();
+ }
+}
+
+void QSGTextEditPrivate::updateDefaultTextOption()
+{
+ Q_Q(QSGTextEdit);
+ QTextOption opt = document->defaultTextOption();
+ int oldAlignment = opt.alignment();
+
+ QSGTextEdit::HAlignment horizontalAlignment = q->effectiveHAlign();
+ if (rightToLeftText) {
+ if (horizontalAlignment == QSGTextEdit::AlignLeft)
+ horizontalAlignment = QSGTextEdit::AlignRight;
+ else if (horizontalAlignment == QSGTextEdit::AlignRight)
+ horizontalAlignment = QSGTextEdit::AlignLeft;
+ }
+ opt.setAlignment((Qt::Alignment)(int)(horizontalAlignment | vAlign));
+
+ QTextOption::WrapMode oldWrapMode = opt.wrapMode();
+ opt.setWrapMode(QTextOption::WrapMode(wrapMode));
+
+ if (oldWrapMode == opt.wrapMode() && oldAlignment == opt.alignment())
+ return;
+ document->setDefaultTextOption(opt);
+}
+
+
+void QSGTextEdit::openSoftwareInputPanel()
+{
+ if (qApp) {
+ if (canvas() && canvas() == qApp->focusWidget()) {
+ QEvent event(QEvent::RequestSoftwareInputPanel);
+ QApplication::sendEvent(canvas(), &event);
+ }
+ }
+}
+
+void QSGTextEdit::closeSoftwareInputPanel()
+{
+ if (qApp) {
+ if (canvas() && canvas() == qApp->focusWidget()) {
+ QEvent event(QEvent::CloseSoftwareInputPanel);
+ QApplication::sendEvent(canvas(), &event);
+ }
+ }
+}
+
+void QSGTextEdit::focusInEvent(QFocusEvent *event)
+{
+ Q_D(const QSGTextEdit);
+ if (d->showInputPanelOnFocus) {
+ if (d->focusOnPress && !isReadOnly()) {
+ openSoftwareInputPanel();
+ }
+ }
+ QSGPaintedItem::focusInEvent(event);
+}
+
+void QSGTextEdit::q_canPasteChanged()
+{
+ Q_D(QSGTextEdit);
+ bool old = d->canPaste;
+ d->canPaste = d->control->canPaste();
+ if(old!=d->canPaste)
+ emit canPasteChanged();
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/items/qsgtextedit_p.h b/src/declarative/items/qsgtextedit_p.h
new file mode 100644
index 0000000000..547ead18e9
--- /dev/null
+++ b/src/declarative/items/qsgtextedit_p.h
@@ -0,0 +1,303 @@
+// Commit: 27e4302b7f45f22180693d26747f419177c81e27
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGTEXTEDIT_P_H
+#define QSGTEXTEDIT_P_H
+
+#include "qsgimplicitsizeitem_p.h"
+
+#include <QtGui/qtextoption.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QSGTextEditPrivate;
+class Q_AUTOTEST_EXPORT QSGTextEdit : public QSGImplicitSizePaintedItem
+{
+ Q_OBJECT
+ Q_ENUMS(VAlignment)
+ Q_ENUMS(HAlignment)
+ Q_ENUMS(TextFormat)
+ Q_ENUMS(WrapMode)
+ Q_ENUMS(SelectionMode)
+
+ Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged)
+ Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged)
+ Q_PROPERTY(QColor selectionColor READ selectionColor WRITE setSelectionColor NOTIFY selectionColorChanged)
+ Q_PROPERTY(QColor selectedTextColor READ selectedTextColor WRITE setSelectedTextColor NOTIFY selectedTextColorChanged)
+ Q_PROPERTY(QFont font READ font WRITE setFont NOTIFY fontChanged)
+ Q_PROPERTY(HAlignment horizontalAlignment READ hAlign WRITE setHAlign RESET resetHAlign NOTIFY horizontalAlignmentChanged)
+ Q_PROPERTY(HAlignment effectiveHorizontalAlignment READ effectiveHAlign NOTIFY effectiveHorizontalAlignmentChanged)
+ Q_PROPERTY(VAlignment verticalAlignment READ vAlign WRITE setVAlign NOTIFY verticalAlignmentChanged)
+ Q_PROPERTY(WrapMode wrapMode READ wrapMode WRITE setWrapMode NOTIFY wrapModeChanged)
+ Q_PROPERTY(int lineCount READ lineCount NOTIFY lineCountChanged)
+ Q_PROPERTY(qreal paintedWidth READ paintedWidth NOTIFY paintedSizeChanged)
+ Q_PROPERTY(qreal paintedHeight READ paintedHeight NOTIFY paintedSizeChanged)
+ Q_PROPERTY(TextFormat textFormat READ textFormat WRITE setTextFormat NOTIFY textFormatChanged)
+ Q_PROPERTY(bool readOnly READ isReadOnly WRITE setReadOnly NOTIFY readOnlyChanged)
+ Q_PROPERTY(bool cursorVisible READ isCursorVisible WRITE setCursorVisible NOTIFY cursorVisibleChanged)
+ Q_PROPERTY(int cursorPosition READ cursorPosition WRITE setCursorPosition NOTIFY cursorPositionChanged)
+ Q_PROPERTY(QRect cursorRectangle READ cursorRectangle NOTIFY cursorRectangleChanged)
+ Q_PROPERTY(QDeclarativeComponent* cursorDelegate READ cursorDelegate WRITE setCursorDelegate NOTIFY cursorDelegateChanged)
+ Q_PROPERTY(int selectionStart READ selectionStart NOTIFY selectionStartChanged)
+ Q_PROPERTY(int selectionEnd READ selectionEnd NOTIFY selectionEndChanged)
+ Q_PROPERTY(QString selectedText READ selectedText NOTIFY selectionChanged)
+ Q_PROPERTY(bool activeFocusOnPress READ focusOnPress WRITE setFocusOnPress NOTIFY activeFocusOnPressChanged)
+ Q_PROPERTY(bool persistentSelection READ persistentSelection WRITE setPersistentSelection NOTIFY persistentSelectionChanged)
+ Q_PROPERTY(qreal textMargin READ textMargin WRITE setTextMargin NOTIFY textMarginChanged)
+ Q_PROPERTY(Qt::InputMethodHints inputMethodHints READ inputMethodHints WRITE setInputMethodHints)
+ Q_PROPERTY(bool selectByMouse READ selectByMouse WRITE setSelectByMouse NOTIFY selectByMouseChanged)
+ Q_PROPERTY(SelectionMode mouseSelectionMode READ mouseSelectionMode WRITE setMouseSelectionMode NOTIFY mouseSelectionModeChanged)
+ Q_PROPERTY(bool canPaste READ canPaste NOTIFY canPasteChanged)
+ Q_PROPERTY(bool inputMethodComposing READ isInputMethodComposing NOTIFY inputMethodComposingChanged)
+
+public:
+ QSGTextEdit(QSGItem *parent=0);
+
+ enum HAlignment {
+ AlignLeft = Qt::AlignLeft,
+ AlignRight = Qt::AlignRight,
+ AlignHCenter = Qt::AlignHCenter,
+ AlignJustify = Qt::AlignJustify
+ };
+
+ enum VAlignment {
+ AlignTop = Qt::AlignTop,
+ AlignBottom = Qt::AlignBottom,
+ AlignVCenter = Qt::AlignVCenter
+ };
+
+ enum TextFormat {
+ PlainText = Qt::PlainText,
+ RichText = Qt::RichText,
+ AutoText = Qt::AutoText
+ };
+
+ enum WrapMode { NoWrap = QTextOption::NoWrap,
+ WordWrap = QTextOption::WordWrap,
+ WrapAnywhere = QTextOption::WrapAnywhere,
+ WrapAtWordBoundaryOrAnywhere = QTextOption::WrapAtWordBoundaryOrAnywhere, // COMPAT
+ Wrap = QTextOption::WrapAtWordBoundaryOrAnywhere
+ };
+
+ enum SelectionMode {
+ SelectCharacters,
+ SelectWords
+ };
+
+ Q_INVOKABLE void openSoftwareInputPanel();
+ Q_INVOKABLE void closeSoftwareInputPanel();
+
+ QString text() const;
+ void setText(const QString &);
+
+ TextFormat textFormat() const;
+ void setTextFormat(TextFormat format);
+
+ QFont font() const;
+ void setFont(const QFont &font);
+
+ QColor color() const;
+ void setColor(const QColor &c);
+
+ QColor selectionColor() const;
+ void setSelectionColor(const QColor &c);
+
+ QColor selectedTextColor() const;
+ void setSelectedTextColor(const QColor &c);
+
+ HAlignment hAlign() const;
+ void setHAlign(HAlignment align);
+ void resetHAlign();
+ HAlignment effectiveHAlign() const;
+
+ VAlignment vAlign() const;
+ void setVAlign(VAlignment align);
+
+ WrapMode wrapMode() const;
+ void setWrapMode(WrapMode w);
+
+ int lineCount() const;
+
+ bool isCursorVisible() const;
+ void setCursorVisible(bool on);
+
+ int cursorPosition() const;
+ void setCursorPosition(int pos);
+
+ QDeclarativeComponent* cursorDelegate() const;
+ void setCursorDelegate(QDeclarativeComponent*);
+
+ int selectionStart() const;
+ int selectionEnd() const;
+
+ QString selectedText() const;
+
+ bool focusOnPress() const;
+ void setFocusOnPress(bool on);
+
+ bool persistentSelection() const;
+ void setPersistentSelection(bool on);
+
+ qreal textMargin() const;
+ void setTextMargin(qreal margin);
+
+ bool selectByMouse() const;
+ void setSelectByMouse(bool);
+
+ SelectionMode mouseSelectionMode() const;
+ void setMouseSelectionMode(SelectionMode mode);
+
+ bool canPaste() const;
+
+ virtual void componentComplete();
+
+ /* FROM EDIT */
+ void setReadOnly(bool);
+ bool isReadOnly() const;
+
+ void setTextInteractionFlags(Qt::TextInteractionFlags flags);
+ Qt::TextInteractionFlags textInteractionFlags() const;
+
+ QRect cursorRectangle() const;
+
+ QVariant inputMethodQuery(Qt::InputMethodQuery property) const;
+
+ qreal paintedWidth() const;
+ qreal paintedHeight() const;
+
+ Q_INVOKABLE QRectF positionToRectangle(int) const;
+ Q_INVOKABLE int positionAt(int x, int y) const;
+ Q_INVOKABLE void moveCursorSelection(int pos);
+ Q_INVOKABLE void moveCursorSelection(int pos, SelectionMode mode);
+
+ QRectF boundingRect() const;
+
+ bool isInputMethodComposing() const;
+
+Q_SIGNALS:
+ void textChanged(const QString &);
+ void paintedSizeChanged();
+ void cursorPositionChanged();
+ void cursorRectangleChanged();
+ void selectionStartChanged();
+ void selectionEndChanged();
+ void selectionChanged();
+ void colorChanged(const QColor &color);
+ void selectionColorChanged(const QColor &color);
+ void selectedTextColorChanged(const QColor &color);
+ void fontChanged(const QFont &font);
+ void horizontalAlignmentChanged(HAlignment alignment);
+ void verticalAlignmentChanged(VAlignment alignment);
+ void wrapModeChanged();
+ void lineCountChanged();
+ void textFormatChanged(TextFormat textFormat);
+ void readOnlyChanged(bool isReadOnly);
+ void cursorVisibleChanged(bool isCursorVisible);
+ void cursorDelegateChanged();
+ void activeFocusOnPressChanged(bool activeFocusOnPressed);
+ void persistentSelectionChanged(bool isPersistentSelection);
+ void textMarginChanged(qreal textMargin);
+ void selectByMouseChanged(bool selectByMouse);
+ void mouseSelectionModeChanged(SelectionMode mode);
+ void linkActivated(const QString &link);
+ void canPasteChanged();
+ void inputMethodComposingChanged();
+ void effectiveHorizontalAlignmentChanged();
+
+public Q_SLOTS:
+ void selectAll();
+ void selectWord();
+ void select(int start, int end);
+ void deselect();
+ bool isRightToLeft(int start, int end);
+#ifndef QT_NO_CLIPBOARD
+ void cut();
+ void copy();
+ void paste();
+#endif
+
+private Q_SLOTS:
+ void updateImgCache(const QRectF &rect);
+ void q_textChanged();
+ void updateSelectionMarkers();
+ void moveCursorDelegate();
+ void loadCursorDelegate();
+ void q_canPasteChanged();
+
+private:
+ void updateSize();
+ void updateTotalLines();
+
+protected:
+ virtual void geometryChanged(const QRectF &newGeometry,
+ const QRectF &oldGeometry);
+
+ bool event(QEvent *);
+ void keyPressEvent(QKeyEvent *);
+ void keyReleaseEvent(QKeyEvent *);
+ void focusInEvent(QFocusEvent *event);
+
+ // mouse filter?
+ void mousePressEvent(QGraphicsSceneMouseEvent *event);
+ void mouseReleaseEvent(QGraphicsSceneMouseEvent *event);
+ void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event);
+ void mouseMoveEvent(QGraphicsSceneMouseEvent *event);
+ void inputMethodEvent(QInputMethodEvent *e);
+ virtual void itemChange(ItemChange, const ItemChangeData &);
+
+ void paint(QPainter *);
+private:
+ Q_DISABLE_COPY(QSGTextEdit)
+ Q_DECLARE_PRIVATE(QSGTextEdit)
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QSGTextEdit)
+
+QT_END_HEADER
+
+#endif // QSGTEXTEDIT_P_H
diff --git a/src/declarative/items/qsgtextedit_p_p.h b/src/declarative/items/qsgtextedit_p_p.h
new file mode 100644
index 0000000000..63f4bbc341
--- /dev/null
+++ b/src/declarative/items/qsgtextedit_p_p.h
@@ -0,0 +1,143 @@
+// Commit: 27e4302b7f45f22180693d26747f419177c81e27
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGTEXTEDIT_P_P_H
+#define QSGTEXTEDIT_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 "qsgtextedit_p.h"
+#include "qsgimplicitsizeitem_p_p.h"
+
+#include <QtDeclarative/qdeclarative.h>
+
+QT_BEGIN_NAMESPACE
+class QTextLayout;
+class QTextDocument;
+class QTextControl;
+class QSGTextEditPrivate : public QSGImplicitSizePaintedItemPrivate
+{
+ Q_DECLARE_PUBLIC(QSGTextEdit)
+
+public:
+ QSGTextEditPrivate()
+ : color("black"), hAlign(QSGTextEdit::AlignLeft), vAlign(QSGTextEdit::AlignTop),
+ imgDirty(true), dirty(false), richText(false), cursorVisible(false), focusOnPress(true),
+ showInputPanelOnFocus(true), clickCausedFocus(false), persistentSelection(true),
+ requireImplicitWidth(false), selectByMouse(false), canPaste(false),
+ hAlignImplicit(true), rightToLeftText(false),
+ textMargin(0.0), lastSelectionStart(0), lastSelectionEnd(0), cursorComponent(0), cursor(0),
+ format(QSGTextEdit::AutoText), document(0), wrapMode(QSGTextEdit::NoWrap),
+ mouseSelectionMode(QSGTextEdit::SelectCharacters),
+ yoff(0)
+ {
+#ifdef Q_OS_SYMBIAN
+ if (QSysInfo::symbianVersion() == QSysInfo::SV_SF_1 || QSysInfo::symbianVersion() == QSysInfo::SV_SF_3) {
+ showInputPanelOnFocus = false;
+ }
+#endif
+ }
+
+ void init();
+
+ void updateDefaultTextOption();
+ void relayoutDocument();
+ void updateSelection();
+ bool determineHorizontalAlignment();
+ bool setHAlign(QSGTextEdit::HAlignment, bool forceAlign = false);
+ void mirrorChange();
+ qreal getImplicitWidth() const;
+
+ QString text;
+ QFont font;
+ QFont sourceFont;
+ QColor color;
+ QColor selectionColor;
+ QColor selectedTextColor;
+ QString style;
+ QColor styleColor;
+ QPixmap imgCache;
+ QPixmap imgStyleCache;
+ QSGTextEdit::HAlignment hAlign;
+ QSGTextEdit::VAlignment vAlign;
+
+ bool imgDirty : 1;
+ bool dirty : 1;
+ bool richText : 1;
+ bool cursorVisible : 1;
+ bool focusOnPress : 1;
+ bool showInputPanelOnFocus : 1;
+ bool clickCausedFocus : 1;
+ bool persistentSelection : 1;
+ bool requireImplicitWidth:1;
+ bool selectByMouse:1;
+ bool canPaste:1;
+ bool hAlignImplicit:1;
+ bool rightToLeftText:1;
+
+ qreal textMargin;
+ int lastSelectionStart;
+ int lastSelectionEnd;
+ QDeclarativeComponent* cursorComponent;
+ QSGItem* cursor;
+ QSGTextEdit::TextFormat format;
+ QTextDocument *document;
+ QTextControl *control;
+ QSGTextEdit::WrapMode wrapMode;
+ QSGTextEdit::SelectionMode mouseSelectionMode;
+ int lineCount;
+ int yoff;
+ QSize paintedSize;
+};
+
+QT_END_NAMESPACE
+
+#endif // QSGTEXTEDIT_P_P_H
diff --git a/src/declarative/items/qsgtextinput.cpp b/src/declarative/items/qsgtextinput.cpp
new file mode 100644
index 0000000000..1db4474d4a
--- /dev/null
+++ b/src/declarative/items/qsgtextinput.cpp
@@ -0,0 +1,1295 @@
+// Commit: 47712d1f330e4b22ce6dd30e7557288ef7f7fca0
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgtextinput_p.h"
+#include "qsgtextinput_p_p.h"
+#include "qsgcanvas.h"
+
+#include <private/qdeclarativeglobal_p.h>
+#include <private/qwidget_p.h>
+
+#include <QtDeclarative/qdeclarativeinfo.h>
+#include <QtGui/qgraphicssceneevent.h>
+#include <QtGui/qinputcontext.h>
+#include <QTextBoundaryFinder>
+#include <qstyle.h>
+
+QT_BEGIN_NAMESPACE
+
+QWidgetPrivate *qt_widget_private(QWidget *widget);
+
+QSGTextInput::QSGTextInput(QSGItem* parent)
+: QSGImplicitSizePaintedItem(*(new QSGTextInputPrivate), parent)
+{
+ Q_D(QSGTextInput);
+ d->init();
+}
+
+QSGTextInput::~QSGTextInput()
+{
+}
+
+QString QSGTextInput::text() const
+{
+ Q_D(const QSGTextInput);
+ return d->control->text();
+}
+
+void QSGTextInput::setText(const QString &s)
+{
+ Q_D(QSGTextInput);
+ if(s == text())
+ return;
+ d->control->setText(s);
+}
+
+QFont QSGTextInput::font() const
+{
+ Q_D(const QSGTextInput);
+ return d->sourceFont;
+}
+
+void QSGTextInput::setFont(const QFont &font)
+{
+ Q_D(QSGTextInput);
+ if (d->sourceFont == font)
+ return;
+
+ d->sourceFont = font;
+ QFont oldFont = d->font;
+ d->font = font;
+ if (d->font.pointSizeF() != -1) {
+ // 0.5pt resolution
+ qreal size = qRound(d->font.pointSizeF()*2.0);
+ d->font.setPointSizeF(size/2.0);
+ }
+ if (oldFont != d->font) {
+ d->control->setFont(d->font);
+ if(d->cursorItem){
+ d->cursorItem->setHeight(QFontMetrics(d->font).height());
+ moveCursor();
+ }
+ updateSize();
+ }
+ emit fontChanged(d->sourceFont);
+}
+
+QColor QSGTextInput::color() const
+{
+ Q_D(const QSGTextInput);
+ return d->color;
+}
+
+void QSGTextInput::setColor(const QColor &c)
+{
+ Q_D(QSGTextInput);
+ if (c != d->color) {
+ d->color = c;
+ update();
+ emit colorChanged(c);
+ }
+}
+
+QColor QSGTextInput::selectionColor() const
+{
+ Q_D(const QSGTextInput);
+ return d->selectionColor;
+}
+
+void QSGTextInput::setSelectionColor(const QColor &color)
+{
+ Q_D(QSGTextInput);
+ if (d->selectionColor == color)
+ return;
+
+ d->selectionColor = color;
+ QPalette p = d->control->palette();
+ p.setColor(QPalette::Highlight, d->selectionColor);
+ d->control->setPalette(p);
+ if (d->control->hasSelectedText())
+ update();
+ emit selectionColorChanged(color);
+}
+
+QColor QSGTextInput::selectedTextColor() const
+{
+ Q_D(const QSGTextInput);
+ return d->selectedTextColor;
+}
+
+void QSGTextInput::setSelectedTextColor(const QColor &color)
+{
+ Q_D(QSGTextInput);
+ if (d->selectedTextColor == color)
+ return;
+
+ d->selectedTextColor = color;
+ QPalette p = d->control->palette();
+ p.setColor(QPalette::HighlightedText, d->selectedTextColor);
+ d->control->setPalette(p);
+ if (d->control->hasSelectedText())
+ update();
+ emit selectedTextColorChanged(color);
+}
+
+QSGTextInput::HAlignment QSGTextInput::hAlign() const
+{
+ Q_D(const QSGTextInput);
+ return d->hAlign;
+}
+
+void QSGTextInput::setHAlign(HAlignment align)
+{
+ Q_D(QSGTextInput);
+ bool forceAlign = d->hAlignImplicit && d->effectiveLayoutMirror;
+ d->hAlignImplicit = false;
+ if (d->setHAlign(align, forceAlign) && isComponentComplete()) {
+ updateRect();
+ d->updateHorizontalScroll();
+ }
+}
+
+void QSGTextInput::resetHAlign()
+{
+ Q_D(QSGTextInput);
+ d->hAlignImplicit = true;
+ if (d->determineHorizontalAlignment() && isComponentComplete()) {
+ updateRect();
+ d->updateHorizontalScroll();
+ }
+}
+
+QSGTextInput::HAlignment QSGTextInput::effectiveHAlign() const
+{
+ Q_D(const QSGTextInput);
+ QSGTextInput::HAlignment effectiveAlignment = d->hAlign;
+ if (!d->hAlignImplicit && d->effectiveLayoutMirror) {
+ switch (d->hAlign) {
+ case QSGTextInput::AlignLeft:
+ effectiveAlignment = QSGTextInput::AlignRight;
+ break;
+ case QSGTextInput::AlignRight:
+ effectiveAlignment = QSGTextInput::AlignLeft;
+ break;
+ default:
+ break;
+ }
+ }
+ return effectiveAlignment;
+}
+
+bool QSGTextInputPrivate::setHAlign(QSGTextInput::HAlignment alignment, bool forceAlign)
+{
+ Q_Q(QSGTextInput);
+ if ((hAlign != alignment || forceAlign) && alignment <= QSGTextInput::AlignHCenter) { // justify not supported
+ QSGTextInput::HAlignment oldEffectiveHAlign = q->effectiveHAlign();
+ hAlign = alignment;
+ emit q->horizontalAlignmentChanged(alignment);
+ if (oldEffectiveHAlign != q->effectiveHAlign())
+ emit q->effectiveHorizontalAlignmentChanged();
+ return true;
+ }
+ return false;
+}
+
+bool QSGTextInputPrivate::determineHorizontalAlignment()
+{
+ if (hAlignImplicit) {
+ // if no explicit alignment has been set, follow the natural layout direction of the text
+ QString text = control->text();
+ bool isRightToLeft = text.isEmpty() ? QApplication::keyboardInputDirection() == Qt::RightToLeft : text.isRightToLeft();
+ return setHAlign(isRightToLeft ? QSGTextInput::AlignRight : QSGTextInput::AlignLeft);
+ }
+ return false;
+}
+
+void QSGTextInputPrivate::mirrorChange()
+{
+ Q_Q(QSGTextInput);
+ if (q->isComponentComplete()) {
+ if (!hAlignImplicit && (hAlign == QSGTextInput::AlignRight || hAlign == QSGTextInput::AlignLeft)) {
+ q->updateRect();
+ updateHorizontalScroll();
+ emit q->effectiveHorizontalAlignmentChanged();
+ }
+ }
+}
+
+bool QSGTextInput::isReadOnly() const
+{
+ Q_D(const QSGTextInput);
+ return d->control->isReadOnly();
+}
+
+void QSGTextInput::setReadOnly(bool ro)
+{
+ Q_D(QSGTextInput);
+ if (d->control->isReadOnly() == ro)
+ return;
+
+ setFlag(QSGItem::ItemAcceptsInputMethod, !ro);
+ d->control->setReadOnly(ro);
+
+ emit readOnlyChanged(ro);
+}
+
+int QSGTextInput::maxLength() const
+{
+ Q_D(const QSGTextInput);
+ return d->control->maxLength();
+}
+
+void QSGTextInput::setMaxLength(int ml)
+{
+ Q_D(QSGTextInput);
+ if (d->control->maxLength() == ml)
+ return;
+
+ d->control->setMaxLength(ml);
+
+ emit maximumLengthChanged(ml);
+}
+
+bool QSGTextInput::isCursorVisible() const
+{
+ Q_D(const QSGTextInput);
+ return d->cursorVisible;
+}
+
+void QSGTextInput::setCursorVisible(bool on)
+{
+ Q_D(QSGTextInput);
+ if (d->cursorVisible == on)
+ return;
+ d->cursorVisible = on;
+ d->control->setCursorBlinkPeriod(on?QApplication::cursorFlashTime():0);
+ QRect r = d->control->cursorRect();
+ if (d->control->inputMask().isEmpty())
+ updateRect(r);
+ else
+ updateRect();
+ emit cursorVisibleChanged(d->cursorVisible);
+}
+
+int QSGTextInput::cursorPosition() const
+{
+ Q_D(const QSGTextInput);
+ return d->control->cursor();
+}
+void QSGTextInput::setCursorPosition(int cp)
+{
+ Q_D(QSGTextInput);
+ if (cp < 0 || cp > d->control->text().length())
+ return;
+ d->control->moveCursor(cp);
+}
+
+QRect QSGTextInput::cursorRectangle() const
+{
+ Q_D(const QSGTextInput);
+ QRect r = d->control->cursorRect();
+ // Scroll and make consistent with TextEdit
+ // QLineControl inexplicably adds 1 to the height and horizontal padding
+ // for unicode direction markers.
+ r.adjust(5 - d->hscroll, 0, -4 - d->hscroll, -1);
+ return r;
+}
+
+int QSGTextInput::selectionStart() const
+{
+ Q_D(const QSGTextInput);
+ return d->lastSelectionStart;
+}
+
+int QSGTextInput::selectionEnd() const
+{
+ Q_D(const QSGTextInput);
+ return d->lastSelectionEnd;
+}
+
+void QSGTextInput::select(int start, int end)
+{
+ Q_D(QSGTextInput);
+ if (start < 0 || end < 0 || start > d->control->text().length() || end > d->control->text().length())
+ return;
+ d->control->setSelection(start, end-start);
+}
+
+QString QSGTextInput::selectedText() const
+{
+ Q_D(const QSGTextInput);
+ return d->control->selectedText();
+}
+
+bool QSGTextInput::focusOnPress() const
+{
+ Q_D(const QSGTextInput);
+ return d->focusOnPress;
+}
+
+void QSGTextInput::setFocusOnPress(bool b)
+{
+ Q_D(QSGTextInput);
+ if (d->focusOnPress == b)
+ return;
+
+ d->focusOnPress = b;
+
+ emit activeFocusOnPressChanged(d->focusOnPress);
+}
+
+bool QSGTextInput::autoScroll() const
+{
+ Q_D(const QSGTextInput);
+ return d->autoScroll;
+}
+
+void QSGTextInput::setAutoScroll(bool b)
+{
+ Q_D(QSGTextInput);
+ if (d->autoScroll == b)
+ return;
+
+ d->autoScroll = b;
+ //We need to repaint so that the scrolling is taking into account.
+ updateSize(true);
+ d->updateHorizontalScroll();
+ emit autoScrollChanged(d->autoScroll);
+}
+
+#ifndef QT_NO_VALIDATOR
+QValidator* QSGTextInput::validator() const
+{
+ Q_D(const QSGTextInput);
+ //###const cast isn't good, but needed for property system?
+ return const_cast<QValidator*>(d->control->validator());
+}
+
+void QSGTextInput::setValidator(QValidator* v)
+{
+ Q_D(QSGTextInput);
+ if (d->control->validator() == v)
+ return;
+
+ d->control->setValidator(v);
+ if(!d->control->hasAcceptableInput()){
+ d->oldValidity = false;
+ emit acceptableInputChanged();
+ }
+
+ emit validatorChanged();
+}
+#endif // QT_NO_VALIDATOR
+
+QString QSGTextInput::inputMask() const
+{
+ Q_D(const QSGTextInput);
+ return d->control->inputMask();
+}
+
+void QSGTextInput::setInputMask(const QString &im)
+{
+ Q_D(QSGTextInput);
+ if (d->control->inputMask() == im)
+ return;
+
+ d->control->setInputMask(im);
+ emit inputMaskChanged(d->control->inputMask());
+}
+
+bool QSGTextInput::hasAcceptableInput() const
+{
+ Q_D(const QSGTextInput);
+ return d->control->hasAcceptableInput();
+}
+
+void QSGTextInputPrivate::updateInputMethodHints()
+{
+ Q_Q(QSGTextInput);
+ Qt::InputMethodHints hints = inputMethodHints;
+ uint echo = control->echoMode();
+ if (echo == QSGTextInput::Password || echo == QSGTextInput::NoEcho)
+ hints |= Qt::ImhHiddenText;
+ else if (echo == QSGTextInput::PasswordEchoOnEdit)
+ hints &= ~Qt::ImhHiddenText;
+ if (echo != QSGTextInput::Normal)
+ hints |= (Qt::ImhNoAutoUppercase | Qt::ImhNoPredictiveText);
+ q->setInputMethodHints(hints);
+}
+
+QSGTextInput::EchoMode QSGTextInput::echoMode() const
+{
+ Q_D(const QSGTextInput);
+ return (QSGTextInput::EchoMode)d->control->echoMode();
+}
+
+void QSGTextInput::setEchoMode(QSGTextInput::EchoMode echo)
+{
+ Q_D(QSGTextInput);
+ if (echoMode() == echo)
+ return;
+ d->control->setEchoMode((uint)echo);
+ d->updateInputMethodHints();
+ q_textChanged();
+ emit echoModeChanged(echoMode());
+}
+
+Qt::InputMethodHints QSGTextInput::imHints() const
+{
+ Q_D(const QSGTextInput);
+ return d->inputMethodHints;
+}
+
+void QSGTextInput::setIMHints(Qt::InputMethodHints hints)
+{
+ Q_D(QSGTextInput);
+ if (d->inputMethodHints == hints)
+ return;
+ d->inputMethodHints = hints;
+ d->updateInputMethodHints();
+}
+
+QDeclarativeComponent* QSGTextInput::cursorDelegate() const
+{
+ Q_D(const QSGTextInput);
+ return d->cursorComponent;
+}
+
+void QSGTextInput::setCursorDelegate(QDeclarativeComponent* c)
+{
+ Q_D(QSGTextInput);
+ if (d->cursorComponent == c)
+ return;
+
+ d->cursorComponent = c;
+ if(!c){
+ //note that the components are owned by something else
+ disconnect(d->control, SIGNAL(cursorPositionChanged(int,int)),
+ this, SLOT(moveCursor()));
+ disconnect(d->control, SIGNAL(updateMicroFocus()),
+ this, SLOT(moveCursor()));
+ delete d->cursorItem;
+ }else{
+ d->startCreatingCursor();
+ }
+
+ emit cursorDelegateChanged();
+}
+
+void QSGTextInputPrivate::startCreatingCursor()
+{
+ Q_Q(QSGTextInput);
+ q->connect(control, SIGNAL(cursorPositionChanged(int,int)),
+ q, SLOT(moveCursor()), Qt::UniqueConnection);
+ q->connect(control, SIGNAL(updateMicroFocus()),
+ q, SLOT(moveCursor()), Qt::UniqueConnection);
+ if(cursorComponent->isReady()){
+ q->createCursor();
+ }else if(cursorComponent->isLoading()){
+ q->connect(cursorComponent, SIGNAL(statusChanged(int)),
+ q, SLOT(createCursor()));
+ }else {//isError
+ qmlInfo(q, cursorComponent->errors()) << QSGTextInput::tr("Could not load cursor delegate");
+ }
+}
+
+void QSGTextInput::createCursor()
+{
+ Q_D(QSGTextInput);
+ if(d->cursorComponent->isError()){
+ qmlInfo(this, d->cursorComponent->errors()) << tr("Could not load cursor delegate");
+ return;
+ }
+
+ if(!d->cursorComponent->isReady())
+ return;
+
+ if(d->cursorItem)
+ delete d->cursorItem;
+ d->cursorItem = qobject_cast<QSGItem*>(d->cursorComponent->create());
+ if(!d->cursorItem){
+ qmlInfo(this, d->cursorComponent->errors()) << tr("Could not instantiate cursor delegate");
+ return;
+ }
+
+ QDeclarative_setParent_noEvent(d->cursorItem, this);
+ d->cursorItem->setParentItem(this);
+ d->cursorItem->setX(d->control->cursorToX());
+ d->cursorItem->setHeight(d->control->height()-1); // -1 to counter QLineControl's +1 which is not consistent with Text.
+}
+
+void QSGTextInput::moveCursor()
+{
+ Q_D(QSGTextInput);
+ if(!d->cursorItem)
+ return;
+ d->updateHorizontalScroll();
+ d->cursorItem->setX(d->control->cursorToX() - d->hscroll);
+}
+
+QRectF QSGTextInput::positionToRectangle(int pos) const
+{
+ Q_D(const QSGTextInput);
+ if (pos > d->control->cursorPosition())
+ pos += d->control->preeditAreaText().length();
+ return QRectF(d->control->cursorToX(pos)-d->hscroll,
+ 0.0,
+ d->control->cursorWidth(),
+ cursorRectangle().height());
+}
+
+int QSGTextInput::positionAt(int x) const
+{
+ return positionAt(x, CursorBetweenCharacters);
+}
+
+int QSGTextInput::positionAt(int x, CursorPosition position) const
+{
+ Q_D(const QSGTextInput);
+ int pos = d->control->xToPos(x + d->hscroll, QTextLine::CursorPosition(position));
+ const int cursor = d->control->cursor();
+ if (pos > cursor) {
+ const int preeditLength = d->control->preeditAreaText().length();
+ pos = pos > cursor + preeditLength
+ ? pos - preeditLength
+ : cursor;
+ }
+ return pos;
+}
+
+void QSGTextInput::keyPressEvent(QKeyEvent* ev)
+{
+ Q_D(QSGTextInput);
+ // Don't allow MacOSX up/down support, and we don't allow a completer.
+ bool ignore = (ev->key() == Qt::Key_Up || ev->key() == Qt::Key_Down) && ev->modifiers() == Qt::NoModifier;
+ if (!ignore && (d->lastSelectionStart == d->lastSelectionEnd) && (ev->key() == Qt::Key_Right || ev->key() == Qt::Key_Left)) {
+ // Ignore when moving off the end unless there is a selection,
+ // because then moving will do something (deselect).
+ int cursorPosition = d->control->cursor();
+ if (cursorPosition == 0)
+ ignore = ev->key() == (d->control->layoutDirection() == Qt::LeftToRight ? Qt::Key_Left : Qt::Key_Right);
+ if (cursorPosition == d->control->text().length())
+ ignore = ev->key() == (d->control->layoutDirection() == Qt::LeftToRight ? Qt::Key_Right : Qt::Key_Left);
+ }
+ if (ignore) {
+ ev->ignore();
+ } else {
+ d->control->processKeyEvent(ev);
+ }
+ if (!ev->isAccepted())
+ QSGPaintedItem::keyPressEvent(ev);
+}
+
+void QSGTextInput::inputMethodEvent(QInputMethodEvent *ev)
+{
+ Q_D(QSGTextInput);
+ const bool wasComposing = d->control->preeditAreaText().length() > 0;
+ if (d->control->isReadOnly()) {
+ ev->ignore();
+ } else {
+ d->control->processInputMethodEvent(ev);
+ updateSize();
+ d->updateHorizontalScroll();
+ }
+ if (!ev->isAccepted())
+ QSGPaintedItem::inputMethodEvent(ev);
+
+ if (wasComposing != (d->control->preeditAreaText().length() > 0))
+ emit inputMethodComposingChanged();
+}
+
+void QSGTextInput::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(QSGTextInput);
+ if (d->sendMouseEventToInputContext(event, QEvent::MouseButtonDblClick))
+ return;
+ if (d->selectByMouse) {
+ int cursor = d->xToPos(event->pos().x());
+ d->control->selectWordAtPos(cursor);
+ event->setAccepted(true);
+ } else {
+ QSGPaintedItem::mouseDoubleClickEvent(event);
+ }
+}
+
+void QSGTextInput::mousePressEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(QSGTextInput);
+ if (d->sendMouseEventToInputContext(event, QEvent::MouseButtonPress))
+ return;
+ if(d->focusOnPress){
+ bool hadActiveFocus = hasActiveFocus();
+ forceActiveFocus();
+ if (d->showInputPanelOnFocus) {
+ if (hasActiveFocus() && hadActiveFocus && !isReadOnly()) {
+ // re-open input panel on press if already focused
+ openSoftwareInputPanel();
+ }
+ } else { // show input panel on click
+ if (hasActiveFocus() && !hadActiveFocus) {
+ d->clickCausedFocus = true;
+ }
+ }
+ }
+ if (d->selectByMouse) {
+ setKeepMouseGrab(false);
+ d->selectPressed = true;
+ d->pressPos = event->pos();
+ }
+ bool mark = (event->modifiers() & Qt::ShiftModifier) && d->selectByMouse;
+ int cursor = d->xToPos(event->pos().x());
+ d->control->moveCursor(cursor, mark);
+ event->setAccepted(true);
+}
+
+void QSGTextInput::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(QSGTextInput);
+ if (d->sendMouseEventToInputContext(event, QEvent::MouseMove))
+ return;
+ if (d->selectPressed) {
+ if (qAbs(int(event->pos().x() - d->pressPos.x())) > QApplication::startDragDistance())
+ setKeepMouseGrab(true);
+ moveCursorSelection(d->xToPos(event->pos().x()), d->mouseSelectionMode);
+ event->setAccepted(true);
+ } else {
+ QSGPaintedItem::mouseMoveEvent(event);
+ }
+}
+
+void QSGTextInput::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(QSGTextInput);
+ if (d->sendMouseEventToInputContext(event, QEvent::MouseButtonRelease))
+ return;
+ if (d->selectPressed) {
+ d->selectPressed = false;
+ setKeepMouseGrab(false);
+ }
+ if (!d->showInputPanelOnFocus) { // input panel on click
+ if (d->focusOnPress && !isReadOnly() && boundingRect().contains(event->pos())) {
+ if (canvas() && canvas() == qApp->focusWidget()) {
+ qt_widget_private(canvas())->handleSoftwareInputPanel(event->button(), d->clickCausedFocus);
+ }
+ }
+ }
+ d->clickCausedFocus = false;
+ d->control->processEvent(event);
+ if (!event->isAccepted())
+ QSGPaintedItem::mouseReleaseEvent(event);
+}
+
+bool QSGTextInputPrivate::sendMouseEventToInputContext(
+ QGraphicsSceneMouseEvent *event, QEvent::Type eventType)
+{
+#if !defined QT_NO_IM
+ if (event->widget() && control->composeMode()) {
+ int tmp_cursor = xToPos(event->pos().x());
+ int mousePos = tmp_cursor - control->cursor();
+ if (mousePos < 0 || mousePos > control->preeditAreaText().length()) {
+ mousePos = -1;
+ // don't send move events outside the preedit area
+ if (eventType == QEvent::MouseMove)
+ return true;
+ }
+
+ QInputContext *qic = event->widget()->inputContext();
+ if (qic) {
+ QMouseEvent mouseEvent(
+ eventType,
+ event->widget()->mapFromGlobal(event->screenPos()),
+ event->screenPos(),
+ event->button(),
+ event->buttons(),
+ event->modifiers());
+ // may be causing reset() in some input methods
+ qic->mouseHandler(mousePos, &mouseEvent);
+ event->setAccepted(mouseEvent.isAccepted());
+ }
+ if (!control->preeditAreaText().isEmpty())
+ return true;
+ }
+#else
+ Q_UNUSED(event);
+ Q_UNUSED(eventType)
+#endif
+
+ return false;
+}
+
+void QSGTextInput::mouseUngrabEvent()
+{
+ Q_D(QSGTextInput);
+ d->selectPressed = false;
+ setKeepMouseGrab(false);
+}
+
+bool QSGTextInput::event(QEvent* ev)
+{
+ Q_D(QSGTextInput);
+ //Anything we don't deal with ourselves, pass to the control
+ bool handled = false;
+ switch(ev->type()){
+ case QEvent::KeyPress:
+ case QEvent::KeyRelease://###Should the control be doing anything with release?
+ case QEvent::InputMethod:
+ case QEvent::GraphicsSceneMousePress:
+ case QEvent::GraphicsSceneMouseMove:
+ case QEvent::GraphicsSceneMouseRelease:
+ case QEvent::GraphicsSceneMouseDoubleClick:
+ break;
+ default:
+ handled = d->control->processEvent(ev);
+ }
+ if(!handled)
+ handled = QSGPaintedItem::event(ev);
+ return handled;
+}
+
+void QSGTextInput::geometryChanged(const QRectF &newGeometry,
+ const QRectF &oldGeometry)
+{
+ Q_D(QSGTextInput);
+ if (newGeometry.width() != oldGeometry.width()) {
+ updateSize();
+ d->updateHorizontalScroll();
+ }
+ QSGPaintedItem::geometryChanged(newGeometry, oldGeometry);
+}
+
+int QSGTextInputPrivate::calculateTextWidth()
+{
+ return qRound(control->naturalTextWidth());
+}
+
+void QSGTextInputPrivate::updateHorizontalScroll()
+{
+ Q_Q(QSGTextInput);
+ const int preeditLength = control->preeditAreaText().length();
+ int cix = qRound(control->cursorToX(control->cursor() + preeditLength));
+ QRect br(q->boundingRect().toRect());
+ int widthUsed = calculateTextWidth();
+
+ QSGTextInput::HAlignment effectiveHAlign = q->effectiveHAlign();
+ if (autoScroll) {
+ if (widthUsed <= br.width()) {
+ // text fits in br; use hscroll for alignment
+ switch (effectiveHAlign & ~(Qt::AlignAbsolute|Qt::AlignVertical_Mask)) {
+ case Qt::AlignRight:
+ hscroll = widthUsed - br.width() - 1;
+ break;
+ case Qt::AlignHCenter:
+ hscroll = (widthUsed - br.width()) / 2;
+ break;
+ default:
+ // Left
+ hscroll = 0;
+ break;
+ }
+ } else if (cix - hscroll >= br.width()) {
+ // text doesn't fit, cursor is to the right of br (scroll right)
+ hscroll = cix - br.width() + 1;
+ } else if (cix - hscroll < 0 && hscroll < widthUsed) {
+ // text doesn't fit, cursor is to the left of br (scroll left)
+ hscroll = cix;
+ } else if (widthUsed - hscroll < br.width()) {
+ // text doesn't fit, text document is to the left of br; align
+ // right
+ hscroll = widthUsed - br.width() + 1;
+ }
+ if (preeditLength > 0) {
+ // check to ensure long pre-edit text doesn't push the cursor
+ // off to the left
+ cix = qRound(control->cursorToX(
+ control->cursor() + qMax(0, control->preeditCursor() - 1)));
+ if (cix < hscroll)
+ hscroll = cix;
+ }
+ } else {
+ switch (effectiveHAlign) {
+ case QSGTextInput::AlignRight:
+ hscroll = q->width() - widthUsed;
+ break;
+ case QSGTextInput::AlignHCenter:
+ hscroll = (q->width() - widthUsed) / 2;
+ break;
+ default:
+ // Left
+ hscroll = 0;
+ break;
+ }
+ }
+}
+
+void QSGTextInput::paint(QPainter *p)
+{
+ // XXX todo
+ QRect r(0, 0, width(), height());
+
+ Q_D(QSGTextInput);
+ p->setRenderHint(QPainter::TextAntialiasing, true);
+ p->save();
+ p->setPen(QPen(d->color));
+ int flags = QLineControl::DrawText;
+ if(!isReadOnly() && d->cursorVisible && !d->cursorItem)
+ flags |= QLineControl::DrawCursor;
+ if (d->control->hasSelectedText())
+ flags |= QLineControl::DrawSelections;
+ QPoint offset = QPoint(0,0);
+ QFontMetrics fm = QFontMetrics(d->font);
+ QRect br(boundingRect().toRect());
+ if (d->autoScroll) {
+ // the y offset is there to keep the baseline constant in case we have script changes in the text.
+ offset = br.topLeft() - QPoint(d->hscroll, d->control->ascent() - fm.ascent());
+ } else {
+ offset = QPoint(d->hscroll, 0);
+ }
+ d->control->draw(p, offset, r, flags);
+ p->restore();
+}
+
+QVariant QSGTextInput::inputMethodQuery(Qt::InputMethodQuery property) const
+{
+ Q_D(const QSGTextInput);
+ switch(property) {
+ case Qt::ImMicroFocus:
+ return cursorRectangle();
+ case Qt::ImFont:
+ return font();
+ case Qt::ImCursorPosition:
+ return QVariant(d->control->cursor());
+ case Qt::ImSurroundingText:
+ if (d->control->echoMode() == PasswordEchoOnEdit && !d->control->passwordEchoEditing())
+ return QVariant(displayText());
+ else
+ return QVariant(text());
+ case Qt::ImCurrentSelection:
+ return QVariant(selectedText());
+ case Qt::ImMaximumTextLength:
+ return QVariant(maxLength());
+ case Qt::ImAnchorPosition:
+ if (d->control->selectionStart() == d->control->selectionEnd())
+ return QVariant(d->control->cursor());
+ else if (d->control->selectionStart() == d->control->cursor())
+ return QVariant(d->control->selectionEnd());
+ else
+ return QVariant(d->control->selectionStart());
+ default:
+ return QVariant();
+ }
+}
+
+void QSGTextInput::deselect()
+{
+ Q_D(QSGTextInput);
+ d->control->deselect();
+}
+
+void QSGTextInput::selectAll()
+{
+ Q_D(QSGTextInput);
+ d->control->setSelection(0, d->control->text().length());
+}
+
+bool QSGTextInput::isRightToLeft(int start, int end)
+{
+ Q_D(QSGTextInput);
+ if (start > end) {
+ qmlInfo(this) << "isRightToLeft(start, end) called with the end property being smaller than the start.";
+ return false;
+ } else {
+ return d->control->text().mid(start, end - start).isRightToLeft();
+ }
+}
+
+#ifndef QT_NO_CLIPBOARD
+void QSGTextInput::cut()
+{
+ Q_D(QSGTextInput);
+ d->control->copy();
+ d->control->del();
+}
+
+void QSGTextInput::copy()
+{
+ Q_D(QSGTextInput);
+ d->control->copy();
+}
+
+void QSGTextInput::paste()
+{
+ Q_D(QSGTextInput);
+ if (!d->control->isReadOnly())
+ d->control->paste();
+}
+#endif // QT_NO_CLIPBOARD
+
+void QSGTextInput::selectWord()
+{
+ Q_D(QSGTextInput);
+ d->control->selectWordAtPos(d->control->cursor());
+}
+
+QString QSGTextInput::passwordCharacter() const
+{
+ Q_D(const QSGTextInput);
+ return QString(d->control->passwordCharacter());
+}
+
+void QSGTextInput::setPasswordCharacter(const QString &str)
+{
+ Q_D(QSGTextInput);
+ if(str.length() < 1)
+ return;
+ d->control->setPasswordCharacter(str.constData()[0]);
+ EchoMode echoMode_ = echoMode();
+ if (echoMode_ == Password || echoMode_ == PasswordEchoOnEdit) {
+ updateSize();
+ }
+ emit passwordCharacterChanged();
+}
+
+QString QSGTextInput::displayText() const
+{
+ Q_D(const QSGTextInput);
+ return d->control->displayText();
+}
+
+bool QSGTextInput::selectByMouse() const
+{
+ Q_D(const QSGTextInput);
+ return d->selectByMouse;
+}
+
+void QSGTextInput::setSelectByMouse(bool on)
+{
+ Q_D(QSGTextInput);
+ if (d->selectByMouse != on) {
+ d->selectByMouse = on;
+ emit selectByMouseChanged(on);
+ }
+}
+
+QSGTextInput::SelectionMode QSGTextInput::mouseSelectionMode() const
+{
+ Q_D(const QSGTextInput);
+ return d->mouseSelectionMode;
+}
+
+void QSGTextInput::setMouseSelectionMode(SelectionMode mode)
+{
+ Q_D(QSGTextInput);
+ if (d->mouseSelectionMode != mode) {
+ d->mouseSelectionMode = mode;
+ emit mouseSelectionModeChanged(mode);
+ }
+}
+
+bool QSGTextInput::canPaste() const
+{
+ Q_D(const QSGTextInput);
+ return d->canPaste;
+}
+
+void QSGTextInput::moveCursorSelection(int position)
+{
+ Q_D(QSGTextInput);
+ d->control->moveCursor(position, true);
+ d->updateHorizontalScroll();
+}
+
+void QSGTextInput::moveCursorSelection(int pos, SelectionMode mode)
+{
+ Q_D(QSGTextInput);
+
+ if (mode == SelectCharacters) {
+ d->control->moveCursor(pos, true);
+ } else if (pos != d->control->cursor()){
+ const int cursor = d->control->cursor();
+ int anchor;
+ if (!d->control->hasSelectedText())
+ anchor = d->control->cursor();
+ else if (d->control->selectionStart() == d->control->cursor())
+ anchor = d->control->selectionEnd();
+ else
+ anchor = d->control->selectionStart();
+
+ if (anchor < pos || (anchor == pos && cursor < pos)) {
+ const QString text = d->control->text();
+ QTextBoundaryFinder finder(QTextBoundaryFinder::Word, text);
+ finder.setPosition(anchor);
+
+ const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons();
+ if (anchor < text.length() && (!(reasons & QTextBoundaryFinder::StartWord)
+ || ((reasons & QTextBoundaryFinder::EndWord) && anchor > cursor))) {
+ finder.toPreviousBoundary();
+ }
+ anchor = finder.position() != -1 ? finder.position() : 0;
+
+ finder.setPosition(pos);
+ if (pos > 0 && !finder.boundaryReasons())
+ finder.toNextBoundary();
+ const int cursor = finder.position() != -1 ? finder.position() : text.length();
+
+ d->control->setSelection(anchor, cursor - anchor);
+ } else if (anchor > pos || (anchor == pos && cursor > pos)) {
+ const QString text = d->control->text();
+ QTextBoundaryFinder finder(QTextBoundaryFinder::Word, text);
+ finder.setPosition(anchor);
+
+ const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons();
+ if (anchor > 0 && (!(reasons & QTextBoundaryFinder::EndWord)
+ || ((reasons & QTextBoundaryFinder::StartWord) && anchor < cursor))) {
+ finder.toNextBoundary();
+ }
+
+ anchor = finder.position() != -1 ? finder.position() : text.length();
+
+ finder.setPosition(pos);
+ if (pos < text.length() && !finder.boundaryReasons())
+ finder.toPreviousBoundary();
+ const int cursor = finder.position() != -1 ? finder.position() : 0;
+
+ d->control->setSelection(anchor, cursor - anchor);
+ }
+ }
+}
+
+void QSGTextInput::openSoftwareInputPanel()
+{
+ QEvent event(QEvent::RequestSoftwareInputPanel);
+ if (qApp) {
+ if (canvas() && canvas() == qApp->focusWidget()) {
+ QEvent event(QEvent::RequestSoftwareInputPanel);
+ QApplication::sendEvent(canvas(), &event);
+ }
+ }
+}
+
+void QSGTextInput::closeSoftwareInputPanel()
+{
+ if (qApp) {
+ if (canvas() && canvas() == qApp->focusWidget()) {
+ QEvent event(QEvent::CloseSoftwareInputPanel);
+ QApplication::sendEvent(canvas(), &event);
+ }
+ }
+}
+
+void QSGTextInput::focusInEvent(QFocusEvent *event)
+{
+ Q_D(const QSGTextInput);
+ if (d->showInputPanelOnFocus) {
+ if (d->focusOnPress && !isReadOnly()) {
+ openSoftwareInputPanel();
+ }
+ }
+ QSGPaintedItem::focusInEvent(event);
+}
+
+void QSGTextInput::itemChange(ItemChange change, const ItemChangeData &value)
+{
+ Q_D(QSGTextInput);
+ if (change == ItemActiveFocusHasChanged) {
+ bool hasFocus = value.boolValue;
+ d->focused = hasFocus;
+ setCursorVisible(hasFocus && d->canvas && d->canvas->hasFocus());
+ if(echoMode() == QSGTextInput::PasswordEchoOnEdit && !hasFocus)
+ d->control->updatePasswordEchoEditing(false);//QLineControl sets it on key events, but doesn't deal with focus events
+ if (!hasFocus)
+ d->control->deselect();
+ }
+ QSGItem::itemChange(change, value);
+}
+
+bool QSGTextInput::isInputMethodComposing() const
+{
+ Q_D(const QSGTextInput);
+ return d->control->preeditAreaText().length() > 0;
+}
+
+void QSGTextInputPrivate::init()
+{
+ Q_Q(QSGTextInput);
+ control->setParent(q);//Now mandatory due to accessibility changes
+ control->setCursorWidth(1);
+ control->setPasswordCharacter(QLatin1Char('*'));
+ q->setSmooth(smooth);
+ q->setAcceptedMouseButtons(Qt::LeftButton);
+ q->setFlag(QSGItem::ItemAcceptsInputMethod);
+ q->connect(control, SIGNAL(cursorPositionChanged(int,int)),
+ q, SLOT(cursorPosChanged()));
+ q->connect(control, SIGNAL(selectionChanged()),
+ q, SLOT(selectionChanged()));
+ q->connect(control, SIGNAL(textChanged(QString)),
+ q, SLOT(q_textChanged()));
+ q->connect(control, SIGNAL(accepted()),
+ q, SIGNAL(accepted()));
+ q->connect(control, SIGNAL(updateNeeded(QRect)),
+ q, SLOT(updateRect(QRect)));
+#ifndef QT_NO_CLIPBOARD
+ q->connect(q, SIGNAL(readOnlyChanged(bool)),
+ q, SLOT(q_canPasteChanged()));
+ q->connect(QApplication::clipboard(), SIGNAL(dataChanged()),
+ q, SLOT(q_canPasteChanged()));
+ canPaste = !control->isReadOnly() && QApplication::clipboard()->text().length() != 0;
+#endif // QT_NO_CLIPBOARD
+ q->connect(control, SIGNAL(updateMicroFocus()),
+ q, SLOT(updateMicroFocus()));
+ q->connect(control, SIGNAL(displayTextChanged(QString)),
+ q, SLOT(updateRect()));
+ q->updateSize();
+ oldValidity = control->hasAcceptableInput();
+ lastSelectionStart = 0;
+ lastSelectionEnd = 0;
+ QPalette p = control->palette();
+ selectedTextColor = p.color(QPalette::HighlightedText);
+ selectionColor = p.color(QPalette::Highlight);
+ determineHorizontalAlignment();
+}
+
+void QSGTextInput::cursorPosChanged()
+{
+ Q_D(QSGTextInput);
+ d->updateHorizontalScroll();
+ updateRect();//TODO: Only update rect between pos's
+ updateMicroFocus();
+ emit cursorPositionChanged();
+ // XXX todo - not in 4.8?
+#if 0
+ d->control->resetCursorBlinkTimer();
+#endif
+
+ if(!d->control->hasSelectedText()){
+ if(d->lastSelectionStart != d->control->cursor()){
+ d->lastSelectionStart = d->control->cursor();
+ emit selectionStartChanged();
+ }
+ if(d->lastSelectionEnd != d->control->cursor()){
+ d->lastSelectionEnd = d->control->cursor();
+ emit selectionEndChanged();
+ }
+ }
+}
+
+void QSGTextInput::selectionChanged()
+{
+ Q_D(QSGTextInput);
+ updateRect();//TODO: Only update rect in selection
+ emit selectedTextChanged();
+
+ if(d->lastSelectionStart != d->control->selectionStart()){
+ d->lastSelectionStart = d->control->selectionStart();
+ if(d->lastSelectionStart == -1)
+ d->lastSelectionStart = d->control->cursor();
+ emit selectionStartChanged();
+ }
+ if(d->lastSelectionEnd != d->control->selectionEnd()){
+ d->lastSelectionEnd = d->control->selectionEnd();
+ if(d->lastSelectionEnd == -1)
+ d->lastSelectionEnd = d->control->cursor();
+ emit selectionEndChanged();
+ }
+}
+
+void QSGTextInput::q_textChanged()
+{
+ Q_D(QSGTextInput);
+ updateSize();
+ d->determineHorizontalAlignment();
+ d->updateHorizontalScroll();
+ updateMicroFocus();
+ emit textChanged();
+ emit displayTextChanged();
+ if(hasAcceptableInput() != d->oldValidity){
+ d->oldValidity = hasAcceptableInput();
+ emit acceptableInputChanged();
+ }
+}
+
+void QSGTextInput::updateRect(const QRect &r)
+{
+ Q_D(QSGTextInput);
+ if(r == QRect())
+ update();
+ else
+ update(QRect(r.x() - d->hscroll, r.y(), r.width(), r.height()));
+}
+
+QRectF QSGTextInput::boundingRect() const
+{
+ Q_D(const QSGTextInput);
+ QRectF r = QSGPaintedItem::boundingRect();
+
+ int cursorWidth = d->cursorItem ? d->cursorItem->width() : d->control->cursorWidth();
+
+ // Could include font max left/right bearings to either side of rectangle.
+
+ r.setRight(r.right() + cursorWidth);
+ return r;
+}
+
+void QSGTextInput::updateSize(bool needsRedraw)
+{
+ Q_D(QSGTextInput);
+ int w = width();
+ int h = height();
+ setImplicitHeight(d->control->height()-1); // -1 to counter QLineControl's +1 which is not consistent with Text.
+ setImplicitWidth(d->calculateTextWidth());
+ setContentsSize(QSize(width(), height()));
+ if(w==width() && h==height() && needsRedraw)
+ update();
+}
+
+void QSGTextInput::q_canPasteChanged()
+{
+ Q_D(QSGTextInput);
+ bool old = d->canPaste;
+#ifndef QT_NO_CLIPBOARD
+ d->canPaste = !d->control->isReadOnly() && QApplication::clipboard()->text().length() != 0;
+#endif
+ if(d->canPaste != old)
+ emit canPasteChanged();
+}
+
+QT_END_NAMESPACE
+
diff --git a/src/declarative/items/qsgtextinput_p.h b/src/declarative/items/qsgtextinput_p.h
new file mode 100644
index 0000000000..ccea485e99
--- /dev/null
+++ b/src/declarative/items/qsgtextinput_p.h
@@ -0,0 +1,302 @@
+// Commit: 2f173e4945dd8414636c1061acfaf9c2d8b718d8
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGTEXTINPUT_P_H
+#define QSGTEXTINPUT_P_H
+
+#include "qsgimplicitsizeitem_p.h"
+#include <QtGui/qvalidator.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QSGTextInputPrivate;
+class QValidator;
+class Q_AUTOTEST_EXPORT QSGTextInput : public QSGImplicitSizePaintedItem
+{
+ Q_OBJECT
+ Q_ENUMS(HAlignment)
+ Q_ENUMS(EchoMode)
+ Q_ENUMS(SelectionMode)
+
+ Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged)
+ Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged)
+ Q_PROPERTY(QColor selectionColor READ selectionColor WRITE setSelectionColor NOTIFY selectionColorChanged)
+ Q_PROPERTY(QColor selectedTextColor READ selectedTextColor WRITE setSelectedTextColor NOTIFY selectedTextColorChanged)
+ Q_PROPERTY(QFont font READ font WRITE setFont NOTIFY fontChanged)
+ Q_PROPERTY(HAlignment horizontalAlignment READ hAlign WRITE setHAlign RESET resetHAlign NOTIFY horizontalAlignmentChanged)
+ Q_PROPERTY(HAlignment effectiveHorizontalAlignment READ effectiveHAlign NOTIFY effectiveHorizontalAlignmentChanged)
+
+ Q_PROPERTY(bool readOnly READ isReadOnly WRITE setReadOnly NOTIFY readOnlyChanged)
+ Q_PROPERTY(bool cursorVisible READ isCursorVisible WRITE setCursorVisible NOTIFY cursorVisibleChanged)
+ Q_PROPERTY(int cursorPosition READ cursorPosition WRITE setCursorPosition NOTIFY cursorPositionChanged)
+ Q_PROPERTY(QRect cursorRectangle READ cursorRectangle NOTIFY cursorPositionChanged)
+ Q_PROPERTY(QDeclarativeComponent *cursorDelegate READ cursorDelegate WRITE setCursorDelegate NOTIFY cursorDelegateChanged)
+ Q_PROPERTY(int selectionStart READ selectionStart NOTIFY selectionStartChanged)
+ Q_PROPERTY(int selectionEnd READ selectionEnd NOTIFY selectionEndChanged)
+ Q_PROPERTY(QString selectedText READ selectedText NOTIFY selectedTextChanged)
+
+ Q_PROPERTY(int maximumLength READ maxLength WRITE setMaxLength NOTIFY maximumLengthChanged)
+#ifndef QT_NO_VALIDATOR
+ Q_PROPERTY(QValidator* validator READ validator WRITE setValidator NOTIFY validatorChanged)
+#endif
+ Q_PROPERTY(QString inputMask READ inputMask WRITE setInputMask NOTIFY inputMaskChanged)
+ Q_PROPERTY(Qt::InputMethodHints inputMethodHints READ imHints WRITE setIMHints)
+
+ Q_PROPERTY(bool acceptableInput READ hasAcceptableInput NOTIFY acceptableInputChanged)
+ Q_PROPERTY(EchoMode echoMode READ echoMode WRITE setEchoMode NOTIFY echoModeChanged)
+ Q_PROPERTY(bool activeFocusOnPress READ focusOnPress WRITE setFocusOnPress NOTIFY activeFocusOnPressChanged)
+ Q_PROPERTY(QString passwordCharacter READ passwordCharacter WRITE setPasswordCharacter NOTIFY passwordCharacterChanged)
+ Q_PROPERTY(QString displayText READ displayText NOTIFY displayTextChanged)
+ Q_PROPERTY(bool autoScroll READ autoScroll WRITE setAutoScroll NOTIFY autoScrollChanged)
+ Q_PROPERTY(bool selectByMouse READ selectByMouse WRITE setSelectByMouse NOTIFY selectByMouseChanged)
+ Q_PROPERTY(SelectionMode mouseSelectionMode READ mouseSelectionMode WRITE setMouseSelectionMode NOTIFY mouseSelectionModeChanged)
+ Q_PROPERTY(bool canPaste READ canPaste NOTIFY canPasteChanged)
+ Q_PROPERTY(bool inputMethodComposing READ isInputMethodComposing NOTIFY inputMethodComposingChanged)
+
+public:
+ QSGTextInput(QSGItem * parent=0);
+ ~QSGTextInput();
+
+ enum EchoMode {//To match QLineEdit::EchoMode
+ Normal,
+ NoEcho,
+ Password,
+ PasswordEchoOnEdit
+ };
+
+ enum HAlignment {
+ AlignLeft = Qt::AlignLeft,
+ AlignRight = Qt::AlignRight,
+ AlignHCenter = Qt::AlignHCenter
+ };
+
+ enum SelectionMode {
+ SelectCharacters,
+ SelectWords
+ };
+
+ enum CursorPosition {
+ CursorBetweenCharacters,
+ CursorOnCharacter
+ };
+
+ //Auxilliary functions needed to control the TextInput from QML
+ Q_INVOKABLE int positionAt(int x) const;
+ Q_INVOKABLE int positionAt(int x, CursorPosition position) const;
+ Q_INVOKABLE QRectF positionToRectangle(int pos) const;
+ Q_INVOKABLE void moveCursorSelection(int pos);
+ Q_INVOKABLE void moveCursorSelection(int pos, SelectionMode mode);
+
+ Q_INVOKABLE void openSoftwareInputPanel();
+ Q_INVOKABLE void closeSoftwareInputPanel();
+
+ QString text() const;
+ void setText(const QString &);
+
+ QFont font() const;
+ void setFont(const QFont &font);
+
+ QColor color() const;
+ void setColor(const QColor &c);
+
+ QColor selectionColor() const;
+ void setSelectionColor(const QColor &c);
+
+ QColor selectedTextColor() const;
+ void setSelectedTextColor(const QColor &c);
+
+ HAlignment hAlign() const;
+ void setHAlign(HAlignment align);
+ void resetHAlign();
+ HAlignment effectiveHAlign() const;
+
+ bool isReadOnly() const;
+ void setReadOnly(bool);
+
+ bool isCursorVisible() const;
+ void setCursorVisible(bool on);
+
+ int cursorPosition() const;
+ void setCursorPosition(int cp);
+
+ QRect cursorRectangle() const;
+
+ int selectionStart() const;
+ int selectionEnd() const;
+
+ QString selectedText() const;
+
+ int maxLength() const;
+ void setMaxLength(int ml);
+
+#ifndef QT_NO_VALIDATOR
+ QValidator * validator() const;
+ void setValidator(QValidator* v);
+#endif
+ QString inputMask() const;
+ void setInputMask(const QString &im);
+
+ EchoMode echoMode() const;
+ void setEchoMode(EchoMode echo);
+
+ QString passwordCharacter() const;
+ void setPasswordCharacter(const QString &str);
+
+ QString displayText() const;
+
+ QDeclarativeComponent* cursorDelegate() const;
+ void setCursorDelegate(QDeclarativeComponent*);
+
+ bool focusOnPress() const;
+ void setFocusOnPress(bool);
+
+ bool autoScroll() const;
+ void setAutoScroll(bool);
+
+ bool selectByMouse() const;
+ void setSelectByMouse(bool);
+
+ SelectionMode mouseSelectionMode() const;
+ void setMouseSelectionMode(SelectionMode mode);
+
+ bool hasAcceptableInput() const;
+
+ void paint(QPainter *p);
+ QVariant inputMethodQuery(Qt::InputMethodQuery property) const;
+
+ QRectF boundingRect() const;
+ bool canPaste() const;
+
+ bool isInputMethodComposing() const;
+
+ Qt::InputMethodHints imHints() const;
+ void setIMHints(Qt::InputMethodHints hints);
+
+Q_SIGNALS:
+ void textChanged();
+ void cursorPositionChanged();
+ void selectionStartChanged();
+ void selectionEndChanged();
+ void selectedTextChanged();
+ void accepted();
+ void acceptableInputChanged();
+ void colorChanged(const QColor &color);
+ void selectionColorChanged(const QColor &color);
+ void selectedTextColorChanged(const QColor &color);
+ void fontChanged(const QFont &font);
+ void horizontalAlignmentChanged(HAlignment alignment);
+ void readOnlyChanged(bool isReadOnly);
+ void cursorVisibleChanged(bool isCursorVisible);
+ void cursorDelegateChanged();
+ void maximumLengthChanged(int maximumLength);
+ void validatorChanged();
+ void inputMaskChanged(const QString &inputMask);
+ void echoModeChanged(EchoMode echoMode);
+ void passwordCharacterChanged();
+ void displayTextChanged();
+ void activeFocusOnPressChanged(bool activeFocusOnPress);
+ void autoScrollChanged(bool autoScroll);
+ void selectByMouseChanged(bool selectByMouse);
+ void mouseSelectionModeChanged(SelectionMode mode);
+ void canPasteChanged();
+ void inputMethodComposingChanged();
+ void effectiveHorizontalAlignmentChanged();
+
+protected:
+ virtual void geometryChanged(const QRectF &newGeometry,
+ const QRectF &oldGeometry);
+
+ void mousePressEvent(QGraphicsSceneMouseEvent *event);
+ void mouseMoveEvent(QGraphicsSceneMouseEvent *event);
+ void mouseReleaseEvent(QGraphicsSceneMouseEvent *event);
+ void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event);
+ bool sceneEvent(QEvent *event);
+ void keyPressEvent(QKeyEvent* ev);
+ void inputMethodEvent(QInputMethodEvent *);
+ void mouseUngrabEvent();
+ bool event(QEvent *e);
+ void focusInEvent(QFocusEvent *event);
+ virtual void itemChange(ItemChange, const ItemChangeData &);
+
+public Q_SLOTS:
+ void selectAll();
+ void selectWord();
+ void select(int start, int end);
+ void deselect();
+ bool isRightToLeft(int start, int end);
+#ifndef QT_NO_CLIPBOARD
+ void cut();
+ void copy();
+ void paste();
+#endif
+
+private Q_SLOTS:
+ void updateSize(bool needsRedraw = true);
+ void q_textChanged();
+ void selectionChanged();
+ void createCursor();
+ void moveCursor();
+ void cursorPosChanged();
+ void updateRect(const QRect &r = QRect());
+ void q_canPasteChanged();
+
+private:
+ Q_DECLARE_PRIVATE(QSGTextInput)
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QSGTextInput)
+#ifndef QT_NO_VALIDATOR
+QML_DECLARE_TYPE(QValidator)
+QML_DECLARE_TYPE(QIntValidator)
+QML_DECLARE_TYPE(QDoubleValidator)
+QML_DECLARE_TYPE(QRegExpValidator)
+#endif
+
+QT_END_HEADER
+
+#endif // QSGTEXTINPUT_P_H
diff --git a/src/declarative/items/qsgtextinput_p_p.h b/src/declarative/items/qsgtextinput_p_p.h
new file mode 100644
index 0000000000..6561d28a31
--- /dev/null
+++ b/src/declarative/items/qsgtextinput_p_p.h
@@ -0,0 +1,152 @@
+// Commit: 47712d1f330e4b22ce6dd30e7557288ef7f7fca0
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGTEXTINPUT_P_P_H
+#define QSGTEXTINPUT_P_P_H
+
+#include "qsgtextinput_p.h"
+#include "qsgtext_p.h"
+#include "qsgimplicitsizeitem_p_p.h"
+
+#include <private/qlinecontrol_p.h>
+
+#include <QtDeclarative/qdeclarative.h>
+#include <QtCore/qpointer.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 Q_AUTOTEST_EXPORT QSGTextInputPrivate : public QSGImplicitSizePaintedItemPrivate
+{
+ Q_DECLARE_PUBLIC(QSGTextInput)
+public:
+ QSGTextInputPrivate() : control(new QLineControl(QString())),
+ color((QRgb)0), style(QSGText::Normal),
+ styleColor((QRgb)0), hAlign(QSGTextInput::AlignLeft),
+ mouseSelectionMode(QSGTextInput::SelectCharacters), inputMethodHints(Qt::ImhNone),
+ hscroll(0), oldScroll(0), oldValidity(false), focused(false), focusOnPress(true),
+ showInputPanelOnFocus(true), clickCausedFocus(false), cursorVisible(false),
+ autoScroll(true), selectByMouse(false), canPaste(false), hAlignImplicit(true),
+ selectPressed(false)
+ {
+#ifdef Q_OS_SYMBIAN
+ if (QSysInfo::symbianVersion() == QSysInfo::SV_SF_1 || QSysInfo::symbianVersion() == QSysInfo::SV_SF_3) {
+ showInputPanelOnFocus = false;
+ }
+#endif
+ }
+
+ ~QSGTextInputPrivate()
+ {
+ }
+
+ int xToPos(int x, QTextLine::CursorPosition betweenOrOn = QTextLine::CursorBetweenCharacters) const
+ {
+ Q_Q(const QSGTextInput);
+ QRect cr = q->boundingRect().toRect();
+ x-= cr.x() - hscroll;
+ return control->xToPos(x, betweenOrOn);
+ }
+
+ void init();
+ void startCreatingCursor();
+ void updateHorizontalScroll();
+ bool determineHorizontalAlignment();
+ bool setHAlign(QSGTextInput::HAlignment, bool forceAlign = false);
+ void mirrorChange();
+ int calculateTextWidth();
+ bool sendMouseEventToInputContext(QGraphicsSceneMouseEvent *event, QEvent::Type eventType);
+ void updateInputMethodHints();
+
+ QLineControl* control;
+
+ QFont font;
+ QFont sourceFont;
+ QColor color;
+ QColor selectionColor;
+ QColor selectedTextColor;
+ QSGText::TextStyle style;
+ QColor styleColor;
+ QSGTextInput::HAlignment hAlign;
+ QSGTextInput::SelectionMode mouseSelectionMode;
+ Qt::InputMethodHints inputMethodHints;
+ QPointer<QDeclarativeComponent> cursorComponent;
+ QPointer<QSGItem> cursorItem;
+ QPointF pressPos;
+
+ int lastSelectionStart;
+ int lastSelectionEnd;
+ int oldHeight;
+ int oldWidth;
+ int hscroll;
+ int oldScroll;
+
+ bool oldValidity:1;
+ bool focused:1;
+ bool focusOnPress:1;
+ bool showInputPanelOnFocus:1;
+ bool clickCausedFocus:1;
+ bool cursorVisible:1;
+ bool autoScroll:1;
+ bool selectByMouse:1;
+ bool canPaste:1;
+ bool hAlignImplicit:1;
+ bool selectPressed:1;
+
+ static inline QSGTextInputPrivate *get(QSGTextInput *t) {
+ return t->d_func();
+ }
+};
+
+QT_END_NAMESPACE
+
+#endif // QSGTEXTINPUT_P_P_H
diff --git a/src/declarative/items/qsgtextnode.cpp b/src/declarative/items/qsgtextnode.cpp
new file mode 100644
index 0000000000..33325a14ab
--- /dev/null
+++ b/src/declarative/items/qsgtextnode.cpp
@@ -0,0 +1,457 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgtextnode_p.h"
+#include "qsgsimplerectnode.h"
+#include <private/qsgadaptationlayer_p.h>
+#include <private/qsgdistancefieldglyphcache_p.h>
+#include <private/qsgdistancefieldglyphnode_p.h>
+
+#include <private/qsgcontext_p.h>
+
+#include <qmath.h>
+#include <qtextdocument.h>
+#include <qtextlayout.h>
+#include <qabstracttextdocumentlayout.h>
+#include <qxmlstream.h>
+#include <qrawfont.h>
+#include <private/qdeclarativestyledtext_p.h>
+#include <private/qfont_p.h>
+#include <private/qfontengine_p.h>
+#include <private/qrawfont_p.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ Creates an empty QSGTextNode
+*/
+QSGTextNode::QSGTextNode(QSGContext *context)
+: m_context(context)
+{
+#if defined(QML_RUNTIME_TESTING)
+ description = QLatin1String("text");
+#endif
+}
+
+QSGTextNode::~QSGTextNode()
+{
+}
+
+#if 0
+void QSGTextNode::setColor(const QColor &color)
+{
+ if (m_usePixmapCache) {
+ setUpdateFlag(UpdateNodes);
+ } else {
+ for (int i=0; i<childCount(); ++i) {
+ QSGNode *childNode = childAtIndex(i);
+ if (childNode->subType() == GlyphNodeSubType) {
+ QSGGlyphNode *glyphNode = static_cast<QSGGlyphNode *>(childNode);
+ if (glyphNode->color() == m_color)
+ glyphNode->setColor(color);
+ } else if (childNode->subType() == SolidRectNodeSubType) {
+ QSGSimpleRectNode *solidRectNode = static_cast<QSGSimpleRectNode *>(childNode);
+ if (solidRectNode->color() == m_color)
+ solidRectNode->setColor(color);
+ }
+ }
+ }
+ m_color = color;
+}
+
+void QSGTextNode::setStyleColor(const QColor &styleColor)
+{
+ if (m_textStyle != QSGTextNode::NormalTextStyle) {
+ if (m_usePixmapCache) {
+ setUpdateFlag(UpdateNodes);
+ } else {
+ for (int i=0; i<childCount(); ++i) {
+ QSGNode *childNode = childAtIndex(i);
+ if (childNode->subType() == GlyphNodeSubType) {
+ QSGGlyphNode *glyphNode = static_cast<QSGGlyphNode *>(childNode);
+ if (glyphNode->color() == m_styleColor)
+ glyphNode->setColor(styleColor);
+ } else if (childNode->subType() == SolidRectNodeSubType) {
+ QSGSimpleRectNode *solidRectNode = static_cast<QSGSimpleRectNode *>(childNode);
+ if (solidRectNode->color() == m_styleColor)
+ solidRectNode->setColor(styleColor);
+ }
+ }
+ }
+ }
+ m_styleColor = styleColor;
+}
+#endif
+
+void QSGTextNode::addTextDecorations(const QPointF &position, const QRawFont &font, const QColor &color,
+ qreal width, bool hasOverline, bool hasStrikeOut, bool hasUnderline)
+{
+ Q_ASSERT(font.isValid());
+ QRawFontPrivate *dptrFont = QRawFontPrivate::get(font);
+ QFontEngine *fontEngine = dptrFont->fontEngine;
+
+ qreal lineThickness = fontEngine->lineThickness().toReal();
+
+ QRectF line(position.x(), position.y() - lineThickness / 2.0, width, lineThickness);
+
+ if (hasUnderline) {
+ int underlinePosition = fontEngine->underlinePosition().ceil().toInt();
+ QRectF underline(line);
+ underline.translate(0.0, underlinePosition);
+ appendChildNode(new QSGSimpleRectNode(underline, color));
+ }
+
+ qreal ascent = font.ascent();
+ if (hasOverline) {
+ QRectF overline(line);
+ overline.translate(0.0, -ascent);
+ appendChildNode(new QSGSimpleRectNode(overline, color));
+ }
+
+ if (hasStrikeOut) {
+ QRectF strikeOut(line);
+ strikeOut.translate(0.0, ascent / -3.0);
+ appendChildNode(new QSGSimpleRectNode(strikeOut, color));
+ }
+}
+
+QSGGlyphNode *QSGTextNode::addGlyphs(const QPointF &position, const QGlyphRun &glyphs, const QColor &color,
+ QSGText::TextStyle style, const QColor &styleColor)
+{
+ QSGGlyphNode *node = m_context->createGlyphNode();
+ if (QSGDistanceFieldGlyphCache::distanceFieldEnabled()) {
+ QSGDistanceFieldGlyphNode *dfNode = static_cast<QSGDistanceFieldGlyphNode *>(node);
+ dfNode->setStyle(style);
+ dfNode->setStyleColor(styleColor);
+ }
+ node->setGlyphs(position, glyphs);
+ node->setColor(color);
+
+ appendChildNode(node);
+
+ return node;
+}
+
+void QSGTextNode::addTextDocument(const QPointF &position, QTextDocument *textDocument, const QColor &color,
+ QSGText::TextStyle style, const QColor &styleColor)
+{
+ Q_UNUSED(position)
+ QTextFrame *textFrame = textDocument->rootFrame();
+ QPointF p = textDocument->documentLayout()->frameBoundingRect(textFrame).topLeft();
+
+ QTextFrame::iterator it = textFrame->begin();
+ while (!it.atEnd()) {
+ addTextBlock(p, textDocument, it.currentBlock(), color, style, styleColor);
+ ++it;
+ }
+}
+
+void QSGTextNode::addTextLayout(const QPointF &position, QTextLayout *textLayout, const QColor &color,
+ QSGText::TextStyle style, const QColor &styleColor)
+{
+ QList<QGlyphRun> glyphsList(textLayout->glyphRuns());
+ for (int i=0; i<glyphsList.size(); ++i) {
+ QGlyphRun glyphs = glyphsList.at(i);
+ QRawFont font = glyphs.rawFont();
+ addGlyphs(position + QPointF(0, font.ascent()), glyphs, color, style, styleColor);
+ }
+
+ QFont font = textLayout->font();
+ QRawFont rawFont = QRawFont::fromFont(font);
+ if (font.strikeOut() || font.underline() || font.overline()) {
+ addTextDecorations(position, rawFont, color, textLayout->boundingRect().width(),
+ font.overline(), font.strikeOut(), font.underline());
+ }
+}
+
+
+/*!
+ Returns true if \a text contains any HTML tags, attributes or CSS properties which are unrelated
+ to text, fonts or text layout. Otherwise the function returns false. If the return value is
+ false, \a text is considered to be easily representable in the scenegraph. If it returns true,
+ then the text should be prerendered into a pixmap before it's displayed on screen.
+*/
+bool QSGTextNode::isComplexRichText(QTextDocument *doc)
+{
+ if (doc == 0)
+ return false;
+
+ static QSet<QString> supportedTags;
+ if (supportedTags.isEmpty()) {
+ supportedTags.insert(QLatin1String("i"));
+ supportedTags.insert(QLatin1String("b"));
+ supportedTags.insert(QLatin1String("u"));
+ supportedTags.insert(QLatin1String("div"));
+ supportedTags.insert(QLatin1String("big"));
+ supportedTags.insert(QLatin1String("blockquote"));
+ supportedTags.insert(QLatin1String("body"));
+ supportedTags.insert(QLatin1String("br"));
+ supportedTags.insert(QLatin1String("center"));
+ supportedTags.insert(QLatin1String("cite"));
+ supportedTags.insert(QLatin1String("code"));
+ supportedTags.insert(QLatin1String("tt"));
+ supportedTags.insert(QLatin1String("dd"));
+ supportedTags.insert(QLatin1String("dfn"));
+ supportedTags.insert(QLatin1String("em"));
+ supportedTags.insert(QLatin1String("font"));
+ supportedTags.insert(QLatin1String("h1"));
+ supportedTags.insert(QLatin1String("h2"));
+ supportedTags.insert(QLatin1String("h3"));
+ supportedTags.insert(QLatin1String("h4"));
+ supportedTags.insert(QLatin1String("h5"));
+ supportedTags.insert(QLatin1String("h6"));
+ supportedTags.insert(QLatin1String("head"));
+ supportedTags.insert(QLatin1String("html"));
+ supportedTags.insert(QLatin1String("meta"));
+ supportedTags.insert(QLatin1String("nobr"));
+ supportedTags.insert(QLatin1String("p"));
+ supportedTags.insert(QLatin1String("pre"));
+ supportedTags.insert(QLatin1String("qt"));
+ supportedTags.insert(QLatin1String("s"));
+ supportedTags.insert(QLatin1String("samp"));
+ supportedTags.insert(QLatin1String("small"));
+ supportedTags.insert(QLatin1String("span"));
+ supportedTags.insert(QLatin1String("strong"));
+ supportedTags.insert(QLatin1String("sub"));
+ supportedTags.insert(QLatin1String("sup"));
+ supportedTags.insert(QLatin1String("title"));
+ supportedTags.insert(QLatin1String("var"));
+ supportedTags.insert(QLatin1String("style"));
+ }
+
+ static QSet<QCss::Property> supportedCssProperties;
+ if (supportedCssProperties.isEmpty()) {
+ supportedCssProperties.insert(QCss::Color);
+ supportedCssProperties.insert(QCss::Float);
+ supportedCssProperties.insert(QCss::Font);
+ supportedCssProperties.insert(QCss::FontFamily);
+ supportedCssProperties.insert(QCss::FontSize);
+ supportedCssProperties.insert(QCss::FontStyle);
+ supportedCssProperties.insert(QCss::FontWeight);
+ supportedCssProperties.insert(QCss::Margin);
+ supportedCssProperties.insert(QCss::MarginBottom);
+ supportedCssProperties.insert(QCss::MarginLeft);
+ supportedCssProperties.insert(QCss::MarginRight);
+ supportedCssProperties.insert(QCss::MarginTop);
+ supportedCssProperties.insert(QCss::TextDecoration);
+ supportedCssProperties.insert(QCss::TextIndent);
+ supportedCssProperties.insert(QCss::TextUnderlineStyle);
+ supportedCssProperties.insert(QCss::VerticalAlignment);
+ supportedCssProperties.insert(QCss::Whitespace);
+ supportedCssProperties.insert(QCss::Padding);
+ supportedCssProperties.insert(QCss::PaddingLeft);
+ supportedCssProperties.insert(QCss::PaddingRight);
+ supportedCssProperties.insert(QCss::PaddingTop);
+ supportedCssProperties.insert(QCss::PaddingBottom);
+ supportedCssProperties.insert(QCss::PageBreakBefore);
+ supportedCssProperties.insert(QCss::PageBreakAfter);
+ supportedCssProperties.insert(QCss::Width);
+ supportedCssProperties.insert(QCss::Height);
+ supportedCssProperties.insert(QCss::MinimumWidth);
+ supportedCssProperties.insert(QCss::MinimumHeight);
+ supportedCssProperties.insert(QCss::MaximumWidth);
+ supportedCssProperties.insert(QCss::MaximumHeight);
+ supportedCssProperties.insert(QCss::Left);
+ supportedCssProperties.insert(QCss::Right);
+ supportedCssProperties.insert(QCss::Top);
+ supportedCssProperties.insert(QCss::Bottom);
+ supportedCssProperties.insert(QCss::Position);
+ supportedCssProperties.insert(QCss::TextAlignment);
+ supportedCssProperties.insert(QCss::FontVariant);
+ }
+
+ QXmlStreamReader reader(doc->toHtml("utf-8"));
+ while (!reader.atEnd()) {
+ reader.readNext();
+
+ if (reader.isStartElement()) {
+ if (!supportedTags.contains(reader.name().toString().toLower()))
+ return true;
+
+ QXmlStreamAttributes attributes = reader.attributes();
+ if (attributes.hasAttribute(QLatin1String("bgcolor")))
+ return true;
+ if (attributes.hasAttribute(QLatin1String("style"))) {
+ QCss::StyleSheet styleSheet;
+ QCss::Parser(attributes.value(QLatin1String("style")).toString()).parse(&styleSheet);
+
+ QVector<QCss::Declaration> decls;
+ for (int i=0; i<styleSheet.pageRules.size(); ++i)
+ decls += styleSheet.pageRules.at(i).declarations;
+
+ QVector<QCss::StyleRule> styleRules =
+ styleSheet.styleRules
+ + styleSheet.idIndex.values().toVector()
+ + styleSheet.nameIndex.values().toVector();
+ for (int i=0; i<styleSheet.mediaRules.size(); ++i)
+ styleRules += styleSheet.mediaRules.at(i).styleRules;
+
+ for (int i=0; i<styleRules.size(); ++i)
+ decls += styleRules.at(i).declarations;
+
+ for (int i=0; i<decls.size(); ++i) {
+ if (!supportedCssProperties.contains(decls.at(i).d->propertyId))
+ return true;
+ }
+
+ }
+ }
+ }
+
+ return reader.hasError();
+}
+
+void QSGTextNode::addTextBlock(const QPointF &position, QTextDocument *textDocument, const QTextBlock &block,
+ const QColor &overrideColor, QSGText::TextStyle style, const QColor &styleColor)
+{
+ if (!block.isValid())
+ return;
+
+ QPointF blockPosition = textDocument->documentLayout()->blockBoundingRect(block).topLeft();
+
+ QTextBlock::iterator it = block.begin();
+ while (!it.atEnd()) {
+ QTextFragment fragment = it.fragment();
+ if (!fragment.text().isEmpty()) {
+ QTextCharFormat charFormat = fragment.charFormat();
+ QColor color = overrideColor.isValid()
+ ? overrideColor
+ : charFormat.foreground().color();
+
+ QList<QGlyphRun> glyphsList = fragment.glyphRuns();
+ for (int i=0; i<glyphsList.size(); ++i) {
+ QGlyphRun glyphs = glyphsList.at(i);
+ QRawFont font = glyphs.rawFont();
+ QSGGlyphNode *glyphNode = addGlyphs(position + blockPosition + QPointF(0, font.ascent()),
+ glyphs, color, style, styleColor);
+
+ QPointF baseLine = glyphNode->baseLine();
+ qreal width = glyphNode->boundingRect().width();
+ addTextDecorations(baseLine, font, color, width,
+ glyphs.overline(), glyphs.strikeOut(), glyphs.underline());
+ }
+ }
+
+ ++it;
+ }
+}
+
+void QSGTextNode::deleteContent()
+{
+ while (childCount() > 0)
+ delete childAtIndex(0);
+}
+
+#if 0
+void QSGTextNode::updateNodes()
+{
+ return;
+ deleteContent();
+ if (m_text.isEmpty())
+ return;
+
+ if (m_usePixmapCache) {
+ // ### gunnar: port properly
+// QPixmap pixmap = generatedPixmap();
+// if (pixmap.isNull())
+// return;
+
+// QSGImageNode *pixmapNode = m_context->createImageNode();
+// pixmapNode->setRect(pixmap.rect());
+// pixmapNode->setSourceRect(pixmap.rect());
+// pixmapNode->setOpacity(m_opacity);
+// pixmapNode->setClampToEdge(true);
+// pixmapNode->setLinearFiltering(m_linearFiltering);
+
+// appendChildNode(pixmapNode);
+ } else {
+ if (m_text.isEmpty())
+ return;
+
+ // Implement styling by drawing text several times at slight shifts. shiftForStyle
+ // contains the sequence of shifted positions at which to draw the text. All except
+ // the last will be drawn with styleColor.
+ QList<QPointF> shiftForStyle;
+ switch (m_textStyle) {
+ case OutlineTextStyle:
+ // ### Should be made faster by implementing outline material
+ shiftForStyle << QPointF(-1, 0);
+ shiftForStyle << QPointF(0, -1);
+ shiftForStyle << QPointF(1, 0);
+ shiftForStyle << QPointF(0, 1);
+ break;
+ case SunkenTextStyle:
+ shiftForStyle << QPointF(0, -1);
+ break;
+ case RaisedTextStyle:
+ shiftForStyle << QPointF(0, 1);
+ break;
+ default:
+ break;
+ }
+
+ shiftForStyle << QPointF(0, 0); // Regular position
+ while (!shiftForStyle.isEmpty()) {
+ QPointF shift = shiftForStyle.takeFirst();
+
+ // Use styleColor for all but last shift
+ if (m_richText) {
+ QColor overrideColor = shiftForStyle.isEmpty() ? QColor() : m_styleColor;
+
+ QTextFrame *textFrame = m_textDocument->rootFrame();
+ QPointF p = m_textDocument->documentLayout()->frameBoundingRect(textFrame).topLeft();
+
+ QTextFrame::iterator it = textFrame->begin();
+ while (!it.atEnd()) {
+ addTextBlock(shift + p, it.currentBlock(), overrideColor);
+ ++it;
+ }
+ } else {
+ addTextLayout(shift, m_textLayout, shiftForStyle.isEmpty()
+ ? m_color
+ : m_styleColor);
+ }
+ }
+ }
+}
+#endif
+
+QT_END_NAMESPACE
diff --git a/src/declarative/items/qsgtextnode_p.h b/src/declarative/items/qsgtextnode_p.h
new file mode 100644
index 0000000000..7a49f51dbe
--- /dev/null
+++ b/src/declarative/items/qsgtextnode_p.h
@@ -0,0 +1,84 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGTEXTNODE_P_H
+#define QSGTEXTNODE_P_H
+
+#include <qsgnode.h>
+#include <qsgtext_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QTextLayout;
+class QSGGlyphNode;
+class QTextBlock;
+class QColor;
+class QTextDocument;
+class QSGContext;
+class QRawFont;
+
+class QSGTextNode : public QSGTransformNode
+{
+public:
+ QSGTextNode(QSGContext *);
+ ~QSGTextNode();
+
+ static bool isComplexRichText(QTextDocument *);
+
+ void deleteContent();
+ void addTextLayout(const QPointF &position, QTextLayout *textLayout, const QColor &color = QColor(),
+ QSGText::TextStyle style = QSGText::Normal, const QColor &styleColor = QColor());
+ void addTextDocument(const QPointF &position, QTextDocument *textDocument, const QColor &color = QColor(),
+ QSGText::TextStyle style = QSGText::Normal, const QColor &styleColor = QColor());
+
+private:
+ void addTextBlock(const QPointF &position, QTextDocument *textDocument, const QTextBlock &block,
+ const QColor &overrideColor, QSGText::TextStyle style = QSGText::Normal, const QColor &styleColor = QColor());
+ QSGGlyphNode *addGlyphs(const QPointF &position, const QGlyphRun &glyphs, const QColor &color,
+ QSGText::TextStyle style = QSGText::Normal, const QColor &styleColor = QColor());
+ void addTextDecorations(const QPointF &position, const QRawFont &font, const QColor &color,
+ qreal width, bool hasOverline, bool hasStrikeOut, bool hasUnderline);
+ QSGContext *m_context;
+};
+
+QT_END_NAMESPACE
+
+#endif // QSGTEXTNODE_P_H
diff --git a/src/declarative/items/qsgtranslate.cpp b/src/declarative/items/qsgtranslate.cpp
new file mode 100644
index 0000000000..5f7112bd42
--- /dev/null
+++ b/src/declarative/items/qsgtranslate.cpp
@@ -0,0 +1,297 @@
+// Commit: ac5c099cc3c5b8c7eec7a49fdeb8a21037230350
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgtranslate_p.h"
+#include "qsgitem_p.h"
+
+#include <QtCore/qmath.h>
+
+QT_BEGIN_NAMESPACE
+
+class QSGTranslatePrivate : public QSGTransformPrivate
+{
+public:
+ QSGTranslatePrivate()
+ : x(0), y(0) {}
+
+ qreal x;
+ qreal y;
+};
+
+QSGTranslate::QSGTranslate(QObject *parent)
+: QSGTransform(*new QSGTranslatePrivate, parent)
+{
+}
+
+QSGTranslate::~QSGTranslate()
+{
+}
+
+qreal QSGTranslate::x() const
+{
+ Q_D(const QSGTranslate);
+ return d->x;
+}
+
+void QSGTranslate::setX(qreal x)
+{
+ Q_D(QSGTranslate);
+ if (d->x == x)
+ return;
+ d->x = x;
+ update();
+ emit xChanged();
+}
+
+qreal QSGTranslate::y() const
+{
+ Q_D(const QSGTranslate);
+ return d->y;
+}
+void QSGTranslate::setY(qreal y)
+{
+ Q_D(QSGTranslate);
+ if (d->y == y)
+ return;
+ d->y = y;
+ update();
+ emit yChanged();
+}
+
+void QSGTranslate::applyTo(QMatrix4x4 *matrix) const
+{
+ Q_D(const QSGTranslate);
+ matrix->translate(d->x, d->y, 0);
+}
+
+class QSGScalePrivate : public QSGTransformPrivate
+{
+public:
+ QSGScalePrivate()
+ : xScale(1), yScale(1), zScale(1) {}
+ QVector3D origin;
+ qreal xScale;
+ qreal yScale;
+ qreal zScale;
+};
+
+QSGScale::QSGScale(QObject *parent)
+ : QSGTransform(*new QSGScalePrivate, parent)
+{
+}
+
+QSGScale::~QSGScale()
+{
+}
+
+QVector3D QSGScale::origin() const
+{
+ Q_D(const QSGScale);
+ return d->origin;
+}
+void QSGScale::setOrigin(const QVector3D &point)
+{
+ Q_D(QSGScale);
+ if (d->origin == point)
+ return;
+ d->origin = point;
+ update();
+ emit originChanged();
+}
+
+qreal QSGScale::xScale() const
+{
+ Q_D(const QSGScale);
+ return d->xScale;
+}
+void QSGScale::setXScale(qreal scale)
+{
+ Q_D(QSGScale);
+ if (d->xScale == scale)
+ return;
+ d->xScale = scale;
+ update();
+ emit xScaleChanged();
+ emit scaleChanged();
+}
+
+qreal QSGScale::yScale() const
+{
+ Q_D(const QSGScale);
+ return d->yScale;
+}
+void QSGScale::setYScale(qreal scale)
+{
+ Q_D(QSGScale);
+ if (d->yScale == scale)
+ return;
+ d->yScale = scale;
+ update();
+ emit yScaleChanged();
+ emit scaleChanged();
+}
+
+qreal QSGScale::zScale() const
+{
+ Q_D(const QSGScale);
+ return d->zScale;
+}
+void QSGScale::setZScale(qreal scale)
+{
+ Q_D(QSGScale);
+ if (d->zScale == scale)
+ return;
+ d->zScale = scale;
+ update();
+ emit zScaleChanged();
+ emit scaleChanged();
+}
+
+void QSGScale::applyTo(QMatrix4x4 *matrix) const
+{
+ Q_D(const QSGScale);
+ matrix->translate(d->origin);
+ matrix->scale(d->xScale, d->yScale, d->zScale);
+ matrix->translate(-d->origin);
+}
+
+class QSGRotationPrivate : public QSGTransformPrivate
+{
+public:
+ QSGRotationPrivate()
+ : angle(0), axis(0, 0, 1) {}
+ QVector3D origin;
+ qreal angle;
+ QVector3D axis;
+};
+
+QSGRotation::QSGRotation(QObject *parent)
+ : QSGTransform(*new QSGRotationPrivate, parent)
+{
+}
+
+QSGRotation::~QSGRotation()
+{
+}
+
+QVector3D QSGRotation::origin() const
+{
+ Q_D(const QSGRotation);
+ return d->origin;
+}
+
+void QSGRotation::setOrigin(const QVector3D &point)
+{
+ Q_D(QSGRotation);
+ if (d->origin == point)
+ return;
+ d->origin = point;
+ update();
+ emit originChanged();
+}
+
+qreal QSGRotation::angle() const
+{
+ Q_D(const QSGRotation);
+ return d->angle;
+}
+void QSGRotation::setAngle(qreal angle)
+{
+ Q_D(QSGRotation);
+ if (d->angle == angle)
+ return;
+ d->angle = angle;
+ update();
+ emit angleChanged();
+}
+
+QVector3D QSGRotation::axis() const
+{
+ Q_D(const QSGRotation);
+ return d->axis;
+}
+void QSGRotation::setAxis(const QVector3D &axis)
+{
+ Q_D(QSGRotation);
+ if (d->axis == axis)
+ return;
+ d->axis = axis;
+ update();
+ emit axisChanged();
+}
+
+void QSGRotation::setAxis(Qt::Axis axis)
+{
+ switch (axis)
+ {
+ case Qt::XAxis:
+ setAxis(QVector3D(1, 0, 0));
+ break;
+ case Qt::YAxis:
+ setAxis(QVector3D(0, 1, 0));
+ break;
+ case Qt::ZAxis:
+ setAxis(QVector3D(0, 0, 1));
+ break;
+ }
+}
+
+struct QGraphicsRotation {
+ static inline void projectedRotate(QMatrix4x4 *matrix, qreal angle, qreal x, qreal y, qreal z)
+ {
+ matrix->projectedRotate(angle, x, y, z);
+ }
+};
+
+void QSGRotation::applyTo(QMatrix4x4 *matrix) const
+{
+ Q_D(const QSGRotation);
+
+ if (d->angle == 0. || d->axis.isNull())
+ return;
+
+ matrix->translate(d->origin);
+ QGraphicsRotation::projectedRotate(matrix, d->angle, d->axis.x(), d->axis.y(), d->axis.z());
+ matrix->translate(-d->origin);
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/items/qsgtranslate_p.h b/src/declarative/items/qsgtranslate_p.h
new file mode 100644
index 0000000000..de05778b1e
--- /dev/null
+++ b/src/declarative/items/qsgtranslate_p.h
@@ -0,0 +1,162 @@
+// Commit: ac5c099cc3c5b8c7eec7a49fdeb8a21037230350
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGTRANSLATE_P_H
+#define QSGTRANSLATE_P_H
+
+#include "qsgitem.h"
+
+#include <QtGui/qmatrix4x4.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QSGTranslatePrivate;
+class Q_AUTOTEST_EXPORT QSGTranslate : public QSGTransform
+{
+ Q_OBJECT
+
+ Q_PROPERTY(qreal x READ x WRITE setX NOTIFY xChanged)
+ Q_PROPERTY(qreal y READ y WRITE setY NOTIFY yChanged)
+
+public:
+ QSGTranslate(QObject *parent = 0);
+ ~QSGTranslate();
+
+ qreal x() const;
+ void setX(qreal);
+
+ qreal y() const;
+ void setY(qreal);
+
+ void applyTo(QMatrix4x4 *matrix) const;
+
+Q_SIGNALS:
+ void xChanged();
+ void yChanged();
+
+private:
+ Q_DECLARE_PRIVATE(QSGTranslate)
+ Q_DISABLE_COPY(QSGTranslate)
+};
+
+class QSGScalePrivate;
+class Q_AUTOTEST_EXPORT QSGScale : public QSGTransform
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QVector3D origin READ origin WRITE setOrigin NOTIFY originChanged)
+ Q_PROPERTY(qreal xScale READ xScale WRITE setXScale NOTIFY xScaleChanged)
+ Q_PROPERTY(qreal yScale READ yScale WRITE setYScale NOTIFY yScaleChanged)
+ Q_PROPERTY(qreal zScale READ zScale WRITE setZScale NOTIFY zScaleChanged)
+public:
+ QSGScale(QObject *parent = 0);
+ ~QSGScale();
+
+ QVector3D origin() const;
+ void setOrigin(const QVector3D &point);
+
+ qreal xScale() const;
+ void setXScale(qreal);
+
+ qreal yScale() const;
+ void setYScale(qreal);
+
+ qreal zScale() const;
+ void setZScale(qreal);
+
+ void applyTo(QMatrix4x4 *matrix) const;
+
+Q_SIGNALS:
+ void originChanged();
+ void xScaleChanged();
+ void yScaleChanged();
+ void zScaleChanged();
+ void scaleChanged();
+
+private:
+ Q_DECLARE_PRIVATE(QSGScale)
+};
+
+class QSGRotationPrivate;
+class Q_AUTOTEST_EXPORT QSGRotation : public QSGTransform
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QVector3D origin READ origin WRITE setOrigin NOTIFY originChanged)
+ Q_PROPERTY(qreal angle READ angle WRITE setAngle NOTIFY angleChanged)
+ Q_PROPERTY(QVector3D axis READ axis WRITE setAxis NOTIFY axisChanged)
+public:
+ QSGRotation(QObject *parent = 0);
+ ~QSGRotation();
+
+ QVector3D origin() const;
+ void setOrigin(const QVector3D &point);
+
+ qreal angle() const;
+ void setAngle(qreal);
+
+ QVector3D axis() const;
+ void setAxis(const QVector3D &axis);
+ void setAxis(Qt::Axis axis);
+
+ void applyTo(QMatrix4x4 *matrix) const;
+
+Q_SIGNALS:
+ void originChanged();
+ void angleChanged();
+ void axisChanged();
+
+private:
+ Q_DECLARE_PRIVATE(QSGRotation)
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QSGTranslate)
+
+QT_END_HEADER
+
+#endif
diff --git a/src/declarative/items/qsgview.cpp b/src/declarative/items/qsgview.cpp
new file mode 100644
index 0000000000..1169c59a1b
--- /dev/null
+++ b/src/declarative/items/qsgview.cpp
@@ -0,0 +1,466 @@
+// Commit: 55c4d94dfea78951f3371d3697a3cb28539b3012
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgview.h"
+
+#include "qsgcanvas_p.h"
+#include "qsgitem_p.h"
+#include "qsgitemchangelistener_p.h"
+
+#include <private/qdeclarativedebugtrace_p.h>
+
+#include <QtDeclarative/qdeclarativeengine.h>
+#include <private/qdeclarativeengine_p.h>
+#include <QtCore/qbasictimer.h>
+
+// XXX todo - This whole class should probably be merged with QDeclarativeView for
+// maximum seamlessness
+QT_BEGIN_NAMESPACE
+
+DEFINE_BOOL_CONFIG_OPTION(frameRateDebug, QML_SHOW_FRAMERATE)
+
+class QSGViewPrivate : public QSGCanvasPrivate,
+ public QSGItemChangeListener
+{
+ Q_DECLARE_PUBLIC(QSGView)
+public:
+ QSGViewPrivate();
+ ~QSGViewPrivate();
+
+ void execute();
+ void itemGeometryChanged(QSGItem *item, const QRectF &newGeometry, const QRectF &oldGeometry);
+ void initResize();
+ void updateSize();
+ void setRootObject(QObject *);
+
+ void init();
+
+ QSize rootObjectSize() const;
+
+ QPointer<QSGItem> root;
+
+ QUrl source;
+
+ QDeclarativeEngine engine;
+ QDeclarativeComponent *component;
+ QBasicTimer resizetimer;
+
+ QSGView::ResizeMode resizeMode;
+ QSize initialSize;
+ QElapsedTimer frameTimer;
+};
+
+void QSGViewPrivate::init()
+{
+ q_func()->setSizePolicy(QSizePolicy::Preferred,QSizePolicy::Preferred);
+ QDeclarativeEnginePrivate::get(&engine)->sgContext = QSGCanvasPrivate::context;
+}
+
+QSGViewPrivate::QSGViewPrivate()
+: root(0), component(0), resizeMode(QSGView::SizeViewToRootObject), initialSize(0,0)
+{
+}
+
+QSGViewPrivate::~QSGViewPrivate()
+{
+ delete root;
+}
+
+void QSGViewPrivate::execute()
+{
+ Q_Q(QSGView);
+ if (root) {
+ delete root;
+ root = 0;
+ }
+ if (component) {
+ delete component;
+ component = 0;
+ }
+ if (!source.isEmpty()) {
+ component = new QDeclarativeComponent(&engine, source, q);
+ if (!component->isLoading()) {
+ q->continueExecute();
+ } else {
+ QObject::connect(component, SIGNAL(statusChanged(QDeclarativeComponent::Status)),
+ q, SLOT(continueExecute()));
+ }
+ }
+}
+
+void QSGViewPrivate::itemGeometryChanged(QSGItem *resizeItem, const QRectF &newGeometry, const QRectF &oldGeometry)
+{
+ Q_Q(QSGView);
+ if (resizeItem == root && resizeMode == QSGView::SizeViewToRootObject) {
+ // wait for both width and height to be changed
+ resizetimer.start(0,q);
+ }
+ QSGItemChangeListener::itemGeometryChanged(resizeItem, newGeometry, oldGeometry);
+}
+
+QSGView::QSGView(QWidget *parent, Qt::WindowFlags f)
+: QSGCanvas(*(new QSGViewPrivate), parent, f)
+{
+ d_func()->init();
+}
+
+QSGView::QSGView(const QGLFormat &format, QWidget *parent, Qt::WindowFlags f)
+: QSGCanvas(*(new QSGViewPrivate), format, parent, f)
+{
+ d_func()->init();
+}
+
+QSGView::QSGView(const QUrl &source, QWidget *parent, Qt::WindowFlags f)
+: QSGCanvas(*(new QSGViewPrivate), parent, f)
+{
+ d_func()->init();
+ setSource(source);
+}
+
+QSGView::QSGView(const QUrl &source, const QGLFormat &format, QWidget *parent, Qt::WindowFlags f)
+: QSGCanvas(*(new QSGViewPrivate), format, parent, f)
+{
+ d_func()->init();
+ setSource(source);
+}
+
+QSGView::~QSGView()
+{
+}
+
+void QSGView::setSource(const QUrl& url)
+{
+ Q_D(QSGView);
+ d->source = url;
+ d->execute();
+}
+
+QUrl QSGView::source() const
+{
+ Q_D(const QSGView);
+ return d->source;
+}
+
+QDeclarativeEngine* QSGView::engine() const
+{
+ Q_D(const QSGView);
+ return const_cast<QDeclarativeEngine *>(&d->engine);
+}
+
+QDeclarativeContext* QSGView::rootContext() const
+{
+ Q_D(const QSGView);
+ return d->engine.rootContext();
+}
+
+QSGView::Status QSGView::status() const
+{
+ Q_D(const QSGView);
+ if (!d->component)
+ return QSGView::Null;
+
+ return QSGView::Status(d->component->status());
+}
+
+QList<QDeclarativeError> QSGView::errors() const
+{
+ Q_D(const QSGView);
+ if (d->component)
+ return d->component->errors();
+ return QList<QDeclarativeError>();
+}
+
+void QSGView::setResizeMode(ResizeMode mode)
+{
+ Q_D(QSGView);
+ if (d->resizeMode == mode)
+ return;
+
+ if (d->root) {
+ if (d->resizeMode == SizeViewToRootObject) {
+ QSGItemPrivate *p = QSGItemPrivate::get(d->root);
+ p->removeItemChangeListener(d, QSGItemPrivate::Geometry);
+ }
+ }
+
+ d->resizeMode = mode;
+ if (d->root) {
+ d->initResize();
+ }
+}
+
+void QSGViewPrivate::initResize()
+{
+ if (root) {
+ if (resizeMode == QSGView::SizeViewToRootObject) {
+ QSGItemPrivate *p = QSGItemPrivate::get(root);
+ p->addItemChangeListener(this, QSGItemPrivate::Geometry);
+ }
+ }
+ updateSize();
+}
+
+void QSGViewPrivate::updateSize()
+{
+ Q_Q(QSGView);
+ if (!root)
+ return;
+
+ if (resizeMode == QSGView::SizeViewToRootObject) {
+ QSize newSize = QSize(root->width(), root->height());
+ if (newSize.isValid() && newSize != q->size()) {
+ q->resize(newSize);
+ }
+ } else if (resizeMode == QSGView::SizeRootObjectToView) {
+ if (!qFuzzyCompare(q->width(), root->width()))
+ root->setWidth(q->width());
+ if (!qFuzzyCompare(q->height(), root->height()))
+ root->setHeight(q->height());
+ }
+
+ q->updateGeometry();
+}
+
+QSize QSGViewPrivate::rootObjectSize() const
+{
+ QSize rootObjectSize(0,0);
+ int widthCandidate = -1;
+ int heightCandidate = -1;
+ if (root) {
+ widthCandidate = root->width();
+ heightCandidate = root->height();
+ }
+ if (widthCandidate > 0) {
+ rootObjectSize.setWidth(widthCandidate);
+ }
+ if (heightCandidate > 0) {
+ rootObjectSize.setHeight(heightCandidate);
+ }
+ return rootObjectSize;
+}
+
+QSGView::ResizeMode QSGView::resizeMode() const
+{
+ Q_D(const QSGView);
+ return d->resizeMode;
+}
+
+/*!
+ \internal
+ */
+void QSGView::continueExecute()
+{
+ Q_D(QSGView);
+ disconnect(d->component, SIGNAL(statusChanged(QDeclarativeComponent::Status)), this, SLOT(continueExecute()));
+
+ if (d->component->isError()) {
+ QList<QDeclarativeError> errorList = d->component->errors();
+ foreach (const QDeclarativeError &error, errorList) {
+ qWarning() << error;
+ }
+ emit statusChanged(status());
+ return;
+ }
+
+ QObject *obj = d->component->create();
+
+ if(d->component->isError()) {
+ QList<QDeclarativeError> errorList = d->component->errors();
+ foreach (const QDeclarativeError &error, errorList) {
+ qWarning() << error;
+ }
+ emit statusChanged(status());
+ return;
+ }
+
+ d->setRootObject(obj);
+ emit statusChanged(status());
+}
+
+
+/*!
+ \internal
+*/
+void QSGViewPrivate::setRootObject(QObject *obj)
+{
+ Q_Q(QSGView);
+ if (root == obj)
+ return;
+ if (QSGItem *sgItem = qobject_cast<QSGItem *>(obj)) {
+ root = sgItem;
+ sgItem->setParentItem(q->QSGCanvas::rootItem());
+ } else {
+ qWarning() << "QSGView only supports loading of root objects that derive from QSGItem." << endl
+ << endl
+ << "If your example is using QML 2, (such as qmlscene) and the .qml file you" << endl
+ << "loaded has 'import QtQuick 1.0' or 'import Qt 4.7', this error will occur." << endl
+ << endl
+ << "To load files with 'import QtQuick 1.0' with QML 2, specify:" << endl
+ << " QMLSCENE_IMPORT_NAME=quick1" << endl
+ << "on as an environment variable prior to launching the application." << endl
+ << endl
+ << "To load files with 'import Qt 4.7' with QML 2, specify:" << endl
+ << " QMLSCENE_IMPORT_NAME=qt" << endl
+ << "on as an environment variable prior to launching the application." << endl;
+ delete obj;
+ root = 0;
+ }
+
+ if (root) {
+ initialSize = rootObjectSize();
+ if (initialSize != q->size()) {
+ if (!(q->parentWidget() && q->parentWidget()->layout())) {
+ q->resize(initialSize);
+ }
+ }
+ initResize();
+ }
+}
+
+/*!
+ \internal
+ If the \l {QTimerEvent} {timer event} \a e is this
+ view's resize timer, sceneResized() is emitted.
+ */
+void QSGView::timerEvent(QTimerEvent* e)
+{
+ Q_D(QSGView);
+ if (!e || e->timerId() == d->resizetimer.timerId()) {
+ d->updateSize();
+ d->resizetimer.stop();
+ }
+}
+
+/*!
+ \internal
+ Preferred size follows the root object geometry.
+*/
+QSize QSGView::sizeHint() const
+{
+ Q_D(const QSGView);
+ QSize rootObjectSize = d->rootObjectSize();
+ if (rootObjectSize.isEmpty()) {
+ return size();
+ } else {
+ return rootObjectSize;
+ }
+}
+
+QSize QSGView::initialSize() const
+{
+ Q_D(const QSGView);
+ return d->initialSize;
+}
+
+QSGItem *QSGView::rootObject() const
+{
+ Q_D(const QSGView);
+ return d->root;
+}
+
+/*!
+ \internal
+ This function handles the \l {QResizeEvent} {resize event}
+ \a e.
+ */
+void QSGView::resizeEvent(QResizeEvent *e)
+{
+ Q_D(QSGView);
+ if (d->resizeMode == SizeRootObjectToView)
+ d->updateSize();
+
+ QSGCanvas::resizeEvent(e);
+}
+
+/*!
+ \internal
+*/
+void QSGView::paintEvent(QPaintEvent *event)
+{
+ Q_D(QSGView);
+ int time = 0;
+ if (frameRateDebug())
+ time = d->frameTimer.restart();
+
+ QSGCanvas::paintEvent(event);
+
+ if (frameRateDebug())
+ qDebug() << "paintEvent:" << d->frameTimer.elapsed() << "time since last frame:" << time;
+}
+
+void QSGView::keyPressEvent(QKeyEvent *e)
+{
+ QDeclarativeDebugTrace::addEvent(QDeclarativeDebugTrace::Key);
+
+ QSGCanvas::keyPressEvent(e);
+}
+
+void QSGView::keyReleaseEvent(QKeyEvent *e)
+{
+ QDeclarativeDebugTrace::addEvent(QDeclarativeDebugTrace::Key);
+
+ QSGCanvas::keyReleaseEvent(e);
+}
+
+void QSGView::mouseMoveEvent(QMouseEvent *e)
+{
+ QDeclarativeDebugTrace::addEvent(QDeclarativeDebugTrace::Mouse);
+
+ QSGCanvas::mouseMoveEvent(e);
+}
+
+void QSGView::mousePressEvent(QMouseEvent *e)
+{
+ QDeclarativeDebugTrace::addEvent(QDeclarativeDebugTrace::Mouse);
+
+ QSGCanvas::mousePressEvent(e);
+}
+
+void QSGView::mouseReleaseEvent(QMouseEvent *e)
+{
+ QDeclarativeDebugTrace::addEvent(QDeclarativeDebugTrace::Mouse);
+
+ QSGCanvas::mouseReleaseEvent(e);
+}
+
+
+QT_END_NAMESPACE
diff --git a/src/declarative/items/qsgview.h b/src/declarative/items/qsgview.h
new file mode 100644
index 0000000000..242017df6b
--- /dev/null
+++ b/src/declarative/items/qsgview.h
@@ -0,0 +1,122 @@
+// Commit: 0b83a2161261be525f01359397ab1c8c34827749
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGVIEW_H
+#define QSGVIEW_H
+
+#include <QtCore/qurl.h>
+#include <qsgcanvas.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QDeclarativeEngine;
+class QDeclarativeContext;
+class QDeclarativeError;
+class QSGItem;
+
+class QSGViewPrivate;
+class Q_DECLARATIVE_EXPORT QSGView : public QSGCanvas
+{
+ Q_OBJECT
+ Q_PROPERTY(ResizeMode resizeMode READ resizeMode WRITE setResizeMode)
+ Q_PROPERTY(Status status READ status NOTIFY statusChanged)
+ Q_PROPERTY(QUrl source READ source WRITE setSource DESIGNABLE true)
+ Q_ENUMS(ResizeMode Status)
+public:
+ explicit QSGView(QWidget *parent = 0, Qt::WindowFlags f = 0);
+ explicit QSGView(const QGLFormat &format, QWidget *parent = 0, Qt::WindowFlags f = 0);
+ QSGView(const QUrl &source, QWidget *parent = 0, Qt::WindowFlags f = 0);
+ QSGView(const QUrl &source, const QGLFormat &format, QWidget *parent = 0, Qt::WindowFlags f = 0);
+ virtual ~QSGView();
+
+ QUrl source() const;
+
+ QDeclarativeEngine* engine() const;
+ QDeclarativeContext* rootContext() const;
+
+ QSGItem *rootObject() const;
+
+ enum ResizeMode { SizeViewToRootObject, SizeRootObjectToView };
+ ResizeMode resizeMode() const;
+ void setResizeMode(ResizeMode);
+
+ enum Status { Null, Ready, Loading, Error };
+ Status status() const;
+
+ QList<QDeclarativeError> errors() const;
+
+ QSize sizeHint() const;
+ QSize initialSize() const;
+
+public Q_SLOTS:
+ void setSource(const QUrl&);
+
+Q_SIGNALS:
+ void statusChanged(QSGView::Status);
+
+private Q_SLOTS:
+ void continueExecute();
+
+protected:
+ virtual void resizeEvent(QResizeEvent *);
+ virtual void paintEvent(QPaintEvent *event);
+ virtual void timerEvent(QTimerEvent*);
+
+ virtual void keyPressEvent(QKeyEvent *);
+ virtual void keyReleaseEvent(QKeyEvent *);
+ virtual void mousePressEvent(QMouseEvent *);
+ virtual void mouseReleaseEvent(QMouseEvent *);
+ virtual void mouseMoveEvent(QMouseEvent *);
+private:
+ Q_DISABLE_COPY(QSGView)
+ Q_DECLARE_PRIVATE(QSGView)
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QSGVIEW_H
diff --git a/src/declarative/items/qsgvisualitemmodel.cpp b/src/declarative/items/qsgvisualitemmodel.cpp
new file mode 100644
index 0000000000..daf67b573a
--- /dev/null
+++ b/src/declarative/items/qsgvisualitemmodel.cpp
@@ -0,0 +1,1254 @@
+// Commit: dcb9148091cbf6872b60407c301d7c92427583a6
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgvisualitemmodel_p.h"
+#include "qsgitem.h"
+
+#include <QtDeclarative/qdeclarativecontext.h>
+#include <QtDeclarative/qdeclarativeengine.h>
+#include <QtDeclarative/qdeclarativeexpression.h>
+#include <QtDeclarative/qdeclarativeinfo.h>
+
+#include <private/qdeclarativecontext_p.h>
+#include <private/qdeclarativepackage_p.h>
+#include <private/qdeclarativeopenmetaobject_p.h>
+#include <private/qdeclarativelistaccessor_p.h>
+#include <private/qdeclarativedata_p.h>
+#include <private/qdeclarativepropertycache_p.h>
+#include <private/qdeclarativeguard_p.h>
+#include <private/qdeclarativeglobal_p.h>
+#include <private/qlistmodelinterface_p.h>
+#include <private/qmetaobjectbuilder_p.h>
+#include <private/qobject_p.h>
+
+#include <QtCore/qhash.h>
+#include <QtCore/qlist.h>
+
+QT_BEGIN_NAMESPACE
+
+QHash<QObject*, QSGVisualItemModelAttached*> QSGVisualItemModelAttached::attachedProperties;
+
+
+class QSGVisualItemModelPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QSGVisualItemModel)
+public:
+ QSGVisualItemModelPrivate() : QObjectPrivate() {}
+
+ static void children_append(QDeclarativeListProperty<QSGItem> *prop, QSGItem *item) {
+ QDeclarative_setParent_noEvent(item, prop->object);
+ static_cast<QSGVisualItemModelPrivate *>(prop->data)->children.append(Item(item));
+ static_cast<QSGVisualItemModelPrivate *>(prop->data)->itemAppended();
+ static_cast<QSGVisualItemModelPrivate *>(prop->data)->emitChildrenChanged();
+ }
+
+ static int children_count(QDeclarativeListProperty<QSGItem> *prop) {
+ return static_cast<QSGVisualItemModelPrivate *>(prop->data)->children.count();
+ }
+
+ static QSGItem *children_at(QDeclarativeListProperty<QSGItem> *prop, int index) {
+ return static_cast<QSGVisualItemModelPrivate *>(prop->data)->children.at(index).item;
+ }
+
+ void itemAppended() {
+ Q_Q(QSGVisualItemModel);
+ QSGVisualItemModelAttached *attached = QSGVisualItemModelAttached::properties(children.last().item);
+ attached->setIndex(children.count()-1);
+ emit q->itemsInserted(children.count()-1, 1);
+ emit q->countChanged();
+ }
+
+ void emitChildrenChanged() {
+ Q_Q(QSGVisualItemModel);
+ emit q->childrenChanged();
+ }
+
+ int indexOf(QSGItem *item) const {
+ for (int i = 0; i < children.count(); ++i)
+ if (children.at(i).item == item)
+ return i;
+ return -1;
+ }
+
+ class Item {
+ public:
+ Item(QSGItem *i) : item(i), ref(0) {}
+
+ void addRef() { ++ref; }
+ bool deref() { return --ref == 0; }
+
+ QSGItem *item;
+ int ref;
+ };
+
+ QList<Item> children;
+};
+
+QSGVisualItemModel::QSGVisualItemModel(QObject *parent)
+ : QSGVisualModel(*(new QSGVisualItemModelPrivate), parent)
+{
+}
+
+QDeclarativeListProperty<QSGItem> QSGVisualItemModel::children()
+{
+ Q_D(QSGVisualItemModel);
+ return QDeclarativeListProperty<QSGItem>(this, d, d->children_append,
+ d->children_count, d->children_at);
+}
+
+int QSGVisualItemModel::count() const
+{
+ Q_D(const QSGVisualItemModel);
+ return d->children.count();
+}
+
+bool QSGVisualItemModel::isValid() const
+{
+ return true;
+}
+
+QSGItem *QSGVisualItemModel::item(int index, bool)
+{
+ Q_D(QSGVisualItemModel);
+ QSGVisualItemModelPrivate::Item &item = d->children[index];
+ item.addRef();
+ return item.item;
+}
+
+QSGVisualModel::ReleaseFlags QSGVisualItemModel::release(QSGItem *item)
+{
+ Q_D(QSGVisualItemModel);
+ int idx = d->indexOf(item);
+ if (idx >= 0) {
+ if (d->children[idx].deref()) {
+ // XXX todo - the original did item->scene()->removeItem(). Why?
+ item->setParentItem(0);
+ QDeclarative_setParent_noEvent(item, this);
+ }
+ }
+ return 0;
+}
+
+bool QSGVisualItemModel::completePending() const
+{
+ return false;
+}
+
+void QSGVisualItemModel::completeItem()
+{
+ // Nothing to do
+}
+
+QString QSGVisualItemModel::stringValue(int index, const QString &name)
+{
+ Q_D(QSGVisualItemModel);
+ if (index < 0 || index >= d->children.count())
+ return QString();
+ return QDeclarativeEngine::contextForObject(d->children.at(index).item)->contextProperty(name).toString();
+}
+
+int QSGVisualItemModel::indexOf(QSGItem *item, QObject *) const
+{
+ Q_D(const QSGVisualItemModel);
+ return d->indexOf(item);
+}
+
+QSGVisualItemModelAttached *QSGVisualItemModel::qmlAttachedProperties(QObject *obj)
+{
+ return QSGVisualItemModelAttached::properties(obj);
+}
+
+//============================================================================
+
+class VDMDelegateDataType : public QDeclarativeOpenMetaObjectType
+{
+public:
+ VDMDelegateDataType(const QMetaObject *base, QDeclarativeEngine *engine) : QDeclarativeOpenMetaObjectType(base, engine) {}
+
+ void propertyCreated(int, QMetaPropertyBuilder &prop) {
+ prop.setWritable(false);
+ }
+};
+
+class QSGVisualDataModelParts;
+class QSGVisualDataModelData;
+class QSGVisualDataModelPrivate : public QObjectPrivate
+{
+public:
+ QSGVisualDataModelPrivate(QDeclarativeContext *);
+
+ static QSGVisualDataModelPrivate *get(QSGVisualDataModel *m) {
+ return static_cast<QSGVisualDataModelPrivate *>(QObjectPrivate::get(m));
+ }
+
+ QDeclarativeGuard<QListModelInterface> m_listModelInterface;
+ QDeclarativeGuard<QAbstractItemModel> m_abstractItemModel;
+ QDeclarativeGuard<QSGVisualDataModel> m_visualItemModel;
+ QString m_part;
+
+ QDeclarativeComponent *m_delegate;
+ QDeclarativeGuard<QDeclarativeContext> m_context;
+ QList<int> m_roles;
+ QHash<QByteArray,int> m_roleNames;
+ void ensureRoles() {
+ if (m_roleNames.isEmpty()) {
+ if (m_listModelInterface) {
+ m_roles = m_listModelInterface->roles();
+ for (int ii = 0; ii < m_roles.count(); ++ii)
+ m_roleNames.insert(m_listModelInterface->toString(m_roles.at(ii)).toUtf8(), m_roles.at(ii));
+ } else if (m_abstractItemModel) {
+ for (QHash<int,QByteArray>::const_iterator it = m_abstractItemModel->roleNames().begin();
+ it != m_abstractItemModel->roleNames().end(); ++it) {
+ m_roles.append(it.key());
+ m_roleNames.insert(*it, it.key());
+ }
+ if (m_roles.count())
+ m_roleNames.insert("hasModelChildren", -1);
+ } else if (m_listAccessor) {
+ m_roleNames.insert("modelData", 0);
+ if (m_listAccessor->type() == QDeclarativeListAccessor::Instance) {
+ if (QObject *object = m_listAccessor->at(0).value<QObject*>()) {
+ int count = object->metaObject()->propertyCount();
+ for (int ii = 1; ii < count; ++ii) {
+ const QMetaProperty &prop = object->metaObject()->property(ii);
+ m_roleNames.insert(prop.name(), 0);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ QHash<int,int> m_roleToPropId;
+ int m_modelDataPropId;
+ void createMetaData() {
+ if (!m_metaDataCreated) {
+ ensureRoles();
+ if (m_roleNames.count()) {
+ QHash<QByteArray, int>::const_iterator it = m_roleNames.begin();
+ while (it != m_roleNames.end()) {
+ int propId = m_delegateDataType->createProperty(it.key()) - m_delegateDataType->propertyOffset();
+ m_roleToPropId.insert(*it, propId);
+ ++it;
+ }
+ // Add modelData property
+ if (m_roles.count() == 1)
+ m_modelDataPropId = m_delegateDataType->createProperty("modelData") - m_delegateDataType->propertyOffset();
+ m_metaDataCreated = true;
+ }
+ }
+ }
+
+ struct ObjectRef {
+ ObjectRef(QObject *object=0) : obj(object), ref(1) {}
+ QObject *obj;
+ int ref;
+ };
+ class Cache : public QHash<int, ObjectRef> {
+ public:
+ QObject *getItem(int index) {
+ QObject *item = 0;
+ QHash<int,ObjectRef>::iterator it = find(index);
+ if (it != end()) {
+ (*it).ref++;
+ item = (*it).obj;
+ }
+ return item;
+ }
+ QObject *item(int index) {
+ QObject *item = 0;
+ QHash<int, ObjectRef>::const_iterator it = find(index);
+ if (it != end())
+ item = (*it).obj;
+ return item;
+ }
+ void insertItem(int index, QObject *obj) {
+ insert(index, ObjectRef(obj));
+ }
+ bool releaseItem(QObject *obj) {
+ QHash<int, ObjectRef>::iterator it = begin();
+ for (; it != end(); ++it) {
+ ObjectRef &objRef = *it;
+ if (objRef.obj == obj) {
+ if (--objRef.ref == 0) {
+ erase(it);
+ return true;
+ }
+ break;
+ }
+ }
+ return false;
+ }
+ };
+
+ int modelCount() const {
+ if (m_visualItemModel)
+ return m_visualItemModel->count();
+ if (m_listModelInterface)
+ return m_listModelInterface->count();
+ if (m_abstractItemModel)
+ return m_abstractItemModel->rowCount(m_root);
+ if (m_listAccessor)
+ return m_listAccessor->count();
+ return 0;
+ }
+
+ Cache m_cache;
+ QHash<QObject *, QDeclarativePackage*> m_packaged;
+
+ QSGVisualDataModelParts *m_parts;
+ friend class QSGVisualItemParts;
+
+ VDMDelegateDataType *m_delegateDataType;
+ friend class QSGVisualDataModelData;
+ bool m_metaDataCreated : 1;
+ bool m_metaDataCacheable : 1;
+ bool m_delegateValidated : 1;
+ bool m_completePending : 1;
+
+ QSGVisualDataModelData *data(QObject *item);
+
+ QVariant m_modelVariant;
+ QDeclarativeListAccessor *m_listAccessor;
+
+ QModelIndex m_root;
+ QList<QByteArray> watchedRoles;
+ QList<int> watchedRoleIds;
+};
+
+class QSGVisualDataModelDataMetaObject : public QDeclarativeOpenMetaObject
+{
+public:
+ QSGVisualDataModelDataMetaObject(QObject *parent, QDeclarativeOpenMetaObjectType *type)
+ : QDeclarativeOpenMetaObject(parent, type) {}
+
+ virtual QVariant initialValue(int);
+ virtual int createProperty(const char *, const char *);
+
+private:
+ friend class QSGVisualDataModelData;
+};
+
+class QSGVisualDataModelData : public QObject
+{
+Q_OBJECT
+public:
+ QSGVisualDataModelData(int index, QSGVisualDataModel *model);
+ ~QSGVisualDataModelData();
+
+ Q_PROPERTY(int index READ index NOTIFY indexChanged)
+ int index() const;
+ void setIndex(int index);
+
+ int propForRole(int) const;
+ int modelDataPropertyId() const {
+ QSGVisualDataModelPrivate *model = QSGVisualDataModelPrivate::get(m_model);
+ return model->m_modelDataPropId;
+ }
+
+ void setValue(int, const QVariant &);
+ bool hasValue(int id) const {
+ return m_meta->hasValue(id);
+ }
+
+ void ensureProperties();
+
+Q_SIGNALS:
+ void indexChanged();
+
+private:
+ friend class QSGVisualDataModelDataMetaObject;
+ int m_index;
+ QDeclarativeGuard<QSGVisualDataModel> m_model;
+ QSGVisualDataModelDataMetaObject *m_meta;
+};
+
+int QSGVisualDataModelData::propForRole(int id) const
+{
+ QSGVisualDataModelPrivate *model = QSGVisualDataModelPrivate::get(m_model);
+ QHash<int,int>::const_iterator it = model->m_roleToPropId.find(id);
+ if (it != model->m_roleToPropId.end())
+ return *it;
+
+ return -1;
+}
+
+void QSGVisualDataModelData::setValue(int id, const QVariant &val)
+{
+ m_meta->setValue(id, val);
+}
+
+int QSGVisualDataModelDataMetaObject::createProperty(const char *name, const char *type)
+{
+ QSGVisualDataModelData *data =
+ static_cast<QSGVisualDataModelData *>(object());
+
+ if (!data->m_model)
+ return -1;
+
+ QSGVisualDataModelPrivate *model = QSGVisualDataModelPrivate::get(data->m_model);
+ if (data->m_index < 0 || data->m_index >= model->modelCount())
+ return -1;
+
+ if ((!model->m_listModelInterface || !model->m_abstractItemModel) && model->m_listAccessor) {
+ if (model->m_listAccessor->type() == QDeclarativeListAccessor::ListProperty) {
+ model->ensureRoles();
+ if (qstrcmp(name,"modelData") == 0)
+ return QDeclarativeOpenMetaObject::createProperty(name, type);
+ }
+ }
+ return -1;
+}
+
+QVariant QSGVisualDataModelDataMetaObject::initialValue(int propId)
+{
+ QSGVisualDataModelData *data =
+ static_cast<QSGVisualDataModelData *>(object());
+
+ Q_ASSERT(data->m_model);
+ QSGVisualDataModelPrivate *model = QSGVisualDataModelPrivate::get(data->m_model);
+
+ QByteArray propName = name(propId);
+ if ((!model->m_listModelInterface || !model->m_abstractItemModel) && model->m_listAccessor) {
+ if (propName == "modelData") {
+ if (model->m_listAccessor->type() == QDeclarativeListAccessor::Instance) {
+ QObject *object = model->m_listAccessor->at(0).value<QObject*>();
+ return object->metaObject()->property(1).read(object); // the first property after objectName
+ }
+ return model->m_listAccessor->at(data->m_index);
+ } else {
+ // return any property of a single object instance.
+ QObject *object = model->m_listAccessor->at(data->m_index).value<QObject*>();
+ return object->property(propName);
+ }
+ } else if (model->m_listModelInterface) {
+ model->ensureRoles();
+ QHash<QByteArray,int>::const_iterator it = model->m_roleNames.find(propName);
+ if (it != model->m_roleNames.end()) {
+ QVariant value = model->m_listModelInterface->data(data->m_index, *it);
+ return value;
+ } else if (model->m_roles.count() == 1 && propName == "modelData") {
+ //for compatibility with other lists, assign modelData if there is only a single role
+ QVariant value = model->m_listModelInterface->data(data->m_index, model->m_roles.first());
+ return value;
+ }
+ } else if (model->m_abstractItemModel) {
+ model->ensureRoles();
+ QModelIndex index = model->m_abstractItemModel->index(data->m_index, 0, model->m_root);
+ if (propName == "hasModelChildren") {
+ return model->m_abstractItemModel->hasChildren(index);
+ } else {
+ QHash<QByteArray,int>::const_iterator it = model->m_roleNames.find(propName);
+ if (it != model->m_roleNames.end()) {
+ return model->m_abstractItemModel->data(index, *it);
+ } else if (model->m_roles.count() == 1 && propName == "modelData") {
+ //for compatibility with other lists, assign modelData if there is only a single role
+ return model->m_abstractItemModel->data(index, model->m_roles.first());
+ }
+ }
+ }
+ Q_ASSERT(!"Can never be reached");
+ return QVariant();
+}
+
+QSGVisualDataModelData::QSGVisualDataModelData(int index,
+ QSGVisualDataModel *model)
+: m_index(index), m_model(model),
+m_meta(new QSGVisualDataModelDataMetaObject(this, QSGVisualDataModelPrivate::get(model)->m_delegateDataType))
+{
+ ensureProperties();
+}
+
+QSGVisualDataModelData::~QSGVisualDataModelData()
+{
+}
+
+void QSGVisualDataModelData::ensureProperties()
+{
+ QSGVisualDataModelPrivate *modelPriv = QSGVisualDataModelPrivate::get(m_model);
+ if (modelPriv->m_metaDataCacheable) {
+ if (!modelPriv->m_metaDataCreated)
+ modelPriv->createMetaData();
+ if (modelPriv->m_metaDataCreated)
+ m_meta->setCached(true);
+ }
+}
+
+int QSGVisualDataModelData::index() const
+{
+ return m_index;
+}
+
+// This is internal only - it should not be set from qml
+void QSGVisualDataModelData::setIndex(int index)
+{
+ m_index = index;
+ emit indexChanged();
+}
+
+//---------------------------------------------------------------------------
+
+class QSGVisualDataModelPartsMetaObject : public QDeclarativeOpenMetaObject
+{
+public:
+ QSGVisualDataModelPartsMetaObject(QObject *parent)
+ : QDeclarativeOpenMetaObject(parent) {}
+
+ virtual void propertyCreated(int, QMetaPropertyBuilder &);
+ virtual QVariant initialValue(int);
+};
+
+class QSGVisualDataModelParts : public QObject
+{
+Q_OBJECT
+public:
+ QSGVisualDataModelParts(QSGVisualDataModel *parent);
+
+private:
+ friend class QSGVisualDataModelPartsMetaObject;
+ QSGVisualDataModel *model;
+};
+
+void QSGVisualDataModelPartsMetaObject::propertyCreated(int, QMetaPropertyBuilder &prop)
+{
+ prop.setWritable(false);
+}
+
+QVariant QSGVisualDataModelPartsMetaObject::initialValue(int id)
+{
+ QSGVisualDataModel *m = new QSGVisualDataModel;
+ m->setParent(object());
+ m->setPart(QString::fromUtf8(name(id)));
+ m->setModel(QVariant::fromValue(static_cast<QSGVisualDataModelParts *>(object())->model));
+
+ QVariant var = QVariant::fromValue((QObject *)m);
+ return var;
+}
+
+QSGVisualDataModelParts::QSGVisualDataModelParts(QSGVisualDataModel *parent)
+: QObject(parent), model(parent)
+{
+ new QSGVisualDataModelPartsMetaObject(this);
+}
+
+QSGVisualDataModelPrivate::QSGVisualDataModelPrivate(QDeclarativeContext *ctxt)
+: m_listModelInterface(0), m_abstractItemModel(0), m_visualItemModel(0), m_delegate(0)
+, m_context(ctxt), m_modelDataPropId(-1), m_parts(0), m_delegateDataType(0), m_metaDataCreated(false)
+, m_metaDataCacheable(false), m_delegateValidated(false), m_completePending(false), m_listAccessor(0)
+{
+}
+
+QSGVisualDataModelData *QSGVisualDataModelPrivate::data(QObject *item)
+{
+ QSGVisualDataModelData *dataItem =
+ item->findChild<QSGVisualDataModelData *>();
+ Q_ASSERT(dataItem);
+ return dataItem;
+}
+
+//---------------------------------------------------------------------------
+
+QSGVisualDataModel::QSGVisualDataModel()
+: QSGVisualModel(*(new QSGVisualDataModelPrivate(0)))
+{
+}
+
+QSGVisualDataModel::QSGVisualDataModel(QDeclarativeContext *ctxt, QObject *parent)
+: QSGVisualModel(*(new QSGVisualDataModelPrivate(ctxt)), parent)
+{
+}
+
+QSGVisualDataModel::~QSGVisualDataModel()
+{
+ Q_D(QSGVisualDataModel);
+ if (d->m_listAccessor)
+ delete d->m_listAccessor;
+ if (d->m_delegateDataType)
+ d->m_delegateDataType->release();
+}
+
+QVariant QSGVisualDataModel::model() const
+{
+ Q_D(const QSGVisualDataModel);
+ return d->m_modelVariant;
+}
+
+void QSGVisualDataModel::setModel(const QVariant &model)
+{
+ Q_D(QSGVisualDataModel);
+ delete d->m_listAccessor;
+ d->m_listAccessor = 0;
+ d->m_modelVariant = model;
+ if (d->m_listModelInterface) {
+ // Assume caller has released all items.
+ QObject::disconnect(d->m_listModelInterface, SIGNAL(itemsChanged(int,int,QList<int>)),
+ this, SLOT(_q_itemsChanged(int,int,QList<int>)));
+ QObject::disconnect(d->m_listModelInterface, SIGNAL(itemsInserted(int,int)),
+ this, SLOT(_q_itemsInserted(int,int)));
+ QObject::disconnect(d->m_listModelInterface, SIGNAL(itemsRemoved(int,int)),
+ this, SLOT(_q_itemsRemoved(int,int)));
+ QObject::disconnect(d->m_listModelInterface, SIGNAL(itemsMoved(int,int,int)),
+ this, SLOT(_q_itemsMoved(int,int,int)));
+ d->m_listModelInterface = 0;
+ } else if (d->m_abstractItemModel) {
+ QObject::disconnect(d->m_abstractItemModel, SIGNAL(rowsInserted(QModelIndex,int,int)),
+ this, SLOT(_q_rowsInserted(QModelIndex,int,int)));
+ QObject::disconnect(d->m_abstractItemModel, SIGNAL(rowsRemoved(QModelIndex,int,int)),
+ this, SLOT(_q_rowsRemoved(QModelIndex,int,int)));
+ QObject::disconnect(d->m_abstractItemModel, SIGNAL(dataChanged(QModelIndex,QModelIndex)),
+ this, SLOT(_q_dataChanged(QModelIndex,QModelIndex)));
+ QObject::disconnect(d->m_abstractItemModel, SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)),
+ this, SLOT(_q_rowsMoved(QModelIndex,int,int,QModelIndex,int)));
+ QObject::disconnect(d->m_abstractItemModel, SIGNAL(modelReset()), this, SLOT(_q_modelReset()));
+ QObject::disconnect(d->m_abstractItemModel, SIGNAL(layoutChanged()), this, SLOT(_q_layoutChanged()));
+ d->m_abstractItemModel = 0;
+ } else if (d->m_visualItemModel) {
+ QObject::disconnect(d->m_visualItemModel, SIGNAL(itemsInserted(int,int)),
+ this, SIGNAL(itemsInserted(int,int)));
+ QObject::disconnect(d->m_visualItemModel, SIGNAL(itemsRemoved(int,int)),
+ this, SIGNAL(itemsRemoved(int,int)));
+ QObject::disconnect(d->m_visualItemModel, SIGNAL(itemsMoved(int,int,int)),
+ this, SIGNAL(itemsMoved(int,int,int)));
+ QObject::disconnect(d->m_visualItemModel, SIGNAL(createdPackage(int,QDeclarativePackage*)),
+ this, SLOT(_q_createdPackage(int,QDeclarativePackage*)));
+ QObject::disconnect(d->m_visualItemModel, SIGNAL(destroyingPackage(QDeclarativePackage*)),
+ this, SLOT(_q_destroyingPackage(QDeclarativePackage*)));
+ d->m_visualItemModel = 0;
+ }
+
+ d->m_roles.clear();
+ d->m_roleNames.clear();
+ if (d->m_delegateDataType)
+ d->m_delegateDataType->release();
+ d->m_metaDataCreated = 0;
+ d->m_metaDataCacheable = false;
+ d->m_delegateDataType = new VDMDelegateDataType(&QSGVisualDataModelData::staticMetaObject, d->m_context?d->m_context->engine():qmlEngine(this));
+
+ QObject *object = qvariant_cast<QObject *>(model);
+ if (object && (d->m_listModelInterface = qobject_cast<QListModelInterface *>(object))) {
+ QObject::connect(d->m_listModelInterface, SIGNAL(itemsChanged(int,int,QList<int>)),
+ this, SLOT(_q_itemsChanged(int,int,QList<int>)));
+ QObject::connect(d->m_listModelInterface, SIGNAL(itemsInserted(int,int)),
+ this, SLOT(_q_itemsInserted(int,int)));
+ QObject::connect(d->m_listModelInterface, SIGNAL(itemsRemoved(int,int)),
+ this, SLOT(_q_itemsRemoved(int,int)));
+ QObject::connect(d->m_listModelInterface, SIGNAL(itemsMoved(int,int,int)),
+ this, SLOT(_q_itemsMoved(int,int,int)));
+ d->m_metaDataCacheable = true;
+ if (d->m_delegate && d->m_listModelInterface->count())
+ emit itemsInserted(0, d->m_listModelInterface->count());
+ return;
+ } else if (object && (d->m_abstractItemModel = qobject_cast<QAbstractItemModel *>(object))) {
+ QObject::connect(d->m_abstractItemModel, SIGNAL(rowsInserted(QModelIndex,int,int)),
+ this, SLOT(_q_rowsInserted(QModelIndex,int,int)));
+ QObject::connect(d->m_abstractItemModel, SIGNAL(rowsRemoved(QModelIndex,int,int)),
+ this, SLOT(_q_rowsRemoved(QModelIndex,int,int)));
+ QObject::connect(d->m_abstractItemModel, SIGNAL(dataChanged(QModelIndex,QModelIndex)),
+ this, SLOT(_q_dataChanged(QModelIndex,QModelIndex)));
+ QObject::connect(d->m_abstractItemModel, SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)),
+ this, SLOT(_q_rowsMoved(QModelIndex,int,int,QModelIndex,int)));
+ QObject::connect(d->m_abstractItemModel, SIGNAL(modelReset()), this, SLOT(_q_modelReset()));
+ QObject::connect(d->m_abstractItemModel, SIGNAL(layoutChanged()), this, SLOT(_q_layoutChanged()));
+ d->m_metaDataCacheable = true;
+ if (d->m_abstractItemModel->canFetchMore(d->m_root))
+ d->m_abstractItemModel->fetchMore(d->m_root);
+ return;
+ }
+ if ((d->m_visualItemModel = qvariant_cast<QSGVisualDataModel *>(model))) {
+ QObject::connect(d->m_visualItemModel, SIGNAL(countChanged()),
+ this, SIGNAL(countChanged()));
+ QObject::connect(d->m_visualItemModel, SIGNAL(itemsInserted(int,int)),
+ this, SIGNAL(itemsInserted(int,int)));
+ QObject::connect(d->m_visualItemModel, SIGNAL(itemsRemoved(int,int)),
+ this, SIGNAL(itemsRemoved(int,int)));
+ QObject::connect(d->m_visualItemModel, SIGNAL(itemsMoved(int,int,int)),
+ this, SIGNAL(itemsMoved(int,int,int)));
+ QObject::connect(d->m_visualItemModel, SIGNAL(createdPackage(int,QDeclarativePackage*)),
+ this, SLOT(_q_createdPackage(int,QDeclarativePackage*)));
+ QObject::connect(d->m_visualItemModel, SIGNAL(destroyingPackage(QDeclarativePackage*)),
+ this, SLOT(_q_destroyingPackage(QDeclarativePackage*)));
+ return;
+ }
+ d->m_listAccessor = new QDeclarativeListAccessor;
+ d->m_listAccessor->setList(model, d->m_context?d->m_context->engine():qmlEngine(this));
+ if (d->m_listAccessor->type() != QDeclarativeListAccessor::ListProperty)
+ d->m_metaDataCacheable = true;
+ if (d->m_delegate && d->modelCount()) {
+ emit itemsInserted(0, d->modelCount());
+ emit countChanged();
+ }
+}
+
+QDeclarativeComponent *QSGVisualDataModel::delegate() const
+{
+ Q_D(const QSGVisualDataModel);
+ if (d->m_visualItemModel)
+ return d->m_visualItemModel->delegate();
+ return d->m_delegate;
+}
+
+void QSGVisualDataModel::setDelegate(QDeclarativeComponent *delegate)
+{
+ Q_D(QSGVisualDataModel);
+ bool wasValid = d->m_delegate != 0;
+ d->m_delegate = delegate;
+ d->m_delegateValidated = false;
+ if (!wasValid && d->modelCount() && d->m_delegate) {
+ emit itemsInserted(0, d->modelCount());
+ emit countChanged();
+ }
+ if (wasValid && !d->m_delegate && d->modelCount()) {
+ emit itemsRemoved(0, d->modelCount());
+ emit countChanged();
+ }
+}
+
+QVariant QSGVisualDataModel::rootIndex() const
+{
+ Q_D(const QSGVisualDataModel);
+ return QVariant::fromValue(d->m_root);
+}
+
+void QSGVisualDataModel::setRootIndex(const QVariant &root)
+{
+ Q_D(QSGVisualDataModel);
+ QModelIndex modelIndex = qvariant_cast<QModelIndex>(root);
+ if (d->m_root != modelIndex) {
+ int oldCount = d->modelCount();
+ d->m_root = modelIndex;
+ if (d->m_abstractItemModel && d->m_abstractItemModel->canFetchMore(modelIndex))
+ d->m_abstractItemModel->fetchMore(modelIndex);
+ int newCount = d->modelCount();
+ if (d->m_delegate && oldCount)
+ emit itemsRemoved(0, oldCount);
+ if (d->m_delegate && newCount)
+ emit itemsInserted(0, newCount);
+ if (newCount != oldCount)
+ emit countChanged();
+ emit rootIndexChanged();
+ }
+}
+
+QVariant QSGVisualDataModel::modelIndex(int idx) const
+{
+ Q_D(const QSGVisualDataModel);
+ if (d->m_abstractItemModel)
+ return QVariant::fromValue(d->m_abstractItemModel->index(idx, 0, d->m_root));
+ return QVariant::fromValue(QModelIndex());
+}
+
+QVariant QSGVisualDataModel::parentModelIndex() const
+{
+ Q_D(const QSGVisualDataModel);
+ if (d->m_abstractItemModel)
+ return QVariant::fromValue(d->m_abstractItemModel->parent(d->m_root));
+ return QVariant::fromValue(QModelIndex());
+}
+
+QString QSGVisualDataModel::part() const
+{
+ Q_D(const QSGVisualDataModel);
+ return d->m_part;
+}
+
+void QSGVisualDataModel::setPart(const QString &part)
+{
+ Q_D(QSGVisualDataModel);
+ d->m_part = part;
+}
+
+int QSGVisualDataModel::count() const
+{
+ Q_D(const QSGVisualDataModel);
+ if (d->m_visualItemModel)
+ return d->m_visualItemModel->count();
+ if (!d->m_delegate)
+ return 0;
+ return d->modelCount();
+}
+
+QSGItem *QSGVisualDataModel::item(int index, bool complete)
+{
+ Q_D(QSGVisualDataModel);
+ if (d->m_visualItemModel)
+ return d->m_visualItemModel->item(index, d->m_part.toUtf8(), complete);
+ return item(index, QByteArray(), complete);
+}
+
+/*
+ Returns ReleaseStatus flags.
+*/
+QSGVisualDataModel::ReleaseFlags QSGVisualDataModel::release(QSGItem *item)
+{
+ Q_D(QSGVisualDataModel);
+ if (d->m_visualItemModel)
+ return d->m_visualItemModel->release(item);
+
+ ReleaseFlags stat = 0;
+ QObject *obj = item;
+ bool inPackage = false;
+
+ QHash<QObject*,QDeclarativePackage*>::iterator it = d->m_packaged.find(item);
+ if (it != d->m_packaged.end()) {
+ QDeclarativePackage *package = *it;
+ d->m_packaged.erase(it);
+ if (d->m_packaged.contains(item))
+ stat |= Referenced;
+ inPackage = true;
+ obj = package; // fall through and delete
+ }
+
+ if (d->m_cache.releaseItem(obj)) {
+ // Remove any bindings to avoid warnings due to parent change.
+ QObjectPrivate *p = QObjectPrivate::get(obj);
+ Q_ASSERT(p->declarativeData);
+ QDeclarativeData *d = static_cast<QDeclarativeData*>(p->declarativeData);
+ if (d->ownContext && d->context)
+ d->context->clearContext();
+
+ if (inPackage) {
+ emit destroyingPackage(qobject_cast<QDeclarativePackage*>(obj));
+ } else {
+ // XXX todo - the original did item->scene()->removeItem(). Why?
+ item->setParentItem(0);
+ }
+ stat |= Destroyed;
+ obj->deleteLater();
+ } else if (!inPackage) {
+ stat |= Referenced;
+ }
+
+ return stat;
+}
+
+QObject *QSGVisualDataModel::parts()
+{
+ Q_D(QSGVisualDataModel);
+ if (!d->m_parts)
+ d->m_parts = new QSGVisualDataModelParts(this);
+ return d->m_parts;
+}
+
+QSGItem *QSGVisualDataModel::item(int index, const QByteArray &viewId, bool complete)
+{
+ Q_D(QSGVisualDataModel);
+ if (d->m_visualItemModel)
+ return d->m_visualItemModel->item(index, viewId, complete);
+
+ if (d->modelCount() <= 0 || !d->m_delegate)
+ return 0;
+ QObject *nobj = d->m_cache.getItem(index);
+ bool needComplete = false;
+ if (!nobj) {
+ QDeclarativeContext *ccontext = d->m_context;
+ if (!ccontext) ccontext = qmlContext(this);
+ QDeclarativeContext *ctxt = new QDeclarativeContext(ccontext);
+ QSGVisualDataModelData *data = new QSGVisualDataModelData(index, this);
+ if ((!d->m_listModelInterface || !d->m_abstractItemModel) && d->m_listAccessor
+ && d->m_listAccessor->type() == QDeclarativeListAccessor::ListProperty) {
+ ctxt->setContextObject(d->m_listAccessor->at(index).value<QObject*>());
+ ctxt = new QDeclarativeContext(ctxt, ctxt);
+ }
+ ctxt->setContextProperty(QLatin1String("model"), data);
+ ctxt->setContextObject(data);
+ d->m_completePending = false;
+ nobj = d->m_delegate->beginCreate(ctxt);
+ if (complete) {
+ d->m_delegate->completeCreate();
+ } else {
+ d->m_completePending = true;
+ needComplete = true;
+ }
+ if (nobj) {
+ QDeclarative_setParent_noEvent(ctxt, nobj);
+ QDeclarative_setParent_noEvent(data, nobj);
+ d->m_cache.insertItem(index, nobj);
+ if (QDeclarativePackage *package = qobject_cast<QDeclarativePackage *>(nobj))
+ emit createdPackage(index, package);
+ } else {
+ delete data;
+ delete ctxt;
+ qmlInfo(this, d->m_delegate->errors()) << "Error creating delegate";
+ }
+ }
+ QSGItem *item = qobject_cast<QSGItem *>(nobj);
+ if (!item) {
+ QDeclarativePackage *package = qobject_cast<QDeclarativePackage *>(nobj);
+ if (package) {
+ QObject *o = package->part(QString::fromUtf8(viewId));
+ item = qobject_cast<QSGItem *>(o);
+ if (item)
+ d->m_packaged.insertMulti(item, package);
+ }
+ }
+ if (!item) {
+ if (needComplete)
+ d->m_delegate->completeCreate();
+ d->m_cache.releaseItem(nobj);
+ if (!d->m_delegateValidated) {
+ qmlInfo(d->m_delegate) << QSGVisualDataModel::tr("Delegate component must be Item type.");
+ d->m_delegateValidated = true;
+ }
+ }
+ if (d->modelCount()-1 == index && d->m_abstractItemModel && d->m_abstractItemModel->canFetchMore(d->m_root))
+ d->m_abstractItemModel->fetchMore(d->m_root);
+
+ return item;
+}
+
+bool QSGVisualDataModel::completePending() const
+{
+ Q_D(const QSGVisualDataModel);
+ if (d->m_visualItemModel)
+ return d->m_visualItemModel->completePending();
+ return d->m_completePending;
+}
+
+void QSGVisualDataModel::completeItem()
+{
+ Q_D(QSGVisualDataModel);
+ if (d->m_visualItemModel) {
+ d->m_visualItemModel->completeItem();
+ return;
+ }
+
+ d->m_delegate->completeCreate();
+ d->m_completePending = false;
+}
+
+QString QSGVisualDataModel::stringValue(int index, const QString &name)
+{
+ Q_D(QSGVisualDataModel);
+ if (d->m_visualItemModel)
+ return d->m_visualItemModel->stringValue(index, name);
+
+ if ((!d->m_listModelInterface || !d->m_abstractItemModel) && d->m_listAccessor) {
+ if (QObject *object = d->m_listAccessor->at(index).value<QObject*>())
+ return object->property(name.toUtf8()).toString();
+ }
+
+ if ((!d->m_listModelInterface && !d->m_abstractItemModel) || !d->m_delegate)
+ return QString();
+
+ QString val;
+ QObject *data = 0;
+ bool tempData = false;
+
+ if (QObject *nobj = d->m_cache.item(index))
+ data = d->data(nobj);
+ if (!data) {
+ data = new QSGVisualDataModelData(index, this);
+ tempData = true;
+ }
+
+ QDeclarativeData *ddata = QDeclarativeData::get(data);
+ if (ddata && ddata->propertyCache) {
+ QDeclarativePropertyCache::Data *prop = ddata->propertyCache->property(name);
+ if (prop) {
+ if (prop->propType == QVariant::String) {
+ void *args[] = { &val, 0 };
+ QMetaObject::metacall(data, QMetaObject::ReadProperty, prop->coreIndex, args);
+ } else if (prop->propType == qMetaTypeId<QVariant>()) {
+ QVariant v;
+ void *args[] = { &v, 0 };
+ QMetaObject::metacall(data, QMetaObject::ReadProperty, prop->coreIndex, args);
+ val = v.toString();
+ }
+ } else {
+ val = data->property(name.toUtf8()).toString();
+ }
+ } else {
+ val = data->property(name.toUtf8()).toString();
+ }
+
+ if (tempData)
+ delete data;
+
+ return val;
+}
+
+int QSGVisualDataModel::indexOf(QSGItem *item, QObject *) const
+{
+ QVariant val = QDeclarativeEngine::contextForObject(item)->contextProperty(QLatin1String("index"));
+ return val.toInt();
+ return -1;
+}
+
+void QSGVisualDataModel::setWatchedRoles(QList<QByteArray> roles)
+{
+ Q_D(QSGVisualDataModel);
+ d->watchedRoles = roles;
+ d->watchedRoleIds.clear();
+}
+
+void QSGVisualDataModel::_q_itemsChanged(int index, int count,
+ const QList<int> &roles)
+{
+ Q_D(QSGVisualDataModel);
+ bool changed = false;
+ if (!d->watchedRoles.isEmpty() && d->watchedRoleIds.isEmpty()) {
+ foreach (QByteArray r, d->watchedRoles) {
+ if (d->m_roleNames.contains(r))
+ d->watchedRoleIds << d->m_roleNames.value(r);
+ }
+ }
+
+ for (QHash<int,QSGVisualDataModelPrivate::ObjectRef>::ConstIterator iter = d->m_cache.begin();
+ iter != d->m_cache.end(); ++iter) {
+ const int idx = iter.key();
+
+ if (idx >= index && idx < index+count) {
+ QSGVisualDataModelPrivate::ObjectRef objRef = *iter;
+ QSGVisualDataModelData *data = d->data(objRef.obj);
+ for (int roleIdx = 0; roleIdx < roles.count(); ++roleIdx) {
+ int role = roles.at(roleIdx);
+ if (!changed && !d->watchedRoleIds.isEmpty() && d->watchedRoleIds.contains(role))
+ changed = true;
+ int propId = data->propForRole(role);
+ if (propId != -1) {
+ if (data->hasValue(propId)) {
+ if (d->m_listModelInterface) {
+ data->setValue(propId, d->m_listModelInterface->data(idx, role));
+ } else if (d->m_abstractItemModel) {
+ QModelIndex index = d->m_abstractItemModel->index(idx, 0, d->m_root);
+ data->setValue(propId, d->m_abstractItemModel->data(index, role));
+ }
+ }
+ } else {
+ QString roleName;
+ if (d->m_listModelInterface)
+ roleName = d->m_listModelInterface->toString(role);
+ else if (d->m_abstractItemModel)
+ roleName = QString::fromUtf8(d->m_abstractItemModel->roleNames().value(role));
+ qmlInfo(this) << "Changing role not present in item: " << roleName;
+ }
+ }
+ if (d->m_roles.count() == 1) {
+ // Handle the modelData role we add if there is just one role.
+ int propId = data->modelDataPropertyId();
+ if (data->hasValue(propId)) {
+ int role = d->m_roles.at(0);
+ if (d->m_listModelInterface) {
+ data->setValue(propId, d->m_listModelInterface->data(idx, role));
+ } else if (d->m_abstractItemModel) {
+ QModelIndex index = d->m_abstractItemModel->index(idx, 0, d->m_root);
+ data->setValue(propId, d->m_abstractItemModel->data(index, role));
+ }
+ }
+ }
+ }
+ }
+ if (changed)
+ emit itemsChanged(index, count);
+}
+
+void QSGVisualDataModel::_q_itemsInserted(int index, int count)
+{
+ Q_D(QSGVisualDataModel);
+ if (!count)
+ return;
+ // XXX - highly inefficient
+ QHash<int,QSGVisualDataModelPrivate::ObjectRef> items;
+ for (QHash<int,QSGVisualDataModelPrivate::ObjectRef>::Iterator iter = d->m_cache.begin();
+ iter != d->m_cache.end(); ) {
+
+ if (iter.key() >= index) {
+ QSGVisualDataModelPrivate::ObjectRef objRef = *iter;
+ int index = iter.key() + count;
+ iter = d->m_cache.erase(iter);
+
+ items.insert(index, objRef);
+
+ QSGVisualDataModelData *data = d->data(objRef.obj);
+ data->setIndex(index);
+ } else {
+ ++iter;
+ }
+ }
+ d->m_cache.unite(items);
+
+ emit itemsInserted(index, count);
+ emit countChanged();
+}
+
+void QSGVisualDataModel::_q_itemsRemoved(int index, int count)
+{
+ Q_D(QSGVisualDataModel);
+ if (!count)
+ return;
+ // XXX - highly inefficient
+ QHash<int, QSGVisualDataModelPrivate::ObjectRef> items;
+ for (QHash<int, QSGVisualDataModelPrivate::ObjectRef>::Iterator iter = d->m_cache.begin();
+ iter != d->m_cache.end(); ) {
+ if (iter.key() >= index && iter.key() < index + count) {
+ QSGVisualDataModelPrivate::ObjectRef objRef = *iter;
+ iter = d->m_cache.erase(iter);
+ items.insertMulti(-1, objRef); //XXX perhaps better to maintain separately
+ QSGVisualDataModelData *data = d->data(objRef.obj);
+ data->setIndex(-1);
+ } else if (iter.key() >= index + count) {
+ QSGVisualDataModelPrivate::ObjectRef objRef = *iter;
+ int index = iter.key() - count;
+ iter = d->m_cache.erase(iter);
+ items.insert(index, objRef);
+ QSGVisualDataModelData *data = d->data(objRef.obj);
+ data->setIndex(index);
+ } else {
+ ++iter;
+ }
+ }
+
+ d->m_cache.unite(items);
+ emit itemsRemoved(index, count);
+ emit countChanged();
+}
+
+void QSGVisualDataModel::_q_itemsMoved(int from, int to, int count)
+{
+ Q_D(QSGVisualDataModel);
+ // XXX - highly inefficient
+ QHash<int,QSGVisualDataModelPrivate::ObjectRef> items;
+ for (QHash<int,QSGVisualDataModelPrivate::ObjectRef>::Iterator iter = d->m_cache.begin();
+ iter != d->m_cache.end(); ) {
+
+ if (iter.key() >= from && iter.key() < from + count) {
+ QSGVisualDataModelPrivate::ObjectRef objRef = *iter;
+ int index = iter.key() - from + to;
+ iter = d->m_cache.erase(iter);
+
+ items.insert(index, objRef);
+
+ QSGVisualDataModelData *data = d->data(objRef.obj);
+ data->setIndex(index);
+ } else {
+ ++iter;
+ }
+ }
+ for (QHash<int,QSGVisualDataModelPrivate::ObjectRef>::Iterator iter = d->m_cache.begin();
+ iter != d->m_cache.end(); ) {
+
+ int diff = from > to ? count : -count;
+ if (iter.key() >= qMin(from,to) && iter.key() < qMax(from+count,to+count)) {
+ QSGVisualDataModelPrivate::ObjectRef objRef = *iter;
+ int index = iter.key() + diff;
+ iter = d->m_cache.erase(iter);
+
+ items.insert(index, objRef);
+
+ QSGVisualDataModelData *data = d->data(objRef.obj);
+ data->setIndex(index);
+ } else {
+ ++iter;
+ }
+ }
+ d->m_cache.unite(items);
+
+ emit itemsMoved(from, to, count);
+}
+
+void QSGVisualDataModel::_q_rowsInserted(const QModelIndex &parent, int begin, int end)
+{
+ Q_D(QSGVisualDataModel);
+ if (parent == d->m_root)
+ _q_itemsInserted(begin, end - begin + 1);
+}
+
+void QSGVisualDataModel::_q_rowsRemoved(const QModelIndex &parent, int begin, int end)
+{
+ Q_D(QSGVisualDataModel);
+ if (parent == d->m_root)
+ _q_itemsRemoved(begin, end - begin + 1);
+}
+
+void QSGVisualDataModel::_q_rowsMoved(const QModelIndex &sourceParent, int sourceStart, int sourceEnd, const QModelIndex &destinationParent, int destinationRow)
+{
+ Q_D(QSGVisualDataModel);
+ const int count = sourceEnd - sourceStart + 1;
+ if (destinationParent == d->m_root && sourceParent == d->m_root) {
+ _q_itemsMoved(sourceStart, sourceStart > destinationRow ? destinationRow : destinationRow-1, count);
+ } else if (sourceParent == d->m_root) {
+ _q_itemsRemoved(sourceStart, count);
+ } else if (destinationParent == d->m_root) {
+ _q_itemsInserted(destinationRow, count);
+ }
+}
+
+void QSGVisualDataModel::_q_dataChanged(const QModelIndex &begin, const QModelIndex &end)
+{
+ Q_D(QSGVisualDataModel);
+ if (begin.parent() == d->m_root)
+ _q_itemsChanged(begin.row(), end.row() - begin.row() + 1, d->m_roles);
+}
+
+void QSGVisualDataModel::_q_layoutChanged()
+{
+ Q_D(QSGVisualDataModel);
+ _q_itemsChanged(0, count(), d->m_roles);
+}
+
+void QSGVisualDataModel::_q_modelReset()
+{
+ Q_D(QSGVisualDataModel);
+ d->m_root = QModelIndex();
+ emit modelReset();
+ emit rootIndexChanged();
+ if (d->m_abstractItemModel && d->m_abstractItemModel->canFetchMore(d->m_root))
+ d->m_abstractItemModel->fetchMore(d->m_root);
+}
+
+void QSGVisualDataModel::_q_createdPackage(int index, QDeclarativePackage *package)
+{
+ Q_D(QSGVisualDataModel);
+ emit createdItem(index, qobject_cast<QSGItem*>(package->part(d->m_part)));
+}
+
+void QSGVisualDataModel::_q_destroyingPackage(QDeclarativePackage *package)
+{
+ Q_D(QSGVisualDataModel);
+ emit destroyingItem(qobject_cast<QSGItem*>(package->part(d->m_part)));
+}
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QListModelInterface)
+
+#include <qsgvisualitemmodel.moc>
diff --git a/src/declarative/items/qsgvisualitemmodel_p.h b/src/declarative/items/qsgvisualitemmodel_p.h
new file mode 100644
index 0000000000..62f89905ac
--- /dev/null
+++ b/src/declarative/items/qsgvisualitemmodel_p.h
@@ -0,0 +1,257 @@
+// Commit: ac5c099cc3c5b8c7eec7a49fdeb8a21037230350
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGVISUALITEMMODEL_P_H
+#define QSGVISUALITEMMODEL_P_H
+
+#include <QtDeclarative/qdeclarative.h>
+#include <QtCore/qobject.h>
+#include <QtCore/qabstractitemmodel.h>
+
+QT_BEGIN_HEADER
+
+Q_DECLARE_METATYPE(QModelIndex)
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QSGItem;
+class QDeclarativeComponent;
+class QDeclarativePackage;
+class QSGVisualDataModelPrivate;
+
+class Q_DECLARATIVE_EXPORT QSGVisualModel : public QObject
+{
+ Q_OBJECT
+
+ Q_PROPERTY(int count READ count NOTIFY countChanged)
+
+public:
+ virtual ~QSGVisualModel() {}
+
+ enum ReleaseFlag { Referenced = 0x01, Destroyed = 0x02 };
+ Q_DECLARE_FLAGS(ReleaseFlags, ReleaseFlag)
+
+ virtual int count() const = 0;
+ virtual bool isValid() const = 0;
+ virtual QSGItem *item(int index, bool complete=true) = 0;
+ virtual ReleaseFlags release(QSGItem *item) = 0;
+ virtual bool completePending() const = 0;
+ virtual void completeItem() = 0;
+ virtual QString stringValue(int, const QString &) = 0;
+ virtual void setWatchedRoles(QList<QByteArray> roles) = 0;
+
+ virtual int indexOf(QSGItem *item, QObject *objectContext) const = 0;
+
+Q_SIGNALS:
+ void countChanged();
+ 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);
+ void modelReset();
+ void createdItem(int index, QSGItem *item);
+ void destroyingItem(QSGItem *item);
+
+protected:
+ QSGVisualModel(QObjectPrivate &dd, QObject *parent = 0)
+ : QObject(dd, parent) {}
+
+private:
+ Q_DISABLE_COPY(QSGVisualModel)
+};
+
+class QSGVisualItemModelAttached;
+class QSGVisualItemModelPrivate;
+class Q_DECLARATIVE_EXPORT QSGVisualItemModel : public QSGVisualModel
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QSGVisualItemModel)
+
+ Q_PROPERTY(QDeclarativeListProperty<QSGItem> children READ children NOTIFY childrenChanged DESIGNABLE false)
+ Q_CLASSINFO("DefaultProperty", "children")
+
+public:
+ QSGVisualItemModel(QObject *parent=0);
+ virtual ~QSGVisualItemModel() {}
+
+ virtual int count() const;
+ virtual bool isValid() const;
+ virtual QSGItem *item(int index, bool complete=true);
+ virtual ReleaseFlags release(QSGItem *item);
+ virtual bool completePending() const;
+ virtual void completeItem();
+ virtual QString stringValue(int index, const QString &role);
+ virtual void setWatchedRoles(QList<QByteArray>) {}
+
+ virtual int indexOf(QSGItem *item, QObject *objectContext) const;
+
+ QDeclarativeListProperty<QSGItem> children();
+
+ static QSGVisualItemModelAttached *qmlAttachedProperties(QObject *obj);
+
+Q_SIGNALS:
+ void childrenChanged();
+
+private:
+ Q_DISABLE_COPY(QSGVisualItemModel)
+};
+
+
+class Q_DECLARATIVE_EXPORT QSGVisualDataModel : public QSGVisualModel
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QSGVisualDataModel)
+
+ Q_PROPERTY(QVariant model READ model WRITE setModel)
+ Q_PROPERTY(QDeclarativeComponent *delegate READ delegate WRITE setDelegate)
+ Q_PROPERTY(QString part READ part WRITE setPart)
+ Q_PROPERTY(QObject *parts READ parts CONSTANT)
+ Q_PROPERTY(QVariant rootIndex READ rootIndex WRITE setRootIndex NOTIFY rootIndexChanged)
+ Q_CLASSINFO("DefaultProperty", "delegate")
+public:
+ QSGVisualDataModel();
+ QSGVisualDataModel(QDeclarativeContext *, QObject *parent=0);
+ virtual ~QSGVisualDataModel();
+
+ QVariant model() const;
+ void setModel(const QVariant &);
+
+ QDeclarativeComponent *delegate() const;
+ void setDelegate(QDeclarativeComponent *);
+
+ QVariant rootIndex() const;
+ void setRootIndex(const QVariant &root);
+
+ Q_INVOKABLE QVariant modelIndex(int idx) const;
+ Q_INVOKABLE QVariant parentModelIndex() const;
+
+ QString part() const;
+ void setPart(const QString &);
+
+ int count() const;
+ bool isValid() const { return delegate() != 0; }
+ QSGItem *item(int index, bool complete=true);
+ QSGItem *item(int index, const QByteArray &, bool complete=true);
+ ReleaseFlags release(QSGItem *item);
+ bool completePending() const;
+ void completeItem();
+ virtual QString stringValue(int index, const QString &role);
+ virtual void setWatchedRoles(QList<QByteArray> roles);
+
+ int indexOf(QSGItem *item, QObject *objectContext) const;
+
+ QObject *parts();
+
+Q_SIGNALS:
+ void createdPackage(int index, QDeclarativePackage *package);
+ void destroyingPackage(QDeclarativePackage *package);
+ void rootIndexChanged();
+
+private Q_SLOTS:
+ void _q_itemsChanged(int, int, const QList<int> &);
+ void _q_itemsInserted(int index, int count);
+ void _q_itemsRemoved(int index, int count);
+ void _q_itemsMoved(int from, int to, int count);
+ void _q_rowsInserted(const QModelIndex &,int,int);
+ void _q_rowsRemoved(const QModelIndex &,int,int);
+ void _q_rowsMoved(const QModelIndex &, int, int, const QModelIndex &, int);
+ void _q_dataChanged(const QModelIndex&,const QModelIndex&);
+ void _q_layoutChanged();
+ void _q_modelReset();
+ void _q_createdPackage(int index, QDeclarativePackage *package);
+ void _q_destroyingPackage(QDeclarativePackage *package);
+
+private:
+ Q_DISABLE_COPY(QSGVisualDataModel)
+};
+
+class QSGVisualItemModelAttached : public QObject
+{
+ Q_OBJECT
+
+public:
+ QSGVisualItemModelAttached(QObject *parent)
+ : QObject(parent), m_index(0) {}
+ ~QSGVisualItemModelAttached() {
+ attachedProperties.remove(parent());
+ }
+
+ Q_PROPERTY(int index READ index NOTIFY indexChanged)
+ int index() const { return m_index; }
+ void setIndex(int idx) {
+ if (m_index != idx) {
+ m_index = idx;
+ emit indexChanged();
+ }
+ }
+
+ static QSGVisualItemModelAttached *properties(QObject *obj) {
+ QSGVisualItemModelAttached *rv = attachedProperties.value(obj);
+ if (!rv) {
+ rv = new QSGVisualItemModelAttached(obj);
+ attachedProperties.insert(obj, rv);
+ }
+ return rv;
+ }
+
+Q_SIGNALS:
+ void indexChanged();
+
+public:
+ int m_index;
+
+ static QHash<QObject*, QSGVisualItemModelAttached*> attachedProperties;
+};
+
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QSGVisualModel)
+QML_DECLARE_TYPE(QSGVisualItemModel)
+QML_DECLARE_TYPEINFO(QSGVisualItemModel, QML_HAS_ATTACHED_PROPERTIES)
+QML_DECLARE_TYPE(QSGVisualDataModel)
+
+QT_END_HEADER
+
+#endif // QSGVISUALITEMMODEL_P_H
diff --git a/src/declarative/items/syncexcludes b/src/declarative/items/syncexcludes
new file mode 100644
index 0000000000..ab7a374a5b
--- /dev/null
+++ b/src/declarative/items/syncexcludes
@@ -0,0 +1,11 @@
+qdeclarativegraphicswidget.cpp
+qdeclarativegraphicswidget_p.h
+qdeclarativetextlayout_p.h
+qdeclarativetextlayout.cpp
+qdeclarativelayoutitem.cpp
+qdeclarativelayoutitem_p.h
+qdeclarativefocuspanel.cpp
+qdeclarativefocuspanel_p.h
+qdeclarativepath_p.h
+qdeclarativepath_p_p.h
+qdeclarativepath.cpp
diff --git a/src/declarative/qml/parser/qdeclarativejs.g b/src/declarative/qml/parser/qdeclarativejs.g
index 590edf82b8..a57ecba3f9 100644
--- a/src/declarative/qml/parser/qdeclarativejs.g
+++ b/src/declarative/qml/parser/qdeclarativejs.g
@@ -127,10 +127,10 @@
#include <string.h>
-#include "private/qdeclarativejsengine_p.h"
-#include "private/qdeclarativejslexer_p.h"
-#include "private/qdeclarativejsast_p.h"
-#include "private/qdeclarativejsnodepool_p.h"
+#include "qdeclarativejsengine_p.h"
+#include "qdeclarativejslexer_p.h"
+#include "qdeclarativejsast_p.h"
+#include "qdeclarativejsnodepool_p.h"
./
@@ -195,10 +195,10 @@
#ifndef QDECLARATIVEJSPARSER_P_H
#define QDECLARATIVEJSPARSER_P_H
-#include "private/qdeclarativejsglobal_p.h"
-#include "private/qdeclarativejsgrammar_p.h"
-#include "private/qdeclarativejsast_p.h"
-#include "private/qdeclarativejsengine_p.h"
+#include "qdeclarativejsglobal_p.h"
+#include "qdeclarativejsgrammar_p.h"
+#include "qdeclarativejsast_p.h"
+#include "qdeclarativejsengine_p.h"
#include <QtCore/QList>
#include <QtCore/QString>
@@ -375,7 +375,7 @@ protected:
/.
-#include "private/qdeclarativejsparser_p.h"
+#include "qdeclarativejsparser_p.h"
#include <QVarLengthArray>
//
@@ -782,19 +782,14 @@ case $rule_number: {
} break;
./
-UiObjectMember: UiQualifiedId T_COLON Block ;
-/.case $rule_number:./
-
-UiObjectMember: UiQualifiedId T_COLON EmptyStatement ;
-/.case $rule_number:./
-
-UiObjectMember: UiQualifiedId T_COLON ExpressionStatement ;
-/.case $rule_number:./
-
-UiObjectMember: UiQualifiedId T_COLON IfStatement ; --- ### do we really want if statement in a binding?
-/.case $rule_number:./
+UiScriptStatement: Block ;
+UiScriptStatement: EmptyStatement ;
+UiScriptStatement: ExpressionStatement ;
+UiScriptStatement: IfStatement ; --- ### do we really want if statement in a binding?
+UiObjectMember: UiQualifiedId T_COLON UiScriptStatement ;
/.
+case $rule_number:
{
AST::UiScriptBinding *node = makeAstNode<AST::UiScriptBinding> (driver->nodePool(),
sym(1).UiQualifiedId, sym(3).Statement);
@@ -922,51 +917,45 @@ case $rule_number: {
} break;
./
-UiObjectMember: T_PROPERTY UiPropertyType JsIdentifier T_COLON Expression T_AUTOMATIC_SEMICOLON ;
-UiObjectMember: T_PROPERTY UiPropertyType JsIdentifier T_COLON Expression T_SEMICOLON ;
+UiObjectMember: T_PROPERTY UiPropertyType JsIdentifier T_COLON UiScriptStatement ;
/.
case $rule_number: {
AST::UiPublicMember *node = makeAstNode<AST::UiPublicMember> (driver->nodePool(), sym(2).sval, sym(3).sval,
- sym(5).Expression);
+ sym(5).Statement);
node->propertyToken = loc(1);
node->typeToken = loc(2);
node->identifierToken = loc(3);
node->colonToken = loc(4);
- node->semicolonToken = loc(6);
sym(1).Node = node;
} break;
./
-UiObjectMember: T_READONLY T_PROPERTY UiPropertyType JsIdentifier T_COLON Expression T_AUTOMATIC_SEMICOLON ;
-UiObjectMember: T_READONLY T_PROPERTY UiPropertyType JsIdentifier T_COLON Expression T_SEMICOLON ;
+UiObjectMember: T_READONLY T_PROPERTY UiPropertyType JsIdentifier T_COLON UiScriptStatement ;
/.
case $rule_number: {
AST::UiPublicMember *node = makeAstNode<AST::UiPublicMember> (driver->nodePool(), sym(3).sval, sym(4).sval,
- sym(6).Expression);
+ 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);
- node->semicolonToken = loc(7);
sym(1).Node = node;
} break;
./
-UiObjectMember: T_DEFAULT T_PROPERTY UiPropertyType JsIdentifier T_COLON Expression T_AUTOMATIC_SEMICOLON ;
-UiObjectMember: T_DEFAULT T_PROPERTY UiPropertyType JsIdentifier T_COLON Expression T_SEMICOLON ;
+UiObjectMember: T_DEFAULT T_PROPERTY UiPropertyType JsIdentifier T_COLON UiScriptStatement ;
/.
case $rule_number: {
AST::UiPublicMember *node = makeAstNode<AST::UiPublicMember> (driver->nodePool(), sym(3).sval, sym(4).sval,
- sym(6).Expression);
+ 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);
- node->semicolonToken = loc(7);
sym(1).Node = node;
} break;
./
diff --git a/src/declarative/qml/parser/qdeclarativejsast.cpp b/src/declarative/qml/parser/qdeclarativejsast.cpp
index 297130b459..8aff1ad4d0 100644
--- a/src/declarative/qml/parser/qdeclarativejsast.cpp
+++ b/src/declarative/qml/parser/qdeclarativejsast.cpp
@@ -39,9 +39,9 @@
**
****************************************************************************/
-#include "private/qdeclarativejsast_p.h"
+#include "qdeclarativejsast_p.h"
-#include "private/qdeclarativejsastvisitor_p.h"
+#include "qdeclarativejsastvisitor_p.h"
QT_QML_BEGIN_NAMESPACE
@@ -836,7 +836,7 @@ void UiFormal::accept0(Visitor *visitor)
void UiPublicMember::accept0(Visitor *visitor)
{
if (visitor->visit(this)) {
- accept(expression, visitor);
+ accept(statement, visitor);
accept(binding, visitor);
}
diff --git a/src/declarative/qml/parser/qdeclarativejsast_p.h b/src/declarative/qml/parser/qdeclarativejsast_p.h
index 8ff558bde0..69d878af13 100644
--- a/src/declarative/qml/parser/qdeclarativejsast_p.h
+++ b/src/declarative/qml/parser/qdeclarativejsast_p.h
@@ -53,8 +53,8 @@
// We mean it.
//
-#include "private/qdeclarativejsastvisitor_p.h"
-#include "private/qdeclarativejsglobal_p.h"
+#include "qdeclarativejsastvisitor_p.h"
+#include "qdeclarativejsglobal_p.h"
#include <QtCore/QString>
@@ -2342,13 +2342,13 @@ public:
UiPublicMember(NameId *memberType,
NameId *name)
- : type(Property), typeModifier(0), memberType(memberType), name(name), expression(0), binding(0), isDefaultMember(false), isReadonlyMember(false), parameters(0)
+ : type(Property), typeModifier(0), memberType(memberType), name(name), statement(0), binding(0), isDefaultMember(false), isReadonlyMember(false), parameters(0)
{ kind = K; }
UiPublicMember(NameId *memberType,
NameId *name,
- ExpressionNode *expression)
- : type(Property), typeModifier(0), memberType(memberType), name(name), expression(expression), binding(0), isDefaultMember(false), isReadonlyMember(false), parameters(0)
+ Statement *statement)
+ : type(Property), typeModifier(0), memberType(memberType), name(name), statement(statement), binding(0), isDefaultMember(false), isReadonlyMember(false), parameters(0)
{ kind = K; }
virtual SourceLocation firstSourceLocation() const
@@ -2376,7 +2376,7 @@ public:
NameId *typeModifier;
NameId *memberType;
NameId *name;
- ExpressionNode *expression; // initialized with a JS expression
+ Statement *statement; // initialized with a JS expression
UiObjectMember *binding; // initialized with a QML object or array.
bool isDefaultMember;
bool isReadonlyMember;
diff --git a/src/declarative/qml/parser/qdeclarativejsastfwd_p.h b/src/declarative/qml/parser/qdeclarativejsastfwd_p.h
index f37459895f..fbc983a7ef 100644
--- a/src/declarative/qml/parser/qdeclarativejsastfwd_p.h
+++ b/src/declarative/qml/parser/qdeclarativejsastfwd_p.h
@@ -42,7 +42,7 @@
#ifndef QDECLARATIVEJSAST_FWD_P_H
#define QDECLARATIVEJSAST_FWD_P_H
-#include "private/qdeclarativejsglobal_p.h"
+#include "qdeclarativejsglobal_p.h"
#include <QtCore/qglobal.h>
diff --git a/src/declarative/qml/parser/qdeclarativejsastvisitor.cpp b/src/declarative/qml/parser/qdeclarativejsastvisitor.cpp
index 276b269406..35720e0106 100644
--- a/src/declarative/qml/parser/qdeclarativejsastvisitor.cpp
+++ b/src/declarative/qml/parser/qdeclarativejsastvisitor.cpp
@@ -39,7 +39,7 @@
**
****************************************************************************/
-#include "private/qdeclarativejsastvisitor_p.h"
+#include "qdeclarativejsastvisitor_p.h"
QT_QML_BEGIN_NAMESPACE
diff --git a/src/declarative/qml/parser/qdeclarativejsastvisitor_p.h b/src/declarative/qml/parser/qdeclarativejsastvisitor_p.h
index df44fdc60d..8f51066e2a 100644
--- a/src/declarative/qml/parser/qdeclarativejsastvisitor_p.h
+++ b/src/declarative/qml/parser/qdeclarativejsastvisitor_p.h
@@ -53,8 +53,8 @@
// We mean it.
//
-#include "private/qdeclarativejsastfwd_p.h"
-#include "private/qdeclarativejsglobal_p.h"
+#include "qdeclarativejsastfwd_p.h"
+#include "qdeclarativejsglobal_p.h"
QT_QML_BEGIN_NAMESPACE
diff --git a/src/declarative/qml/parser/qdeclarativejsengine_p.cpp b/src/declarative/qml/parser/qdeclarativejsengine_p.cpp
index 7f9ad91062..a449f779b7 100644
--- a/src/declarative/qml/parser/qdeclarativejsengine_p.cpp
+++ b/src/declarative/qml/parser/qdeclarativejsengine_p.cpp
@@ -39,10 +39,10 @@
**
****************************************************************************/
-#include "private/qdeclarativejsengine_p.h"
+#include "qdeclarativejsengine_p.h"
-#include "private/qdeclarativejsglobal_p.h"
-#include "private/qdeclarativejsnodepool_p.h"
+#include "qdeclarativejsglobal_p.h"
+#include "qdeclarativejsnodepool_p.h"
#include <qnumeric.h>
#include <QHash>
diff --git a/src/declarative/qml/parser/qdeclarativejsengine_p.h b/src/declarative/qml/parser/qdeclarativejsengine_p.h
index 409c2a3c53..e366e8b9b3 100644
--- a/src/declarative/qml/parser/qdeclarativejsengine_p.h
+++ b/src/declarative/qml/parser/qdeclarativejsengine_p.h
@@ -53,8 +53,8 @@
// We mean it.
//
-#include "private/qdeclarativejsglobal_p.h"
-#include "private/qdeclarativejsastfwd_p.h"
+#include "qdeclarativejsglobal_p.h"
+#include "qdeclarativejsastfwd_p.h"
#include <QString>
#include <QSet>
diff --git a/src/declarative/qml/parser/qdeclarativejsglobal_p.h b/src/declarative/qml/parser/qdeclarativejsglobal_p.h
index aefc204df3..83b5b95a2f 100644
--- a/src/declarative/qml/parser/qdeclarativejsglobal_p.h
+++ b/src/declarative/qml/parser/qdeclarativejsglobal_p.h
@@ -58,7 +58,7 @@
#else // !QT_CREATOR
# define QT_QML_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
# define QT_QML_END_NAMESPACE QT_END_NAMESPACE
-# define QML_PARSER_EXPORT
+# define QML_PARSER_EXPORT Q_AUTOTEST_EXPORT
#endif // QT_CREATOR
#endif // QDECLARATIVEJSGLOBAL_P_H
diff --git a/src/declarative/qml/parser/qdeclarativejsgrammar.cpp b/src/declarative/qml/parser/qdeclarativejsgrammar.cpp
index c48cf2b997..38bd46bfcf 100644
--- a/src/declarative/qml/parser/qdeclarativejsgrammar.cpp
+++ b/src/declarative/qml/parser/qdeclarativejsgrammar.cpp
@@ -61,462 +61,469 @@ const short QDeclarativeJSGrammar::lhs [] = {
101, 101, 101, 101, 101, 101, 102, 108, 108, 111,
111, 113, 112, 112, 112, 112, 112, 112, 112, 112,
115, 110, 109, 118, 118, 119, 119, 120, 120, 117,
- 106, 106, 106, 106, 106, 106, 106, 106, 126, 126,
- 126, 127, 127, 128, 128, 106, 106, 106, 106, 106,
+ 106, 106, 106, 106, 122, 122, 122, 122, 106, 127,
+ 127, 127, 128, 128, 129, 129, 106, 106, 106, 106,
106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
- 106, 106, 106, 106, 106, 116, 116, 116, 116, 116,
- 131, 131, 131, 131, 131, 131, 131, 131, 131, 131,
- 131, 131, 131, 131, 131, 131, 131, 131, 121, 133,
- 133, 133, 133, 132, 132, 135, 135, 137, 137, 137,
- 137, 137, 137, 138, 138, 138, 138, 138, 138, 138,
- 138, 138, 138, 138, 138, 138, 138, 138, 138, 138,
- 138, 138, 138, 138, 138, 138, 138, 138, 138, 138,
- 138, 138, 138, 138, 139, 139, 114, 114, 114, 114,
- 114, 142, 142, 143, 143, 143, 143, 141, 141, 144,
- 144, 145, 145, 146, 146, 146, 147, 147, 147, 147,
- 147, 147, 147, 147, 147, 147, 148, 148, 148, 148,
- 149, 149, 149, 150, 150, 150, 150, 151, 151, 151,
- 151, 151, 151, 151, 152, 152, 152, 152, 152, 152,
- 153, 153, 153, 153, 153, 154, 154, 154, 154, 154,
- 155, 155, 156, 156, 157, 157, 158, 158, 159, 159,
- 160, 160, 161, 161, 162, 162, 163, 163, 164, 164,
- 165, 165, 166, 166, 136, 136, 167, 167, 168, 168,
- 168, 168, 168, 168, 168, 168, 168, 168, 168, 168,
- 104, 104, 169, 169, 170, 170, 171, 171, 103, 103,
+ 106, 106, 106, 116, 116, 116, 116, 116, 132, 132,
+ 132, 132, 132, 132, 132, 132, 132, 132, 132, 132,
+ 132, 132, 132, 132, 132, 132, 121, 134, 134, 134,
+ 134, 133, 133, 136, 136, 138, 138, 138, 138, 138,
+ 138, 139, 139, 139, 139, 139, 139, 139, 139, 139,
+ 139, 139, 139, 139, 139, 139, 139, 139, 139, 139,
+ 139, 139, 139, 139, 139, 139, 139, 139, 139, 139,
+ 139, 139, 140, 140, 114, 114, 114, 114, 114, 143,
+ 143, 144, 144, 144, 144, 142, 142, 145, 145, 146,
+ 146, 147, 147, 147, 148, 148, 148, 148, 148, 148,
+ 148, 148, 148, 148, 149, 149, 149, 149, 150, 150,
+ 150, 151, 151, 151, 151, 152, 152, 152, 152, 152,
+ 152, 152, 153, 153, 153, 153, 153, 153, 154, 154,
+ 154, 154, 154, 155, 155, 155, 155, 155, 156, 156,
+ 157, 157, 158, 158, 159, 159, 160, 160, 161, 161,
+ 162, 162, 163, 163, 164, 164, 165, 165, 166, 166,
+ 167, 167, 137, 137, 168, 168, 169, 169, 169, 169,
+ 169, 169, 169, 169, 169, 169, 169, 169, 104, 104,
+ 170, 170, 171, 171, 172, 172, 103, 103, 103, 103,
103, 103, 103, 103, 103, 103, 103, 103, 103, 103,
- 103, 103, 103, 122, 183, 183, 182, 182, 130, 130,
- 184, 184, 185, 185, 187, 187, 186, 188, 191, 189,
- 189, 192, 190, 190, 123, 124, 124, 125, 125, 172,
- 172, 172, 172, 172, 172, 172, 173, 173, 173, 173,
- 174, 174, 174, 174, 175, 175, 176, 178, 193, 193,
- 196, 196, 194, 194, 197, 195, 177, 177, 177, 179,
- 179, 180, 180, 180, 198, 199, 181, 181, 129, 140,
- 203, 203, 200, 200, 201, 201, 204, 107, 205, 205,
- 105, 105, 202, 202, 134, 134, 206};
+ 103, 123, 184, 184, 183, 183, 131, 131, 185, 185,
+ 186, 186, 188, 188, 187, 189, 192, 190, 190, 193,
+ 191, 191, 124, 125, 125, 126, 126, 173, 173, 173,
+ 173, 173, 173, 173, 174, 174, 174, 174, 175, 175,
+ 175, 175, 176, 176, 177, 179, 194, 194, 197, 197,
+ 195, 195, 198, 196, 178, 178, 178, 180, 180, 181,
+ 181, 181, 199, 200, 182, 182, 130, 141, 204, 204,
+ 201, 201, 202, 202, 205, 107, 206, 206, 105, 105,
+ 203, 203, 135, 135, 207};
const short QDeclarativeJSGrammar::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, 3, 3, 3, 3, 1, 1,
- 1, 0, 1, 2, 4, 6, 6, 3, 3, 7,
- 7, 4, 4, 5, 5, 6, 6, 7, 7, 7,
- 7, 10, 6, 1, 1, 1, 1, 1, 1, 1,
+ 1, 5, 4, 4, 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,
- 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, 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, 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, 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, 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, 2,
- 1, 1, 0, 1, 0, 1, 2};
+ 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, 2, 1, 1,
+ 0, 1, 0, 1, 2};
const short QDeclarativeJSGrammar::action_default [] = {
- 0, 0, 0, 0, 0, 0, 22, 0, 174, 241,
- 205, 213, 209, 153, 225, 201, 3, 138, 72, 154,
- 217, 221, 142, 171, 152, 157, 137, 191, 178, 0,
- 79, 80, 75, 343, 66, 345, 0, 0, 0, 0,
- 77, 0, 0, 73, 76, 70, 0, 0, 67, 69,
- 68, 78, 71, 0, 74, 0, 0, 167, 0, 0,
- 154, 173, 156, 155, 0, 0, 0, 169, 170, 168,
- 172, 0, 202, 0, 0, 0, 0, 192, 0, 0,
- 0, 0, 0, 0, 182, 0, 0, 0, 176, 177,
- 175, 180, 184, 183, 181, 179, 194, 193, 195, 0,
- 210, 0, 206, 0, 0, 148, 135, 147, 136, 104,
- 105, 106, 131, 107, 132, 108, 109, 110, 111, 112,
- 113, 114, 115, 116, 117, 118, 119, 120, 133, 121,
- 122, 123, 124, 125, 126, 127, 128, 129, 130, 134,
- 0, 0, 146, 242, 149, 0, 150, 0, 151, 145,
- 0, 238, 231, 229, 236, 237, 235, 234, 240, 233,
- 232, 230, 239, 226, 0, 214, 0, 0, 218, 0,
- 0, 222, 0, 0, 148, 140, 0, 139, 0, 144,
- 158, 0, 344, 333, 334, 0, 331, 0, 332, 0,
- 335, 249, 256, 255, 263, 251, 0, 252, 336, 0,
- 342, 253, 254, 259, 257, 339, 337, 341, 260, 0,
- 271, 0, 0, 0, 0, 343, 66, 0, 345, 67,
- 243, 285, 68, 0, 0, 0, 272, 0, 0, 261,
- 262, 0, 250, 258, 286, 287, 330, 340, 0, 301,
- 302, 303, 304, 0, 297, 298, 299, 300, 327, 328,
- 0, 0, 0, 0, 0, 290, 291, 247, 245, 207,
- 215, 211, 227, 203, 248, 0, 154, 219, 223, 196,
- 185, 0, 0, 204, 0, 0, 0, 0, 197, 0,
- 0, 0, 0, 0, 189, 187, 190, 188, 186, 199,
- 198, 200, 0, 212, 0, 208, 0, 246, 154, 0,
- 228, 243, 244, 0, 243, 0, 0, 293, 0, 0,
- 0, 295, 0, 216, 0, 0, 220, 0, 0, 224,
- 283, 0, 275, 284, 278, 0, 282, 0, 243, 276,
- 0, 243, 0, 0, 294, 0, 0, 0, 296, 344,
- 333, 0, 0, 335, 0, 329, 0, 319, 0, 0,
- 0, 289, 0, 288, 0, 346, 0, 103, 265, 268,
- 0, 104, 271, 107, 132, 109, 110, 75, 114, 115,
- 66, 116, 119, 73, 76, 67, 243, 68, 78, 122,
- 71, 124, 74, 126, 127, 272, 129, 130, 134, 0,
- 96, 0, 0, 98, 102, 100, 87, 99, 101, 0,
- 97, 86, 266, 264, 142, 143, 148, 0, 141, 0,
- 318, 0, 305, 306, 0, 317, 0, 0, 0, 308,
- 313, 311, 314, 0, 0, 312, 313, 0, 309, 0,
- 310, 267, 316, 0, 267, 315, 0, 320, 321, 0,
- 267, 322, 323, 0, 0, 324, 0, 0, 0, 325,
- 326, 160, 159, 0, 0, 0, 292, 0, 0, 0,
- 307, 280, 273, 0, 281, 277, 0, 279, 269, 0,
- 270, 274, 90, 0, 0, 94, 81, 0, 83, 92,
- 0, 84, 93, 95, 85, 91, 82, 0, 88, 164,
- 162, 166, 163, 161, 165, 6, 338, 4, 2, 64,
- 89, 0, 0, 67, 69, 68, 31, 5, 0, 65,
- 0, 41, 40, 39, 0, 0, 54, 0, 55, 0,
- 60, 61, 0, 41, 0, 0, 0, 0, 0, 50,
- 0, 51, 0, 0, 26, 0, 0, 62, 27, 0,
- 30, 28, 24, 0, 29, 25, 0, 52, 0, 53,
- 0, 142, 0, 56, 57, 63, 0, 0, 0, 0,
- 0, 58, 59, 0, 48, 42, 49, 43, 0, 0,
- 0, 0, 45, 0, 46, 47, 44, 0, 0, 35,
- 36, 37, 38, 142, 267, 0, 0, 104, 271, 107,
- 132, 109, 110, 75, 114, 115, 66, 116, 119, 73,
- 76, 67, 243, 68, 78, 122, 71, 124, 74, 126,
- 127, 272, 129, 130, 134, 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, 347};
+ 0, 0, 0, 0, 0, 0, 22, 0, 172, 239,
+ 203, 211, 207, 151, 223, 199, 3, 136, 70, 152,
+ 215, 219, 140, 169, 150, 155, 135, 189, 176, 0,
+ 77, 78, 73, 341, 64, 343, 0, 0, 0, 0,
+ 75, 0, 0, 71, 74, 68, 0, 0, 65, 67,
+ 66, 76, 69, 0, 72, 0, 0, 165, 0, 0,
+ 152, 171, 154, 153, 0, 0, 0, 167, 168, 166,
+ 170, 0, 200, 0, 0, 0, 0, 190, 0, 0,
+ 0, 0, 0, 0, 180, 0, 0, 0, 174, 175,
+ 173, 178, 182, 181, 179, 177, 192, 191, 193, 0,
+ 208, 0, 204, 0, 0, 146, 133, 145, 134, 102,
+ 103, 104, 129, 105, 130, 106, 107, 108, 109, 110,
+ 111, 112, 113, 114, 115, 116, 117, 118, 131, 119,
+ 120, 121, 122, 123, 124, 125, 126, 127, 128, 132,
+ 0, 0, 144, 240, 147, 0, 148, 0, 149, 143,
+ 0, 236, 229, 227, 234, 235, 233, 232, 238, 231,
+ 230, 228, 237, 224, 0, 212, 0, 0, 216, 0,
+ 0, 220, 0, 0, 146, 138, 0, 137, 0, 142,
+ 156, 0, 342, 331, 332, 0, 329, 0, 330, 0,
+ 333, 247, 254, 253, 261, 249, 0, 250, 334, 0,
+ 340, 251, 252, 257, 255, 337, 335, 339, 258, 0,
+ 269, 0, 0, 0, 0, 341, 64, 0, 343, 65,
+ 241, 283, 66, 0, 0, 0, 270, 0, 0, 259,
+ 260, 0, 248, 256, 284, 285, 328, 338, 0, 299,
+ 300, 301, 302, 0, 295, 296, 297, 298, 325, 326,
+ 0, 0, 0, 0, 0, 288, 289, 245, 243, 205,
+ 213, 209, 225, 201, 246, 0, 152, 217, 221, 194,
+ 183, 0, 0, 202, 0, 0, 0, 0, 195, 0,
+ 0, 0, 0, 0, 187, 185, 188, 186, 184, 197,
+ 196, 198, 0, 210, 0, 206, 0, 244, 152, 0,
+ 226, 241, 242, 0, 241, 0, 0, 291, 0, 0,
+ 0, 293, 0, 214, 0, 0, 218, 0, 0, 222,
+ 281, 0, 273, 282, 276, 0, 280, 0, 241, 274,
+ 0, 241, 0, 0, 292, 0, 0, 0, 294, 342,
+ 331, 0, 0, 333, 0, 327, 0, 317, 0, 0,
+ 0, 287, 0, 286, 0, 344, 0, 101, 263, 266,
+ 0, 102, 269, 105, 130, 107, 108, 73, 112, 113,
+ 64, 114, 117, 71, 74, 65, 241, 66, 76, 120,
+ 69, 122, 72, 124, 125, 270, 127, 128, 132, 0,
+ 94, 0, 0, 96, 100, 98, 85, 97, 99, 0,
+ 95, 84, 264, 262, 140, 141, 146, 0, 139, 0,
+ 316, 0, 303, 304, 0, 315, 0, 0, 0, 306,
+ 311, 309, 312, 0, 0, 310, 311, 0, 307, 0,
+ 308, 265, 314, 0, 265, 313, 0, 318, 319, 0,
+ 265, 320, 321, 0, 0, 322, 0, 0, 0, 323,
+ 324, 158, 157, 0, 0, 0, 290, 0, 0, 0,
+ 305, 278, 271, 0, 279, 275, 0, 277, 267, 0,
+ 268, 272, 88, 0, 0, 92, 79, 0, 81, 90,
+ 0, 82, 91, 93, 83, 89, 80, 0, 86, 162,
+ 160, 164, 161, 159, 163, 6, 336, 4, 2, 62,
+ 87, 0, 0, 65, 67, 66, 31, 5, 0, 63,
+ 0, 42, 41, 40, 0, 0, 55, 0, 56, 35,
+ 36, 37, 38, 59, 0, 42, 0, 0, 0, 0,
+ 0, 51, 0, 52, 0, 0, 26, 0, 0, 60,
+ 27, 0, 30, 28, 24, 0, 29, 25, 0, 53,
+ 0, 54, 140, 0, 57, 61, 0, 0, 0, 0,
+ 58, 0, 49, 43, 50, 44, 0, 0, 0, 0,
+ 46, 0, 47, 48, 45, 0, 0, 140, 265, 0,
+ 0, 39, 102, 269, 105, 130, 107, 108, 73, 112,
+ 113, 64, 114, 117, 71, 74, 65, 241, 66, 76,
+ 120, 69, 122, 72, 124, 125, 270, 127, 128, 132,
+ 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,
+ 345};
const short QDeclarativeJSGrammar::goto_default [] = {
- 7, 626, 207, 196, 205, 507, 495, 625, 644, 620,
- 624, 622, 627, 22, 623, 18, 506, 543, 533, 540,
- 535, 191, 195, 197, 201, 524, 568, 567, 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, 233, 203, 208, 229, 230,
- 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};
+ 7, 621, 207, 196, 205, 507, 495, 620, 639, 615,
+ 619, 617, 622, 22, 618, 18, 506, 545, 535, 542,
+ 537, 523, 191, 195, 197, 201, 526, 566, 565, 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, 233, 203, 208, 229,
+ 230, 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 QDeclarativeJSGrammar::action_index [] = {
- 421, 1288, 2322, 2322, 2419, 1016, -52, 37, 140, -101,
- 35, -13, -40, 190, -101, 272, 34, -101, -101, 658,
- 42, 103, 194, 201, -101, -101, -101, 439, 256, 1288,
- -101, -101, -101, 282, -101, 2128, 1751, 1288, 1288, 1288,
- -101, 917, 1288, -101, -101, -101, 1288, 1288, -101, -101,
- -101, -101, -101, 1288, -101, 1288, 1288, -101, 1288, 1288,
- 109, 245, -101, -101, 1288, 1288, 1288, -101, -101, -101,
- 185, 1288, 295, 1288, 1288, 1288, 1288, 461, 1288, 1288,
- 1288, 1288, 1288, 1288, 256, 1288, 1288, 1288, 155, 119,
- 114, 176, 256, 332, 202, 332, 560, 560, 471, 1288,
- -23, 1288, 53, 2031, 1288, 1288, -101, -101, -101, -101,
+ 350, 1271, 2492, 2492, 2395, 999, 52, 93, 137, -101,
+ 104, 72, 66, 177, -101, 285, 80, -101, -101, 641,
+ 71, 130, 167, 178, -101, -101, -101, 431, 321, 1271,
+ -101, -101, -101, 393, -101, 2201, 2007, 1271, 1271, 1271,
+ -101, 811, 1271, -101, -101, -101, 1271, 1271, -101, -101,
+ -101, -101, -101, 1271, -101, 1271, 1271, -101, 1271, 1271,
+ 87, 188, -101, -101, 1271, 1271, 1271, -101, -101, -101,
+ 179, 1271, 263, 1271, 1271, 1271, 1271, 456, 1271, 1271,
+ 1271, 1271, 1271, 1271, 321, 1271, 1271, 1271, 128, 114,
+ 120, 193, 181, 172, 321, 321, 446, 395, 405, 1271,
+ -8, 1271, 76, 2104, 1271, 1271, -101, -101, -101, -101,
-101, -101, -101, -101, -101, -101, -101, -101, -101, -101,
-101, -101, -101, -101, -101, -101, -101, -101, -101, -101,
-101, -101, -101, -101, -101, -101, -101, -101, -101, -101,
- 100, 1288, -101, -101, 70, 59, -101, 1288, -101, -101,
- 1288, -101, -101, -101, -101, -101, -101, -101, -101, -101,
- -101, -101, -101, -101, 1288, 41, 1288, 1288, 98, 91,
- 1288, -101, 2031, 1288, 1288, -101, 121, -101, 73, -101,
- -101, 39, -101, 385, 180, 78, -101, 391, -101, 64,
- 2322, -101, -101, -101, -101, -101, 208, -101, -101, 82,
- -101, -101, -101, -101, -101, -101, 2322, -101, -101, 538,
- -101, 495, 128, 2419, 54, 358, 62, 44, 2613, 67,
- 1288, -101, 76, 63, 1288, 58, -101, 60, 46, -101,
- -101, 309, -101, -101, -101, -101, -101, -101, 86, -101,
- -101, -101, -101, 107, -101, -101, -101, -101, -101, -101,
- 28, 52, 1288, 101, 102, -101, -101, 1472, -101, 83,
- 75, 79, -101, 287, 84, 80, 585, 69, 89, 321,
- 177, 482, 1288, 297, 1288, 1288, 1288, 1288, 331, 1288,
- 1288, 1288, 1288, 1288, 332, 222, 332, 332, 332, 410,
- 410, 410, 1288, 57, 1288, 72, 1288, -101, 658, 1288,
- -101, 1288, 71, 45, 1288, 61, 2419, -101, 1288, 132,
- 2419, -101, 1288, 47, 1288, 1288, 66, 65, 1288, -101,
- 68, 112, 81, -101, -101, 1288, -101, 369, 1288, -101,
- 85, 1288, 74, 2419, -101, 1288, 122, 2419, -101, 77,
- 294, 16, -29, 2322, -53, -101, 2419, -101, 1288, 127,
- 2419, -15, 2419, -101, 10, 11, -34, -101, -101, 2419,
- -48, 504, 4, 476, 113, 1288, 2419, 2, -28, 420,
- 6, -21, 719, 7, 87, -101, 1382, -101, -4, -16,
- 5, 1288, 3, -27, 1288, 9, 1288, -18, -31, 1288,
- -101, 2225, -7, -101, -101, -101, -101, -101, -101, 1288,
- -101, -101, -101, -101, 246, -101, 1288, -38, -101, 2419,
- -101, 88, -101, -101, 2419, -101, 1288, 106, 26, -101,
- 55, -101, 50, 105, 1288, -101, 48, 38, -101, -8,
- -101, 2419, -101, 94, 2419, -101, 238, -101, -101, 104,
- 2419, 31, -101, 21, 19, -101, 305, 1, 30, -101,
- -101, -101, -101, 1288, 136, 2419, -101, 1288, 134, 2419,
- -101, 49, -101, 173, -101, -101, 1288, -101, -101, 363,
- -101, -101, -101, 137, 1565, -101, -101, 1658, -101, -101,
- 1844, -101, -101, -101, -101, -101, -101, 95, -101, -101,
- -101, -101, -101, -101, -101, -101, 2322, -101, -101, -101,
- 92, 15, 925, 169, 27, -6, -101, -101, 212, -101,
- 191, -101, -101, -101, 323, 211, -101, 1288, -101, 214,
- -101, -101, 216, 40, 317, 210, 43, 259, 236, -101,
- 36, -101, 747, 96, -101, 29, 747, -101, -101, 1198,
- -101, -101, -101, 1107, -101, -101, 231, -101, 1288, -101,
- 217, 286, 32, -101, -101, -101, 188, 340, 51, 1288,
- 175, -101, -101, 171, -101, 179, -101, 56, -11, 351,
- 181, 336, -101, 110, -101, -101, -101, 1934, 647, -101,
- -101, -101, -101, 253, 2516, 1751, -5, 460, 22, 468,
- 138, 1288, 2419, 24, -2, 412, 23, -3, 836, 20,
- 87, -101, 1382, -101, 17, -10, 18, 1288, 25, 8,
- 1288, 33, 1288, 12, 14, 120, -101, -101, 13, -101,
- -101, 747, -101, 248, -47, 828, -101, -101, 152, 482,
- -101, 150, -101, 123, -101, -101, 398, -101, -101, 117,
- -101, -101, -101, -101, -101, -101,
+ 110, 1271, -101, -101, 68, 38, -101, 1271, -101, -101,
+ 1271, -101, -101, -101, -101, -101, -101, -101, -101, -101,
+ -101, -101, -101, -101, 1271, 32, 1271, 1271, 85, 83,
+ 1271, -101, 2104, 1271, 1271, -101, 108, -101, 53, -101,
+ -101, 64, -101, 393, 89, 62, -101, 297, -101, 63,
+ 2492, -101, -101, -101, -101, -101, 154, -101, -101, 47,
+ -101, -101, -101, -101, -101, -101, 2492, -101, -101, 461,
+ -101, 470, 74, 2395, 59, 393, 92, 67, 2686, 152,
+ 1271, -101, 65, 43, 1271, 41, -101, 39, 34, -101,
+ -101, 393, -101, -101, -101, -101, -101, -101, 86, -101,
+ -101, -101, -101, 90, -101, -101, -101, -101, -101, -101,
+ -11, 50, 1271, 103, 82, -101, -101, 1455, -101, 84,
+ 44, 5, -101, 267, 70, 33, 575, 79, 69, 471,
+ 235, 393, 1271, 275, 1271, 1271, 1271, 1271, 305, 1271,
+ 1271, 1271, 1271, 1271, 229, 201, 225, 202, 321, 355,
+ 374, 380, 1271, 35, 1271, 81, 1271, -101, 641, 1271,
+ -101, 1271, 61, 1, 1271, 29, 2395, -101, 1271, 133,
+ 2395, -101, 1271, 73, 1271, 1271, 99, 97, 1271, -101,
+ 51, 153, 60, -101, -101, 1271, -101, 393, 1271, -101,
+ 56, 1271, -25, 2395, -101, 1271, 129, 2395, -101, -35,
+ 309, -56, -31, 2492, -39, -101, 2395, -101, 1271, 245,
+ 2395, -5, 2395, -101, 6, 0, -33, -101, -101, 2395,
+ -43, 543, 7, 488, 112, 1271, 2395, -1, -27, 453,
+ 8, -18, 630, 14, 16, -101, 1365, -101, 12, -19,
+ 3, 1271, 58, -30, 1271, -2, 1271, -29, -36, 1271,
+ -101, 2298, 18, -101, -101, -101, -101, -101, -101, 1271,
+ -101, -101, -101, -101, 223, -101, 1271, -10, -101, 2395,
+ -101, 95, -101, -101, 2395, -101, 1271, 107, 20, -101,
+ 40, -101, 46, 100, 1271, -101, 55, 57, -101, 28,
+ -101, 2395, -101, 118, 2395, -101, 161, -101, -101, 126,
+ 2395, 37, -101, -12, -4, -101, 393, -34, -6, -101,
+ -101, -101, -101, 1271, 98, 2395, -101, 1271, 116, 2395,
+ -101, 19, -101, 186, -101, -101, 1271, -101, -101, 303,
+ -101, -101, -101, 119, 1638, -101, -101, 1821, -101, -101,
+ 1914, -101, -101, -101, -101, -101, -101, 123, -101, -101,
+ -101, -101, -101, -101, -101, -101, 2492, -101, -101, -101,
+ 94, -26, 819, 158, -28, 4, -101, -101, 210, -101,
+ 203, -101, -101, -101, 393, 230, -101, 1545, -101, -101,
+ -101, -101, -101, -101, 234, 2, 393, 232, 17, 393,
+ 163, -101, 10, -101, 908, 125, -101, 13, 908, -101,
+ -101, 1090, -101, -101, -101, 1181, -101, -101, 214, -101,
+ 1545, -101, 262, 9, -101, -101, 180, 318, 30, 1545,
+ -101, 238, -101, 236, -101, 26, -32, 315, 183, 288,
+ -101, 77, -101, -101, -101, 1728, 908, 291, 2589, 2007,
+ -3, -101, 443, 25, 497, 88, 1271, 2395, 24, 11,
+ 384, 36, 27, 702, 48, 49, -101, 1365, -101, 54,
+ 31, 45, 1271, 58, 15, 1271, 42, 1271, 23, 22,
+ 122, -101, -101, 21, -101, -101, 730, -101, 254, -70,
+ 908, -101, -101, 138, 393, -101, 143, -101, 134, -101,
+ -101, 268, -101, -101, 124, -101, -101, -101, -101, -101,
+ -101,
- -106, 6, -92, 10, 5, 278, -106, -106, -106, -106,
- -106, -106, -106, -106, -106, -106, -106, -106, -106, -42,
- -106, -106, -106, -106, -106, -106, -106, -106, -106, 109,
- -106, -106, -106, -10, -106, -106, -35, 24, 73, 90,
- -106, 219, 181, -106, -106, -106, 171, 120, -106, -106,
- -106, -106, -106, 174, -106, 170, 167, -106, 175, 163,
- -106, -106, -106, -106, 184, 177, 180, -106, -106, -106,
- -106, 125, -106, 132, 134, 162, 130, -106, 121, 124,
- 123, 141, 142, 152, -106, 154, 161, 160, -106, -106,
- -106, -106, -106, -106, -106, -106, -106, -106, -106, 139,
- -106, 143, -106, 156, 91, 55, -106, -106, -106, -106,
- -106, -106, -106, -106, -106, -106, -106, -106, -106, -106,
- -106, -106, -106, -106, -106, -106, -106, -106, -106, -106,
- -106, -106, -106, -106, -106, -106, -106, -106, -106, -106,
- -106, 32, -106, -106, -106, -106, -106, 33, -106, -106,
- 26, -106, -106, -106, -106, -106, -106, -106, -106, -106,
- -106, -106, -106, -106, 96, -106, 119, 52, -106, -106,
- 66, -106, 220, 69, 71, -106, -106, -106, -106, -106,
- -106, -106, -106, 25, -106, -106, -106, 64, -106, -106,
- -106, -106, -106, -106, -106, -106, -106, -106, -106, -106,
- -106, -106, -106, -106, -106, -106, 70, -106, -106, 61,
- -106, 41, -106, 39, -106, 37, -106, -106, 42, -106,
- 79, -106, -106, -106, 81, 72, -106, -106, -106, -106,
- -106, -5, -106, -106, -106, -106, -106, -106, -106, -106,
- -106, -106, -106, -106, -106, -106, -106, -106, -106, -106,
- -106, -106, 21, -106, -106, -106, -106, 112, -106, -106,
- -106, -106, -106, -106, -106, -106, -106, -106, -106, -106,
- -106, 17, 237, -106, 192, 236, 224, 225, -106, 97,
- 98, 101, 99, 113, -106, -106, -106, -106, -106, -106,
- -106, -106, 204, -106, 223, -106, 235, -106, -106, 239,
- -106, 197, -106, -106, 228, -106, 27, -106, 13, -106,
- 2, -106, 233, -106, 190, 198, -106, -106, 196, -106,
- -106, -106, -106, -106, -106, 200, -106, 107, 135, -106,
- -106, 186, -106, 84, -106, 80, -106, 76, -106, -106,
- 89, -106, -106, -49, -106, -106, 47, -106, 40, -106,
- 44, -106, 68, -106, -106, -106, -106, -106, -106, 53,
- -106, 35, -106, 49, -106, 87, 63, -106, -106, 30,
- -106, -106, 103, -106, -106, -106, 51, -106, -106, -106,
- -106, 86, -106, 67, 114, -106, 74, -106, -106, 65,
- -106, 56, -106, -106, -106, -106, -106, -106, -106, 62,
- -106, -106, -106, -106, -106, -106, 95, -106, -106, 78,
- -106, -106, -106, -106, 75, -106, 88, -106, -106, -106,
- -106, -106, -54, -106, 45, -106, -40, -106, -106, -106,
- -106, 94, -106, -106, 100, -106, -106, -106, -106, -106,
- 150, -41, -106, -106, 54, -106, 43, -106, 48, -106,
- -106, -106, -106, 59, -106, 57, -106, 60, -106, 58,
- -106, -106, -106, -106, -106, -106, 38, -106, -106, 144,
- -106, -106, -106, -106, 31, -106, -106, 202, -106, -106,
- 50, -106, -106, -106, -106, -106, -106, -106, -106, -106,
- -106, -106, -106, -106, -106, -106, 77, -106, -106, -106,
- -106, -106, 82, -106, -106, -106, -106, -106, -106, -106,
- -17, -106, -106, -106, -4, -106, -106, 12, -106, -106,
- -106, -106, -106, -106, -14, 46, -106, -13, -106, -106,
- -106, -106, 108, -106, -106, -106, 243, -106, -106, 295,
- -106, -106, -106, 290, -106, -106, -106, -106, 346, -106,
- -106, -106, 16, -106, -106, -106, 22, 23, -106, 34,
- -106, -106, -106, -106, -106, 11, -106, -106, -106, 7,
- 1, 8, -106, -106, -106, -106, -106, 307, 179, -106,
- -106, -106, -106, -106, 18, 281, 9, 15, -106, 4,
- -106, 83, 29, -106, -106, -2, -106, -106, 85, -106,
- -106, -106, 3, -106, -106, -106, -106, 14, -106, 0,
- 105, -106, 93, -106, -106, -106, -106, -106, -1, -106,
- -106, 20, -106, -106, 28, 92, -106, -106, -106, 19,
- -106, -106, -106, -106, -106, -106, -12, -106, -106, -106,
- -106, -106, -106, -106, -106, -106};
+ -107, 25, -75, 27, 30, 272, -107, -107, -107, -107,
+ -107, -107, -107, -107, -107, -107, -107, -107, -107, -42,
+ -107, -107, -107, -107, -107, -107, -107, -107, -107, 95,
+ -107, -107, -107, 31, -107, -107, 1, 37, 91, 80,
+ -107, 89, 167, -107, -107, -107, 175, 181, -107, -107,
+ -107, -107, -107, 137, -107, 130, 129, -107, 144, 152,
+ -107, -107, -107, -107, 140, 133, 149, -107, -107, -107,
+ -107, 157, -107, 182, 179, 170, 70, -107, 66, 78,
+ 55, 94, 100, 114, -107, 120, 109, 104, -107, -107,
+ -107, -107, -107, -107, -107, -107, -107, -107, -107, 172,
+ -107, 128, -107, 122, 58, 34, -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, 51, -107, -107, -107, -107, -107, 36, -107, -107,
+ 47, -107, -107, -107, -107, -107, -107, -107, -107, -107,
+ -107, -107, -107, -107, 154, -107, 158, -35, -107, -107,
+ 13, -107, 248, 42, 115, -107, -107, -107, -107, -107,
+ -107, -107, -107, 20, -107, -107, -107, 2, -107, -107,
+ -107, -107, -107, -107, -107, -107, -107, -107, -107, -107,
+ -107, -107, -107, -107, -107, -107, 61, -107, -107, 67,
+ -107, 64, -107, 76, -107, 43, -107, -107, 57, -107,
+ 60, -107, -107, -107, 85, 69, -107, -107, -107, -107,
+ -107, -5, -107, -107, -107, -107, -107, -107, -107, -107,
+ -107, -107, -107, -107, -107, -107, -107, -107, -107, -107,
+ -107, -107, 24, -107, -107, -107, -107, 148, -107, -107,
+ -107, -107, -107, -107, -107, -107, -107, -107, -107, -107,
+ -107, 9, 186, -107, 196, 221, 220, 212, -107, 102,
+ 98, 96, 116, 118, -107, -107, -107, -107, -107, -107,
+ -107, -107, 230, -107, 199, -107, 193, -107, -107, 211,
+ -107, 132, -107, -107, 126, -107, 14, -107, 5, -107,
+ 10, -107, 208, -107, 189, 202, -107, -107, 209, -107,
+ -107, -107, -107, -107, -107, 200, -107, 103, 121, -107,
+ -107, 168, -107, 50, -107, 54, -107, 62, -107, -107,
+ 88, -107, -107, -21, -107, -107, 184, -107, 63, -107,
+ 65, -107, 74, -107, -107, -107, -107, -107, -107, 92,
+ -107, 35, -107, 45, -107, 171, 75, -107, -107, 56,
+ -107, -107, 166, -107, -107, -107, 90, -107, -107, -107,
+ -107, 39, -107, 32, 159, -107, 178, -107, -107, -3,
+ -107, -17, -107, -107, -107, -107, -107, -107, -107, 3,
+ -107, -107, -107, -107, -107, -107, 68, -107, -107, 79,
+ -107, -107, -107, -107, 16, -107, 11, -107, -107, -107,
+ -107, -107, -8, -107, 59, -107, -41, -107, -107, -107,
+ -107, 99, -107, -107, 160, -107, -107, -107, -107, -107,
+ 93, -7, -107, -107, 77, -107, 40, -107, 46, -107,
+ -107, -107, -107, 53, -107, 83, -107, 72, -107, 71,
+ -107, -107, -107, -107, -107, -107, 48, -107, -107, 81,
+ -107, -107, -107, -107, 38, -107, -107, 173, -107, -107,
+ 33, -107, -107, -107, -107, -107, -107, -107, -107, -107,
+ -107, -107, -107, -107, -107, -107, 86, -107, -107, -107,
+ -107, -107, 73, -107, -107, -107, -107, -107, -107, -107,
+ 22, -107, -107, -107, -10, -107, -107, 259, -107, -107,
+ -107, -107, -107, -107, -107, -107, -6, -15, -107, -2,
+ -107, -107, -107, -107, 101, -107, -107, -107, 106, -107,
+ -107, 290, -107, -107, -107, 294, -107, -107, -107, -107,
+ 318, -107, -107, -4, -107, -107, -19, -13, -107, 364,
+ -107, -107, -107, -26, -107, -107, -107, -11, -20, -12,
+ -107, -107, -107, -107, -107, 305, 278, -107, 17, 261,
+ 4, -107, 28, -107, 26, -107, 87, 19, -107, -107,
+ 23, -107, -107, 84, -107, -107, -107, 44, -107, -107,
+ -107, -107, 41, -107, 29, 125, -107, 110, -107, -107,
+ -107, -107, -107, 15, -107, -107, 12, -107, -107, 18,
+ 97, -107, -107, -107, 7, -107, -107, -107, -107, -107,
+ -107, 21, -107, -107, -107, -107, -107, -107, -107, -107,
+ -107};
const short QDeclarativeJSGrammar::action_info [] = {
- 399, 352, 345, -101, 343, 457, 440, 403, 257, -112,
- -125, -131, -123, 346, -120, 348, -128, 389, 453, 391,
- 416, 401, 408, 563, -101, -123, 416, -120, 539, -131,
- 346, -112, -125, 348, 257, 99, 71, 645, 621, 101,
- -128, 440, 141, 621, 164, 431, 539, 430, 453, 573,
- 457, 444, 440, 424, 71, 424, 101, 446, 559, 420,
- 424, 448, 539, 440, 570, 539, 466, 527, 312, 346,
- 532, 312, 318, 272, 409, 183, 342, 525, 147, 141,
- 348, 510, 457, 414, 272, 325, 0, 0, 252, 99,
- 257, 440, 296, 556, -102, 292, 453, 190, 170, 416,
- 164, 434, 141, 141, 536, 251, 304, 172, 141, 141,
- 443, 0, 335, 340, 141, 427, 0, 0, 0, 149,
- 327, 306, 0, 292, 444, 0, 173, 0, 536, 141,
- 141, 0, 0, 179, 333, 141, 294, 236, 189, 314,
- 141, 301, 141, 315, 141, 477, 331, 242, 241, 413,
- 412, 62, 537, 166, 58, 488, 142, 167, 294, 58,
- 428, 254, 63, 256, 255, 59, 418, 172, 247, 246,
- 59, 575, 574, 328, 249, 248, 616, 177, 641, 640,
- 58, 469, 337, 141, 635, 634, 173, 350, 187, 249,
- 248, 59, 310, 478, 459, 58, 455, 64, 523, 249,
- 248, 85, 85, 86, 86, 103, 59, 565, 511, 172,
- 511, 638, 637, 64, 87, 87, 141, 511, 517, 577,
- 511, 0, 141, 0, 104, 141, 105, 85, 173, 86,
- 174, 172, 566, 564, 470, 468, 562, 561, 548, 511,
- 87, 636, 65, 530, 513, 539, 141, 85, 66, 86,
- 173, 0, 406, 0, 513, 512, 513, 64, 65, 0,
- 87, 172, 0, 513, 66, 512, 513, 512, 172, 235,
- 234, 0, 518, 516, 512, 521, 520, 512, 554, 553,
- 173, 85, 406, 86, 0, 513, -89, 173, 34, 174,
- 73, 74, 549, 547, 87, 631, 512, 531, 529, 438,
- 437, 172, 65, 0, 578, 274, 275, 0, 66, 632,
- 630, 34, 0, 73, 74, 274, 275, 75, 76, -89,
- 173, 0, 174, 34, 0, 48, 50, 49, 0, 0,
- 0, 0, 276, 277, 34, 0, 0, 0, 34, 629,
- 75, 76, 276, 277, 279, 280, 34, 0, 48, 50,
- 49, 45, 34, 281, 279, 280, 282, 85, 283, 86,
- 48, 50, 49, 281, 0, 34, 282, 0, 283, 34,
- 87, 48, 50, 49, 45, 48, 50, 49, 0, 0,
- 34, 0, 0, 48, 50, 49, 45, 34, 0, 48,
- 50, 49, 34, 0, 0, 0, 0, 45, 34, 0,
- 0, 45, 48, 50, 49, 0, 48, 50, 49, 45,
- 0, 0, 0, 0, 34, 45, 0, 48, 50, 49,
- 34, 0, 0, 0, 48, 50, 49, 34, 45, 48,
- 50, 49, 45, 279, 280, 48, 50, 49, 0, 0,
- 0, 34, 281, 45, 0, 282, 0, 283, -343, 34,
- 45, 48, 50, 49, 0, 45, -343, 48, 50, 49,
- 0, 45, 78, 79, 48, 50, 49, 0, 0, 0,
- 80, 81, 0, 0, 82, 0, 83, 45, 48, 50,
- 49, 0, 0, 45, 78, 79, 48, 50, 49, 34,
- 45, 0, 80, 81, 78, 79, 82, 34, 83, 0,
- 0, 0, 80, 81, 45, 34, 82, 0, 83, 0,
- 0, 34, 45, 0, 6, 5, 4, 1, 3, 2,
- 0, 240, 239, 0, 34, 0, 48, 50, 49, 245,
- 244, 0, 0, 34, 48, 50, 49, 245, 244, 0,
- 0, 0, 48, 50, 49, 0, 0, 0, 48, 50,
- 49, 0, 45, 0, 0, 0, 245, 244, 0, 0,
- 45, 48, 50, 49, 0, 240, 239, 34, 45, 0,
- 48, 50, 49, 0, 45, 0, 0, 0, 0, 0,
- 0, 0, 0, 78, 79, 0, 0, 45, 151, 0,
- 0, 80, 81, 0, 0, 82, 45, 83, 152, 240,
- 239, 0, 153, 0, 48, 50, 49, 0, 0, 0,
- 0, 154, 0, 155, 0, 0, 308, 0, 0, 0,
- 0, 0, 0, 0, 156, 0, 157, 62, 0, 0,
- 45, 0, 0, 0, 158, 0, 0, 159, 63, 0,
- 0, 0, 0, 160, 0, 0, 0, 0, 0, 161,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 30,
- 31, 151, 0, 0, 0, 162, 0, 0, 0, 33,
- 0, 152, 0, 0, 0, 153, 34, 0, 0, 0,
- 35, 36, 0, 37, 154, 0, 155, 0, 0, 0,
- 502, 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, 30, 31, 0, 40, 0, 0, 0, 162, 45,
- 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,
- 502, 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,
- 30, 31, 0, 0, 0, 0, 0, 0, 30, 31,
- 33, 0, 0, 0, 0, 0, 0, 34, 33, 0,
- 0, 35, 36, 0, 37, 34, 0, 0, 0, 35,
- 36, 502, 37, 0, 0, 44, 0, 0, 0, 41,
- 0, 0, 0, 44, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 51, 48, 50, 49, 0, 52, 0,
- 0, 51, 48, 50, 49, 0, 52, 0, 0, 43,
- 54, 32, 0, 0, 0, 40, 0, 43, 54, 32,
- 45, 0, 0, 40, 0, 0, 0, 0, 45, 30,
- 31, 0, 0, 0, 0, 0, 0, 30, 31, 33,
- 0, 0, 0, 0, 0, 0, 34, 33, 0, 0,
- 35, 36, 0, 37, 34, 0, 0, 0, 35, 36,
- 41, 37, 0, 0, 44, 0, 0, 0, 502, 0,
- 0, 0, 44, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 51, 48, 50, 49, 0, 52, 0, 0,
- 51, 48, 50, 49, 0, 52, 0, 0, 43, 54,
- 32, 0, 0, 0, 40, 0, 43, 54, 32, 45,
- 0, 0, 40, 0, 0, 0, 0, 45, 0, 0,
- 0, 0, 0, 0, 0, 0, 501, 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, 502,
- 0, 0, 0, 44, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 51, 503, 505, 504, 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, 501, 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,
- 502, 0, 0, 0, 44, 0, 0, 0, 0, 0,
- 0, 0, 544, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 51, 503, 505, 504, 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, 501, 0,
+ 457, 340, 343, 440, 342, -126, -110, 453, 391, 257,
+ -121, 352, 403, 389, -129, 346, 345, 416, 348, -99,
+ 616, -118, 401, -100, 446, 399, 448, 440, 571, 440,
+ 541, -110, -129, 561, 568, 333, 466, 559, 556, 527,
+ 510, 529, 541, 346, 534, 424, 541, 257, 440, -126,
+ 408, 424, -121, 420, 541, -118, -100, 444, 457, 453,
+ 424, -99, 304, 348, 431, -123, 251, 416, 325, 141,
+ 457, 101, 414, 164, 440, 453, 147, 71, 296, 416,
+ 99, 312, 272, 430, 294, 272, 252, 164, 141, 306,
+ 170, 335, 292, 640, 301, 257, 190, 187, 149, 346,
+ 183, 312, 236, 348, 318, 71, 141, 0, 0, 172,
+ 427, 141, 0, 179, 294, 141, 141, 331, 141, 314,
+ 99, 292, 189, 315, 141, 434, 141, 477, 173, 62,
+ 538, 141, 443, 538, 0, 249, 248, 141, 573, 572,
+ 63, 141, 616, 256, 255, 101, 444, 242, 241, 249,
+ 248, 247, 246, 172, 58, 428, 413, 412, 455, 409,
+ 58, 327, 141, 254, 177, 59, 142, 418, 58, 141,
+ 532, 59, 173, 249, 248, 478, 459, 58, 611, 59,
+ 166, 539, 172, 488, 167, 636, 635, 525, 59, 337,
+ 64, 64, 103, 310, 469, 630, 629, 85, 0, 86,
+ 64, 173, 0, 174, 633, 632, 85, 0, 86, 511,
+ 87, 104, 511, 105, 328, 235, 234, 575, 85, 87,
+ 86, 550, 438, 437, 533, 531, 85, 85, 86, 86,
+ 0, 87, 511, 513, 631, 65, 65, 517, 172, 87,
+ 87, 66, 66, 541, 512, 65, 0, 470, 468, 172,
+ 85, 66, 86, 141, 85, 513, 86, 173, 513, 406,
+ 85, 511, 86, 87, 0, 511, 512, 87, 173, 512,
+ 406, 0, 0, 87, 563, 551, 549, 172, 513, 0,
+ 0, 73, 74, 0, 0, 274, 275, 0, 0, 512,
+ 0, 518, 516, 274, 275, -87, 173, 34, 174, 564,
+ 562, 626, 576, 73, 74, 350, 172, 513, 75, 76,
+ 0, 513, 276, 277, 0, 627, 625, 34, 512, 0,
+ 276, 277, 512, 0, -87, 173, 34, 174, 279, 280,
+ 75, 76, 34, 0, 48, 50, 49, 281, 34, 0,
+ 282, 0, 283, 0, 34, 624, 85, 34, 86, 0,
+ 0, 0, 0, 0, 48, 50, 49, 0, 0, 87,
+ 45, 0, 0, 48, 50, 49, 0, 0, 0, 48,
+ 50, 49, 0, 0, 0, 48, 50, 49, 279, 280,
+ 45, 48, 50, 49, 48, 50, 49, 281, 0, 45,
+ 282, 0, 283, 0, 0, 45, 0, 279, 280, 0,
+ 0, 45, 0, 279, 280, 0, 281, 45, 0, 282,
+ 45, 283, 281, 34, 0, 282, 0, 283, 78, 79,
+ -341, 0, 34, 0, 0, 0, 80, 81, 78, 79,
+ 82, 0, 83, 0, 0, 0, 80, 81, 0, 0,
+ 82, 0, 83, 6, 5, 4, 1, 3, 2, 0,
+ 48, 50, 49, 0, 78, 79, 0, 0, 0, 48,
+ 50, 49, 80, 81, 0, 0, 82, 0, 83, 78,
+ 79, 0, 34, 0, 0, 0, 45, 80, 81, 78,
+ 79, 82, 34, 83, 0, 45, 0, 80, 81, -341,
+ 34, 82, 0, 83, 279, 280, 0, 0, 0, 34,
+ 0, 0, 0, 281, 240, 239, 282, 0, 283, 48,
+ 50, 49, 0, 0, 0, 0, 0, 34, 0, 48,
+ 50, 49, 240, 239, 0, 0, 34, 48, 50, 49,
+ 0, 245, 244, 0, 0, 45, 48, 50, 49, 0,
+ 0, 0, 0, 0, 0, 45, 0, 0, 0, 245,
+ 244, 0, 0, 45, 48, 50, 49, 0, 245, 244,
+ 0, 0, 45, 48, 50, 49, 0, 0, 0, 0,
+ 0, 0, 34, 0, 0, 0, 0, 0, 151, 0,
+ 45, 0, 0, 0, 0, 0, 0, 0, 152, 45,
+ 0, 0, 153, 0, 0, 0, 0, 0, 0, 0,
+ 0, 154, 0, 155, 240, 239, 308, 0, 0, 48,
+ 50, 49, 0, 0, 156, 0, 157, 62, 0, 0,
+ 0, 0, 0, 0, 158, 0, 0, 159, 63, 0,
+ 0, 0, 0, 160, 0, 45, 0, 0, 0, 161,
+ 0, 0, 30, 31, 151, 0, 0, 0, 0, 0,
+ 0, 0, 33, 0, 152, 162, 0, 0, 153, 34,
+ 0, 0, 0, 35, 36, 0, 37, 154, 0, 155,
+ 0, 0, 0, 41, 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, 30, 31, 0, 40, 0, 0,
+ 0, 162, 45, 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, 502, 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, 30, 31, 0, 0, 0, 0, 0,
+ 0, 30, 31, 33, 0, 0, 0, 0, 0, 0,
+ 34, 33, 0, 0, 35, 36, 0, 37, 34, 0,
+ 0, 0, 35, 36, 41, 37, 0, 0, 44, 0,
+ 0, 0, 502, 0, 0, 0, 44, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 51, 48, 50, 49,
+ 0, 52, 0, 0, 51, 48, 50, 49, 0, 52,
+ 0, 0, 43, 54, 32, 0, 0, 0, 40, 0,
+ 43, 54, 32, 45, 0, 0, 40, 0, 0, 0,
+ 0, 45, 0, 0, 0, 0, 0, 0, 0, 0,
30, 31, 0, 0, 0, 0, 0, 0, 0, 0,
- 215, 0, 0, 0, 0, 0, 0, 34, 0, 0,
+ 33, 0, 0, 0, 0, 0, 0, 34, 0, 0,
0, 35, 36, 0, 37, 0, 0, 0, 0, 0,
0, 502, 0, 0, 0, 44, 0, 0, 0, 0,
- 0, 0, 0, 541, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 51, 503, 505, 504, 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, 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, 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,
+ 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, -121,
- 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, 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, 483, 0, 0, 29, 30, 31, 0,
+ 45, 0, 0, 0, 0, 0, 0, 0, 0, 501,
+ 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, 502, 0, 0, 0, 44, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 51, 503, 505, 504, 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,
+ 501, 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, 502, 0, 0, 0, 44, 0, 0,
+ 0, 0, 0, 0, 0, 543, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 51, 503, 505, 504, 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, 501, 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, 502, 0, 0, 0, 44, 0,
+ 0, 0, 0, 0, 0, 0, 546, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 51, 503, 505, 504,
+ 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, 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, -119, 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, 486, 0, 0, 0, 0, 0, 0, 0, 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, 475, 0, 0, 29,
+ 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, 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, 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, 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, 481, 0, 0, 0, 0, 0,
+ 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, 29,
+ 30, 31, 0, 0, 0, 0, 0, 0, 0, 0,
+ 33, 0, 0, 0, 0, 0, 0, 34, 217, 0,
+ 0, 578, 579, 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, 0, 52, 0,
53, 0, 55, 0, 56, 0, 0, 0, 0, 43,
54, 32, 0, 0, 0, 40, 0, 0, 0, 0,
@@ -525,7 +532,7 @@ const short QDeclarativeJSGrammar::action_info [] = {
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, 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,
@@ -539,44 +546,54 @@ const short QDeclarativeJSGrammar::action_info [] = {
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, 29, 30, 31, 0, 0,
- 0, 0, 0, 0, 0, 0, 33, 0, 0, 0,
- 0, 0, 0, 34, 217, 0, 0, 584, 585, 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, 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, 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, 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, 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,
+ 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, 0, 48, 50, 49,
+ 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, 45, 0, 0, 0, 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, 0, 0, 0, 0, 129, 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, 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, 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, 209, 0, 0, 0,
0, 211, 0, 29, 30, 31, 213, 0, 0, 0,
0, 0, 0, 214, 215, 0, 0, 0, 0, 0,
@@ -587,248 +604,238 @@ const short QDeclarativeJSGrammar::action_info [] = {
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, 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, 0, 0, 582, 110, 111, 0, 0, 584, 115,
+ 586, 30, 31, 587, 0, 118, 0, 0, 0, 120,
+ 589, 590, 0, 0, 0, 0, 0, 0, 591, 592,
+ 124, 125, 218, 36, 0, 37, 0, 0, 0, 38,
+ 0, 39, 593, 42, 0, 0, 595, 0, 0, 0,
+ 46, 0, 47, 0, 0, 0, 0, 0, 597, 0,
+ 221, 0, 0, 0, 599, 596, 598, 49, 600, 601,
+ 602, 53, 604, 605, 606, 607, 608, 609, 0, 0,
+ 594, 603, 588, 583, 585, 128, 40, 0, 0, 0,
0, 45, 0, 0, 0, 0, 0, 0, 0, 0,
- 587, 110, 111, 0, 0, 589, 115, 591, 30, 31,
- 592, 0, 118, 0, 0, 0, 120, 594, 595, 0,
- 0, 0, 0, 0, 0, 596, 597, 124, 125, 218,
- 36, 0, 37, 0, 0, 0, 38, 0, 39, 598,
- 42, 0, 0, 600, 0, 0, 0, 46, 0, 47,
- 0, 0, 0, 0, 0, 602, 0, 221, 0, 0,
- 0, 604, 601, 603, 49, 605, 606, 607, 53, 609,
- 610, 611, 612, 613, 614, 0, 0, 599, 608, 593,
- 588, 590, 128, 40, 0, 0, 0, 0, 45, 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, -267, 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,
+ 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, -265, 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,
- 472, 546, 528, 639, 311, 182, 302, 498, 514, 16,
- 461, 515, 496, 182, 497, 519, 309, 436, 619, 243,
- 358, 439, 576, 572, 253, 150, 571, 487, 617, 307,
- 238, 250, 320, 628, 633, 555, 569, 560, 558, 642,
- 186, 250, 425, 349, 358, 182, 351, 557, 433, 347,
- 238, 344, 339, 429, 302, 402, 243, 445, 447, 456,
- 460, 163, 454, 458, 243, 250, 485, 143, 148, 449,
- 353, 526, 176, 467, 237, 450, 238, 415, 338, 188,
- 410, 237, 302, 336, 436, 482, 334, 169, 439, 436,
- 146, 417, 392, 439, 140, 522, 358, 400, 404, 0,
- 390, 171, 358, 0, 186, 500, 146, 0, 643, 0,
- 0, 178, 0, 0, 0, 0, 404, 60, 60, 489,
- 452, 500, 320, 0, 534, 0, 405, 60, 0, 180,
- 146, 60, 0, 180, 60, 407, 490, 60, 302, 452,
- 60, 60, 60, 60, 405, 60, 284, 285, 287, 60,
- 286, 451, 358, 60, 165, 180, 266, 60, 60, 461,
- 451, 270, 288, 60, 60, 60, 493, 60, 60, 60,
- 84, 106, 92, 91, 60, 432, 60, 72, 60, 168,
- 98, 435, 77, 60, 96, 60, 60, 60, 341, 302,
- 93, 94, 500, 108, 329, 100, 60, 102, 60, 618,
- 302, 95, 88, 330, 60, 60, 60, 60, 90, 89,
- 70, 60, 97, 452, 60, 60, 451, 492, 60, 60,
- 494, 60, 61, 68, 60, 60, 69, 491, 60, 471,
- 67, 302, 404, 480, 60, 106, 60, 479, 0, 270,
- 298, 270, 298, 278, 298, 270, 0, 270, 60, 270,
- 0, 316, 0, 270, 332, 0, 500, 108, 175, 538,
- 405, 293, 319, 0, 317, 303, 326, 60, 60, 60,
- 0, 0, 270, 270, 270, 290, 291, 60, 295, 298,
- 60, 60, 270, 298, 270, 270, 270, 289, 270, 0,
- 273, 500, 313, 0, 551, 545, 305, 534, 508, 615,
- 542, 297, 0, 500, 0, 300, 499, 509, 500, 0,
- 508, 0, 0, 0, 0, 508, 472, 0, 499, 509,
- 583, 0, 0, 499, 509, 0, 0, 586, 579, 580,
- 581, 582, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 550,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 551,
- 0, 0, 0, 0, 0, 0, 552, 0, 0, 0,
+ 567, 169, 558, 570, 574, 515, 569, 557, 309, 548,
+ 461, 528, 311, 530, 417, 555, 307, 188, 415, 358,
+ 392, 250, 628, 612, 320, 623, 150, 253, 16, 637,
+ 496, 497, 498, 390, 614, 186, 634, 472, 182, 400,
+ 487, 243, 436, 238, 436, 176, 182, 302, 514, 171,
+ 238, 439, 334, 429, 439, 447, 454, 336, 339, 358,
+ 243, 140, 433, 302, 338, 237, 349, 351, 449, 482,
+ 146, 182, 148, 460, 485, 458, 353, 250, 250, 243,
+ 344, 410, 238, 163, 467, 456, 524, 143, 436, 425,
+ 237, 439, 445, 302, 402, 358, 461, 404, 0, 450,
+ 60, 358, 404, 186, 146, 92, 0, 0, 0, 407,
+ 500, 60, 0, 638, 500, 60, 84, 536, 320, 500,
+ 0, 98, 540, 60, 302, 60, 405, 490, 91, 302,
+ 0, 405, 60, 0, 180, 302, 60, 106, 489, 60,
+ 60, 60, 180, 60, 93, 60, 286, 60, 285, 60,
+ 94, 146, 284, 90, 60, 60, 178, 452, 89, 60,
+ 108, 60, 358, 60, 95, 60, 287, 471, 288, 88,
+ 60, 302, 451, 60, 60, 60, 452, 451, 60, 404,
+ 68, 432, 60, 102, 494, 60, 347, 67, 341, 60,
+ 330, 329, 61, 266, 60, 305, 69, 60, 270, 60,
+ 70, 303, 60, 60, 60, 480, 451, 0, 405, 479,
+ 72, 0, 60, 165, 491, 60, 60, 60, 180, 168,
+ 60, 97, 492, 60, 60, 452, 60, 60, 493, 100,
+ 96, 60, 0, 77, 60, 0, 270, 332, 298, 270,
+ 273, 60, 435, 270, 60, 298, 270, 298, 278, 270,
+ 270, 316, 270, 60, 298, 295, 298, 60, 270, 270,
+ 297, 270, 270, 106, 291, 60, 60, 326, 313, 317,
+ 270, 270, 290, 289, 552, 60, 319, 536, 300, 610,
+ 270, 519, 520, 521, 522, 500, 108, 175, 293, 0,
+ 0, 500, 508, 0, 0, 544, 0, 472, 613, 547,
+ 0, 499, 509, 500, 0, 0, 0, 500, 0, 0,
+ 508, 0, 0, 0, 508, 0, 0, 0, 577, 499,
+ 509, 0, 0, 499, 509, 580, 581, 519, 520, 521,
+ 522, 552, 0, 0, 0, 0, 0, 0, 553, 554,
+ 519, 520, 521, 522, 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, 560, 519, 520, 521, 522,
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, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0};
const short QDeclarativeJSGrammar::action_check [] = {
- 7, 16, 55, 7, 33, 36, 33, 55, 36, 7,
- 7, 7, 7, 7, 7, 36, 7, 7, 36, 8,
- 36, 55, 60, 29, 7, 7, 36, 7, 33, 7,
- 7, 7, 7, 36, 36, 48, 1, 0, 90, 79,
- 7, 33, 8, 90, 2, 7, 33, 55, 36, 60,
- 36, 20, 33, 5, 1, 5, 79, 36, 7, 33,
- 5, 60, 33, 33, 8, 33, 17, 24, 2, 7,
- 34, 2, 7, 1, 7, 36, 60, 37, 8, 8,
- 36, 66, 36, 7, 1, 17, -1, -1, 36, 48,
- 36, 33, 8, 66, 7, 48, 36, 33, 7, 36,
- 2, 7, 8, 8, 8, 77, 61, 15, 8, 8,
- 6, -1, 31, 36, 8, 10, -1, -1, -1, 60,
- 8, 60, -1, 48, 20, -1, 34, -1, 8, 8,
- 8, -1, -1, 60, 60, 8, 79, 55, 60, 50,
- 8, 61, 8, 54, 8, 8, 61, 61, 62, 61,
- 62, 42, 56, 50, 40, 60, 56, 54, 79, 40,
- 55, 60, 53, 61, 62, 51, 60, 15, 61, 62,
- 51, 61, 62, 61, 61, 62, 56, 56, 61, 62,
- 40, 8, 60, 8, 61, 62, 34, 60, 8, 61,
- 62, 51, 60, 56, 60, 40, 60, 12, 29, 61,
- 62, 25, 25, 27, 27, 15, 51, 36, 29, 15,
- 29, 61, 62, 12, 38, 38, 8, 29, 7, 7,
- 29, -1, 8, -1, 34, 8, 36, 25, 34, 27,
- 36, 15, 61, 62, 61, 62, 61, 62, 7, 29,
- 38, 91, 57, 7, 75, 33, 8, 25, 63, 27,
- 34, -1, 36, -1, 75, 86, 75, 12, 57, -1,
- 38, 15, -1, 75, 63, 86, 75, 86, 15, 61,
- 62, -1, 61, 62, 86, 61, 62, 86, 61, 62,
- 34, 25, 36, 27, -1, 75, 33, 34, 29, 36,
- 18, 19, 61, 62, 38, 47, 86, 61, 62, 61,
- 62, 15, 57, -1, 92, 18, 19, -1, 63, 61,
- 62, 29, -1, 18, 19, 18, 19, 45, 46, 33,
- 34, -1, 36, 29, -1, 66, 67, 68, -1, -1,
- -1, -1, 45, 46, 29, -1, -1, -1, 29, 91,
- 45, 46, 45, 46, 23, 24, 29, -1, 66, 67,
- 68, 92, 29, 32, 23, 24, 35, 25, 37, 27,
- 66, 67, 68, 32, -1, 29, 35, -1, 37, 29,
- 38, 66, 67, 68, 92, 66, 67, 68, -1, -1,
- 29, -1, -1, 66, 67, 68, 92, 29, -1, 66,
- 67, 68, 29, -1, -1, -1, -1, 92, 29, -1,
- -1, 92, 66, 67, 68, -1, 66, 67, 68, 92,
- -1, -1, -1, -1, 29, 92, -1, 66, 67, 68,
- 29, -1, -1, -1, 66, 67, 68, 29, 92, 66,
- 67, 68, 92, 23, 24, 66, 67, 68, -1, -1,
- -1, 29, 32, 92, -1, 35, -1, 37, 36, 29,
- 92, 66, 67, 68, -1, 92, 36, 66, 67, 68,
- -1, 92, 23, 24, 66, 67, 68, -1, -1, -1,
- 31, 32, -1, -1, 35, -1, 37, 92, 66, 67,
- 68, -1, -1, 92, 23, 24, 66, 67, 68, 29,
- 92, -1, 31, 32, 23, 24, 35, 29, 37, -1,
- -1, -1, 31, 32, 92, 29, 35, -1, 37, -1,
- -1, 29, 92, -1, 93, 94, 95, 96, 97, 98,
- -1, 61, 62, -1, 29, -1, 66, 67, 68, 61,
- 62, -1, -1, 29, 66, 67, 68, 61, 62, -1,
- -1, -1, 66, 67, 68, -1, -1, -1, 66, 67,
- 68, -1, 92, -1, -1, -1, 61, 62, -1, -1,
- 92, 66, 67, 68, -1, 61, 62, 29, 92, -1,
- 66, 67, 68, -1, 92, -1, -1, -1, -1, -1,
- -1, -1, -1, 23, 24, -1, -1, 92, 3, -1,
- -1, 31, 32, -1, -1, 35, 92, 37, 13, 61,
- 62, -1, 17, -1, 66, 67, 68, -1, -1, -1,
- -1, 26, -1, 28, -1, -1, 31, -1, -1, -1,
- -1, -1, -1, -1, 39, -1, 41, 42, -1, -1,
- 92, -1, -1, -1, 49, -1, -1, 52, 53, -1,
- -1, -1, -1, 58, -1, -1, -1, -1, -1, 64,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, 12,
- 13, 3, -1, -1, -1, 80, -1, -1, -1, 22,
- -1, 13, -1, -1, -1, 17, 29, -1, -1, -1,
- 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, 12, 13, -1, 87, -1, -1, -1, 80, 92,
- -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, -1, -1, -1, -1, -1, -1, -1, 81, 82,
- 83, -1, -1, -1, 87, -1, -1, -1, -1, 92,
- 12, 13, -1, -1, -1, -1, -1, -1, 12, 13,
- 22, -1, -1, -1, -1, -1, -1, 29, 22, -1,
- -1, 33, 34, -1, 36, 29, -1, -1, -1, 33,
- 34, 43, 36, -1, -1, 47, -1, -1, -1, 43,
- -1, -1, -1, 47, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, 65, 66, 67, 68, -1, 70, -1,
- -1, 65, 66, 67, 68, -1, 70, -1, -1, 81,
- 82, 83, -1, -1, -1, 87, -1, 81, 82, 83,
- 92, -1, -1, 87, -1, -1, -1, -1, 92, 12,
- 13, -1, -1, -1, -1, -1, -1, 12, 13, 22,
- -1, -1, -1, -1, -1, -1, 29, 22, -1, -1,
- 33, 34, -1, 36, 29, -1, -1, -1, 33, 34,
- 43, 36, -1, -1, 47, -1, -1, -1, 43, -1,
- -1, -1, 47, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, 65, 66, 67, 68, -1, 70, -1, -1,
- 65, 66, 67, 68, -1, 70, -1, -1, 81, 82,
- 83, -1, -1, -1, 87, -1, 81, 82, 83, 92,
- -1, -1, 87, -1, -1, -1, -1, 92, -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, 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, 10, -1,
+ 36, 36, 33, 33, 60, 7, 7, 36, 8, 36,
+ 7, 16, 55, 7, 7, 7, 55, 36, 36, 7,
+ 90, 7, 55, 7, 36, 7, 60, 33, 60, 33,
+ 33, 7, 7, 29, 8, 60, 17, 7, 66, 37,
+ 66, 24, 33, 7, 34, 5, 33, 36, 33, 7,
+ 60, 5, 7, 33, 33, 7, 7, 20, 36, 36,
+ 5, 7, 61, 36, 7, 7, 77, 36, 17, 8,
+ 36, 79, 7, 2, 33, 36, 8, 1, 8, 36,
+ 48, 2, 1, 55, 79, 1, 36, 2, 8, 60,
+ 7, 31, 48, 0, 61, 36, 33, 8, 60, 7,
+ 36, 2, 55, 36, 7, 1, 8, -1, -1, 15,
+ 10, 8, -1, 60, 79, 8, 8, 61, 8, 50,
+ 48, 48, 60, 54, 8, 7, 8, 8, 34, 42,
+ 8, 8, 6, 8, -1, 61, 62, 8, 61, 62,
+ 53, 8, 90, 61, 62, 79, 20, 61, 62, 61,
+ 62, 61, 62, 15, 40, 55, 61, 62, 60, 7,
+ 40, 8, 8, 60, 56, 51, 56, 60, 40, 8,
+ 7, 51, 34, 61, 62, 56, 60, 40, 56, 51,
+ 50, 56, 15, 60, 54, 61, 62, 29, 51, 60,
+ 12, 12, 15, 60, 8, 61, 62, 25, -1, 27,
+ 12, 34, -1, 36, 61, 62, 25, -1, 27, 29,
+ 38, 34, 29, 36, 61, 61, 62, 7, 25, 38,
+ 27, 7, 61, 62, 61, 62, 25, 25, 27, 27,
+ -1, 38, 29, 75, 91, 57, 57, 7, 15, 38,
+ 38, 63, 63, 33, 86, 57, -1, 61, 62, 15,
+ 25, 63, 27, 8, 25, 75, 27, 34, 75, 36,
+ 25, 29, 27, 38, -1, 29, 86, 38, 34, 86,
+ 36, -1, -1, 38, 36, 61, 62, 15, 75, -1,
+ -1, 18, 19, -1, -1, 18, 19, -1, -1, 86,
+ -1, 61, 62, 18, 19, 33, 34, 29, 36, 61,
+ 62, 47, 92, 18, 19, 60, 15, 75, 45, 46,
+ -1, 75, 45, 46, -1, 61, 62, 29, 86, -1,
+ 45, 46, 86, -1, 33, 34, 29, 36, 23, 24,
+ 45, 46, 29, -1, 66, 67, 68, 32, 29, -1,
+ 35, -1, 37, -1, 29, 91, 25, 29, 27, -1,
+ -1, -1, -1, -1, 66, 67, 68, -1, -1, 38,
+ 92, -1, -1, 66, 67, 68, -1, -1, -1, 66,
+ 67, 68, -1, -1, -1, 66, 67, 68, 23, 24,
+ 92, 66, 67, 68, 66, 67, 68, 32, -1, 92,
+ 35, -1, 37, -1, -1, 92, -1, 23, 24, -1,
+ -1, 92, -1, 23, 24, -1, 32, 92, -1, 35,
+ 92, 37, 32, 29, -1, 35, -1, 37, 23, 24,
+ 36, -1, 29, -1, -1, -1, 31, 32, 23, 24,
+ 35, -1, 37, -1, -1, -1, 31, 32, -1, -1,
+ 35, -1, 37, 93, 94, 95, 96, 97, 98, -1,
+ 66, 67, 68, -1, 23, 24, -1, -1, -1, 66,
+ 67, 68, 31, 32, -1, -1, 35, -1, 37, 23,
+ 24, -1, 29, -1, -1, -1, 92, 31, 32, 23,
+ 24, 35, 29, 37, -1, 92, -1, 31, 32, 36,
+ 29, 35, -1, 37, 23, 24, -1, -1, -1, 29,
+ -1, -1, -1, 32, 61, 62, 35, -1, 37, 66,
+ 67, 68, -1, -1, -1, -1, -1, 29, -1, 66,
+ 67, 68, 61, 62, -1, -1, 29, 66, 67, 68,
+ -1, 61, 62, -1, -1, 92, 66, 67, 68, -1,
+ -1, -1, -1, -1, -1, 92, -1, -1, -1, 61,
+ 62, -1, -1, 92, 66, 67, 68, -1, 61, 62,
+ -1, -1, 92, 66, 67, 68, -1, -1, -1, -1,
+ -1, -1, 29, -1, -1, -1, -1, -1, 3, -1,
+ 92, -1, -1, -1, -1, -1, -1, -1, 13, 92,
+ -1, -1, 17, -1, -1, -1, -1, -1, -1, -1,
+ -1, 26, -1, 28, 61, 62, 31, -1, -1, 66,
+ 67, 68, -1, -1, 39, -1, 41, 42, -1, -1,
+ -1, -1, -1, -1, 49, -1, -1, 52, 53, -1,
+ -1, -1, -1, 58, -1, 92, -1, -1, -1, 64,
+ -1, -1, 12, 13, 3, -1, -1, -1, -1, -1,
+ -1, -1, 22, -1, 13, 80, -1, -1, 17, 29,
+ -1, -1, -1, 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, 12, 13, -1, 87, -1, -1,
+ -1, 80, 92, -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, -1, -1, -1, -1, -1, -1,
+ -1, 81, 82, 83, -1, -1, -1, 87, -1, -1,
+ -1, -1, 92, 12, 13, -1, -1, -1, -1, -1,
+ -1, 12, 13, 22, -1, -1, -1, -1, -1, -1,
+ 29, 22, -1, -1, 33, 34, -1, 36, 29, -1,
+ -1, -1, 33, 34, 43, 36, -1, -1, 47, -1,
+ -1, -1, 43, -1, -1, -1, 47, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 65, 66, 67, 68,
+ -1, 70, -1, -1, 65, 66, 67, 68, -1, 70,
+ -1, -1, 81, 82, 83, -1, -1, -1, 87, -1,
+ 81, 82, 83, 92, -1, -1, 87, -1, -1, -1,
+ -1, 92, -1, -1, -1, -1, -1, -1, -1, -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, 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, -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,
+ -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, 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, 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, 8, -1, -1, 11, 12, 13, -1,
+ 92, -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,
+ 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, 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, 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, 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, 56, -1, -1, -1, -1, -1, -1, -1, -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, 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, 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, -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,
@@ -841,6 +848,15 @@ const short QDeclarativeJSGrammar::action_check [] = {
-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, 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, -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, 8,
-1, -1, 11, 12, 13, -1, -1, -1, -1, -1,
-1, -1, -1, 22, -1, -1, -1, -1, -1, -1,
@@ -860,44 +876,54 @@ const short QDeclarativeJSGrammar::action_check [] = {
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, 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, -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, 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, 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, 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, 43, -1, -1, -1, 47, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- 59, -1, -1, -1, -1, -1, -1, 66, 67, 68,
+ 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, 92, -1, -1, -1, -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, -1, -1, -1, -1, 59, -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, 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,
+ -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, 86, -1, -1, -1, -1, -1, -1, -1, -1,
+ 85, -1, 87, -1, -1, -1, -1, 92, -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,
@@ -908,74 +934,66 @@ const short QDeclarativeJSGrammar::action_check [] = {
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, 4, -1, -1, -1, -1, 9, -1,
- 11, 12, 13, 14, -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,
- -1, -1, 33, 34, -1, 36, -1, -1, -1, 40,
+ 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, -1, 87, -1, -1, -1,
+ 81, 82, 83, 84, 85, 86, 87, -1, -1, -1,
-1, 92, -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, 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, 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, -1, -1, -1, -1, -1, -1,
- 35, 15, 15, 15, 2, 15, 3, 2, 25, 3,
- 15, 15, 104, 15, 4, 3, 3, 3, 19, 15,
- 2, 21, 15, 15, 3, 67, 25, 3, 19, 2,
- 15, 2, 15, 13, 15, 19, 25, 3, 15, 11,
- 15, 2, 96, 3, 2, 15, 2, 25, 3, 2,
- 15, 100, 15, 93, 3, 2, 15, 98, 15, 2,
- 2, 35, 3, 3, 15, 2, 35, 35, 35, 21,
- 2, 25, 3, 35, 4, 21, 15, 2, 2, 15,
- 2, 4, 3, 3, 3, 35, 2, 35, 21, 3,
- 35, 3, 36, 21, 3, 13, 2, 35, 13, -1,
- 35, 35, 2, -1, 15, 13, 35, -1, 16, -1,
- -1, 40, -1, -1, -1, -1, 13, 44, 44, 46,
- 46, 13, 15, -1, 16, -1, 41, 44, -1, 46,
- 35, 44, -1, 46, 44, 40, 46, 44, 3, 46,
- 44, 44, 44, 44, 41, 44, 49, 49, 49, 44,
- 49, 46, 2, 44, 58, 46, 44, 44, 44, 15,
- 46, 49, 49, 44, 44, 44, 46, 44, 44, 44,
- 49, 15, 49, 49, 44, 81, 44, 52, 44, 60,
- 50, 81, 50, 44, 50, 44, 44, 44, 99, 3,
- 49, 49, 13, 37, 87, 56, 44, 54, 44, 20,
- 3, 49, 48, 68, 44, 44, 44, 44, 48, 48,
- 47, 44, 50, 46, 44, 44, 46, 46, 44, 44,
- 46, 44, 47, 46, 44, 44, 46, 46, 44, 85,
- 46, 3, 13, 31, 44, 15, 44, 35, -1, 49,
- 44, 49, 44, 51, 44, 49, -1, 49, 44, 49,
- -1, 61, -1, 49, 68, -1, 13, 37, 38, 16,
- 41, 57, 66, -1, 66, 68, 66, 44, 44, 44,
- -1, -1, 49, 49, 49, 51, 51, 44, 55, 44,
- 44, 44, 49, 44, 49, 49, 49, 51, 49, -1,
- 53, 13, 59, -1, 13, 5, 68, 16, 20, 18,
- 5, 66, -1, 13, -1, 66, 28, 29, 13, -1,
- 20, -1, -1, -1, -1, 20, 35, -1, 28, 29,
- 13, -1, -1, 28, 29, -1, -1, 20, 21, 22,
- 23, 24, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, 3,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, 13,
- -1, -1, -1, -1, -1, -1, 20, -1, -1, -1,
+ 26, 36, 15, 15, 15, 15, 26, 26, 3, 15,
+ 15, 26, 2, 15, 3, 19, 2, 15, 2, 2,
+ 37, 2, 15, 19, 15, 13, 68, 3, 3, 11,
+ 105, 4, 2, 36, 19, 15, 15, 36, 15, 36,
+ 3, 15, 3, 15, 3, 3, 15, 3, 26, 36,
+ 15, 22, 2, 94, 22, 15, 3, 3, 15, 2,
+ 15, 3, 3, 3, 2, 4, 3, 2, 22, 36,
+ 36, 15, 36, 2, 36, 3, 2, 2, 2, 15,
+ 101, 2, 15, 36, 36, 2, 13, 36, 3, 97,
+ 4, 22, 99, 3, 2, 2, 15, 13, -1, 22,
+ 45, 2, 13, 15, 36, 50, -1, -1, -1, 41,
+ 13, 45, -1, 16, 13, 45, 50, 16, 15, 13,
+ -1, 51, 16, 45, 3, 45, 42, 47, 50, 3,
+ -1, 42, 45, -1, 47, 3, 45, 15, 47, 45,
+ 45, 45, 47, 45, 50, 45, 50, 45, 50, 45,
+ 50, 36, 50, 49, 45, 45, 41, 47, 49, 45,
+ 38, 45, 2, 45, 50, 45, 50, 86, 50, 49,
+ 45, 3, 47, 45, 45, 45, 47, 47, 45, 13,
+ 47, 82, 45, 55, 47, 45, 2, 47, 100, 45,
+ 69, 88, 48, 45, 45, 69, 47, 45, 50, 45,
+ 48, 69, 45, 45, 45, 32, 47, -1, 42, 36,
+ 53, -1, 45, 59, 47, 45, 45, 45, 47, 61,
+ 45, 51, 47, 45, 45, 47, 45, 45, 47, 57,
+ 51, 45, -1, 51, 45, -1, 50, 69, 45, 50,
+ 54, 45, 82, 50, 45, 45, 50, 45, 52, 50,
+ 50, 62, 50, 45, 45, 56, 45, 45, 50, 50,
+ 67, 50, 50, 15, 52, 45, 45, 67, 60, 67,
+ 50, 50, 52, 52, 13, 45, 67, 16, 67, 18,
+ 50, 22, 23, 24, 25, 13, 38, 39, 58, -1,
+ -1, 13, 20, -1, -1, 5, -1, 36, 20, 5,
+ -1, 29, 30, 13, -1, -1, -1, 13, -1, -1,
+ 20, -1, -1, -1, 20, -1, -1, -1, 13, 29,
+ 30, -1, -1, 29, 30, 20, 21, 22, 23, 24,
+ 25, 13, -1, -1, -1, -1, -1, -1, 20, 21,
+ 22, 23, 24, 25, -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, 21, 22, 23, 24, 25,
-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,
@@ -984,6 +1002,6 @@ const short QDeclarativeJSGrammar::action_check [] = {
-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/declarative/qml/parser/qdeclarativejsgrammar_p.h b/src/declarative/qml/parser/qdeclarativejsgrammar_p.h
index dda1659d26..a093bc25d9 100644
--- a/src/declarative/qml/parser/qdeclarativejsgrammar_p.h
+++ b/src/declarative/qml/parser/qdeclarativejsgrammar_p.h
@@ -164,15 +164,15 @@ public:
T_XOR = 79,
T_XOR_EQ = 80,
- ACCEPT_STATE = 645,
- RULE_COUNT = 347,
- STATE_COUNT = 646,
+ ACCEPT_STATE = 640,
+ RULE_COUNT = 345,
+ STATE_COUNT = 641,
TERMINAL_COUNT = 101,
- NON_TERMINAL_COUNT = 106,
+ NON_TERMINAL_COUNT = 107,
- GOTO_INDEX_OFFSET = 646,
- GOTO_INFO_OFFSET = 2714,
- GOTO_CHECK_OFFSET = 2714
+ GOTO_INDEX_OFFSET = 641,
+ GOTO_INFO_OFFSET = 2787,
+ GOTO_CHECK_OFFSET = 2787
};
static const char *const spell [];
diff --git a/src/declarative/qml/parser/qdeclarativejslexer.cpp b/src/declarative/qml/parser/qdeclarativejslexer.cpp
index b718c0fbf0..4d68f289bc 100644
--- a/src/declarative/qml/parser/qdeclarativejslexer.cpp
+++ b/src/declarative/qml/parser/qdeclarativejslexer.cpp
@@ -43,11 +43,11 @@
#include <config.h>
#endif
-#include "private/qdeclarativejslexer_p.h"
+#include "qdeclarativejslexer_p.h"
-#include "private/qdeclarativejsglobal_p.h"
-#include "private/qdeclarativejsengine_p.h"
-#include "private/qdeclarativejsgrammar_p.h"
+#include "qdeclarativejsglobal_p.h"
+#include "qdeclarativejsengine_p.h"
+#include "qdeclarativejsgrammar_p.h"
#include <QtCore/qcoreapplication.h>
diff --git a/src/declarative/qml/parser/qdeclarativejslexer_p.h b/src/declarative/qml/parser/qdeclarativejslexer_p.h
index fbbd8f5684..5147df17e4 100644
--- a/src/declarative/qml/parser/qdeclarativejslexer_p.h
+++ b/src/declarative/qml/parser/qdeclarativejslexer_p.h
@@ -53,7 +53,7 @@
// We mean it.
//
-#include "private/qdeclarativejsglobal_p.h"
+#include "qdeclarativejsglobal_p.h"
#include <QtCore/QString>
diff --git a/src/declarative/qml/parser/qdeclarativejsmemorypool_p.h b/src/declarative/qml/parser/qdeclarativejsmemorypool_p.h
index 6d81e7565c..8d61dbe714 100644
--- a/src/declarative/qml/parser/qdeclarativejsmemorypool_p.h
+++ b/src/declarative/qml/parser/qdeclarativejsmemorypool_p.h
@@ -53,7 +53,7 @@
// We mean it.
//
-#include "private/qdeclarativejsglobal_p.h"
+#include "qdeclarativejsglobal_p.h"
#include <QtCore/qglobal.h>
#include <QtCore/qshareddata.h>
diff --git a/src/declarative/qml/parser/qdeclarativejsnodepool_p.h b/src/declarative/qml/parser/qdeclarativejsnodepool_p.h
index bc7d1017e9..401500c57c 100644
--- a/src/declarative/qml/parser/qdeclarativejsnodepool_p.h
+++ b/src/declarative/qml/parser/qdeclarativejsnodepool_p.h
@@ -53,8 +53,8 @@
// We mean it.
//
-#include "private/qdeclarativejsglobal_p.h"
-#include "private/qdeclarativejsmemorypool_p.h"
+#include "qdeclarativejsglobal_p.h"
+#include "qdeclarativejsmemorypool_p.h"
#include <QtCore/QHash>
#include <QtCore/QString>
diff --git a/src/declarative/qml/parser/qdeclarativejsparser.cpp b/src/declarative/qml/parser/qdeclarativejsparser.cpp
index f709843c43..d820c5d67a 100644
--- a/src/declarative/qml/parser/qdeclarativejsparser.cpp
+++ b/src/declarative/qml/parser/qdeclarativejsparser.cpp
@@ -44,14 +44,14 @@
#include <string.h>
-#include "private/qdeclarativejsengine_p.h"
-#include "private/qdeclarativejslexer_p.h"
-#include "private/qdeclarativejsast_p.h"
-#include "private/qdeclarativejsnodepool_p.h"
+#include "qdeclarativejsengine_p.h"
+#include "qdeclarativejslexer_p.h"
+#include "qdeclarativejsast_p.h"
+#include "qdeclarativejsnodepool_p.h"
-#include "private/qdeclarativejsparser_p.h"
+#include "qdeclarativejsparser_p.h"
#include <QVarLengthArray>
//
@@ -361,7 +361,8 @@ case 33: {
node->hasOnToken = true;
sym(1).Node = node;
} break;
-case 34:case 35:case 36:case 37:
+
+case 38:
{
AST::UiScriptBinding *node = makeAstNode<AST::UiScriptBinding> (driver->nodePool(),
sym(1).UiQualifiedId, sym(3).Statement);
@@ -369,35 +370,35 @@ case 34:case 35:case 36:case 37:
sym(1).Node = node;
} break;
-case 38:
+case 39:
-case 39: {
+case 40: {
sym(1).sval = driver->intern(lexer->characterBuffer(), lexer->characterCount());
break;
}
-case 41: {
+case 42: {
sym(1).Node = 0;
} break;
-case 42: {
+case 43: {
sym(1).Node = sym(1).UiParameterList->finish ();
} break;
-case 43: {
+case 44: {
AST::UiParameterList *node = makeAstNode<AST::UiParameterList> (driver->nodePool(), sym(1).sval, sym(2).sval);
node->identifierToken = loc(2);
sym(1).Node = node;
} break;
-case 44: {
+case 45: {
AST::UiParameterList *node = makeAstNode<AST::UiParameterList> (driver->nodePool(), sym(1).UiParameterList, sym(3).sval, sym(4).sval);
node->commaToken = loc(2);
node->identifierToken = loc(4);
sym(1).Node = node;
} break;
-case 46: {
+case 47: {
AST::UiPublicMember *node = makeAstNode<AST::UiPublicMember> (driver->nodePool(), (NameId *)0, sym(2).sval);
node->type = AST::UiPublicMember::Signal;
node->propertyToken = loc(1);
@@ -408,7 +409,7 @@ case 46: {
sym(1).Node = node;
} break;
-case 48: {
+case 49: {
AST::UiPublicMember *node = makeAstNode<AST::UiPublicMember> (driver->nodePool(), (NameId *)0, sym(2).sval);
node->type = AST::UiPublicMember::Signal;
node->propertyToken = loc(1);
@@ -418,7 +419,7 @@ case 48: {
sym(1).Node = node;
} break;
-case 50: {
+case 51: {
AST::UiPublicMember *node = makeAstNode<AST::UiPublicMember> (driver->nodePool(), sym(4).sval, sym(6).sval);
node->typeModifier = sym(2).sval;
node->propertyToken = loc(1);
@@ -429,7 +430,7 @@ case 50: {
sym(1).Node = node;
} break;
-case 52: {
+case 53: {
AST::UiPublicMember *node = makeAstNode<AST::UiPublicMember> (driver->nodePool(), sym(2).sval, sym(3).sval);
node->propertyToken = loc(1);
node->typeToken = loc(2);
@@ -438,7 +439,7 @@ case 52: {
sym(1).Node = node;
} break;
-case 54: {
+case 55: {
AST::UiPublicMember *node = makeAstNode<AST::UiPublicMember> (driver->nodePool(), sym(3).sval, sym(4).sval);
node->isDefaultMember = true;
node->defaultToken = loc(1);
@@ -451,42 +452,39 @@ case 54: {
case 56: {
AST::UiPublicMember *node = makeAstNode<AST::UiPublicMember> (driver->nodePool(), sym(2).sval, sym(3).sval,
- sym(5).Expression);
+ sym(5).Statement);
node->propertyToken = loc(1);
node->typeToken = loc(2);
node->identifierToken = loc(3);
node->colonToken = loc(4);
- node->semicolonToken = loc(6);
sym(1).Node = node;
} break;
-case 58: {
+case 57: {
AST::UiPublicMember *node = makeAstNode<AST::UiPublicMember> (driver->nodePool(), sym(3).sval, sym(4).sval,
- sym(6).Expression);
+ 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);
- node->semicolonToken = loc(7);
sym(1).Node = node;
} break;
-case 60: {
+case 58: {
AST::UiPublicMember *node = makeAstNode<AST::UiPublicMember> (driver->nodePool(), sym(3).sval, sym(4).sval,
- sym(6).Expression);
+ 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);
- node->semicolonToken = loc(7);
sym(1).Node = node;
} break;
-case 61: {
+case 59: {
AST::UiPublicMember *node = makeAstNode<AST::UiPublicMember> (driver->nodePool(), sym(4).sval, sym(6).sval);
node->typeModifier = sym(2).sval;
node->propertyToken = loc(1);
@@ -510,7 +508,7 @@ case 61: {
sym(1).Node = node;
} break;
-case 62: {
+case 60: {
AST::UiPublicMember *node = makeAstNode<AST::UiPublicMember> (driver->nodePool(), sym(2).sval, sym(3).sval);
node->propertyToken = loc(1);
node->typeToken = loc(2);
@@ -530,81 +528,81 @@ case 62: {
sym(1).Node = node;
} break;
-case 63: {
+case 61: {
sym(1).Node = makeAstNode<AST::UiSourceElement>(driver->nodePool(), sym(1).Node);
} break;
-case 64: {
+case 62: {
sym(1).Node = makeAstNode<AST::UiSourceElement>(driver->nodePool(), sym(1).Node);
} break;
-case 66: {
+case 64: {
QString s = QLatin1String(QDeclarativeJSGrammar::spell[T_PROPERTY]);
sym(1).sval = driver->intern(s.constData(), s.length());
break;
}
-case 67: {
+case 65: {
QString s = QLatin1String(QDeclarativeJSGrammar::spell[T_SIGNAL]);
sym(1).sval = driver->intern(s.constData(), s.length());
break;
}
-case 68: {
+case 66: {
QString s = QLatin1String(QDeclarativeJSGrammar::spell[T_READONLY]);
sym(1).sval = driver->intern(s.constData(), s.length());
break;
}
-case 69: {
+case 67: {
QString s = QLatin1String(QDeclarativeJSGrammar::spell[T_ON]);
sym(1).sval = driver->intern(s.constData(), s.length());
break;
}
-case 70: {
+case 68: {
AST::ThisExpression *node = makeAstNode<AST::ThisExpression> (driver->nodePool());
node->thisToken = loc(1);
sym(1).Node = node;
} break;
-case 71: {
+case 69: {
AST::IdentifierExpression *node = makeAstNode<AST::IdentifierExpression> (driver->nodePool(), sym(1).sval);
node->identifierToken = loc(1);
sym(1).Node = node;
} break;
-case 72: {
+case 70: {
AST::NullExpression *node = makeAstNode<AST::NullExpression> (driver->nodePool());
node->nullToken = loc(1);
sym(1).Node = node;
} break;
-case 73: {
+case 71: {
AST::TrueLiteral *node = makeAstNode<AST::TrueLiteral> (driver->nodePool());
node->trueToken = loc(1);
sym(1).Node = node;
} break;
-case 74: {
+case 72: {
AST::FalseLiteral *node = makeAstNode<AST::FalseLiteral> (driver->nodePool());
node->falseToken = loc(1);
sym(1).Node = node;
} break;
-case 75: {
+case 73: {
AST::NumericLiteral *node = makeAstNode<AST::NumericLiteral> (driver->nodePool(), sym(1).dval);
node->literalToken = loc(1);
sym(1).Node = node;
} break;
-case 76:
-case 77: {
+case 74:
+case 75: {
AST::StringLiteral *node = makeAstNode<AST::StringLiteral> (driver->nodePool(), sym(1).sval);
node->literalToken = loc(1);
sym(1).Node = node;
} break;
-case 78: {
+case 76: {
bool rx = lexer->scanRegExp(Lexer::NoPrefix);
if (!rx) {
diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, location(lexer), lexer->errorMessage()));
@@ -618,7 +616,7 @@ case 78: {
sym(1).Node = node;
} break;
-case 79: {
+case 77: {
bool rx = lexer->scanRegExp(Lexer::EqualPrefix);
if (!rx) {
diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, location(lexer), lexer->errorMessage()));
@@ -632,28 +630,28 @@ case 79: {
sym(1).Node = node;
} break;
-case 80: {
+case 78: {
AST::ArrayLiteral *node = makeAstNode<AST::ArrayLiteral> (driver->nodePool(), (AST::Elision *) 0);
node->lbracketToken = loc(1);
node->rbracketToken = loc(2);
sym(1).Node = node;
} break;
-case 81: {
+case 79: {
AST::ArrayLiteral *node = makeAstNode<AST::ArrayLiteral> (driver->nodePool(), sym(2).Elision->finish());
node->lbracketToken = loc(1);
node->rbracketToken = loc(3);
sym(1).Node = node;
} break;
-case 82: {
+case 80: {
AST::ArrayLiteral *node = makeAstNode<AST::ArrayLiteral> (driver->nodePool(), sym(2).ElementList->finish ());
node->lbracketToken = loc(1);
node->rbracketToken = loc(3);
sym(1).Node = node;
} break;
-case 83: {
+case 81: {
AST::ArrayLiteral *node = makeAstNode<AST::ArrayLiteral> (driver->nodePool(), sym(2).ElementList->finish (),
(AST::Elision *) 0);
node->lbracketToken = loc(1);
@@ -662,7 +660,7 @@ case 83: {
sym(1).Node = node;
} break;
-case 84: {
+case 82: {
AST::ArrayLiteral *node = makeAstNode<AST::ArrayLiteral> (driver->nodePool(), sym(2).ElementList->finish (),
sym(4).Elision->finish());
node->lbracketToken = loc(1);
@@ -671,7 +669,7 @@ case 84: {
sym(1).Node = node;
} break;
-case 85: {
+case 83: {
AST::ObjectLiteral *node = 0;
if (sym(2).Node)
node = makeAstNode<AST::ObjectLiteral> (driver->nodePool(),
@@ -683,7 +681,7 @@ case 85: {
sym(1).Node = node;
} break;
-case 86: {
+case 84: {
AST::ObjectLiteral *node = makeAstNode<AST::ObjectLiteral> (driver->nodePool(),
sym(2).PropertyNameAndValueList->finish ());
node->lbraceToken = loc(1);
@@ -691,14 +689,14 @@ case 86: {
sym(1).Node = node;
} break;
-case 87: {
+case 85: {
AST::NestedExpression *node = makeAstNode<AST::NestedExpression>(driver->nodePool(), sym(2).Expression);
node->lparenToken = loc(1);
node->rparenToken = loc(3);
sym(1).Node = node;
} break;
-case 88: {
+case 86: {
if (AST::ArrayMemberExpression *mem = AST::cast<AST::ArrayMemberExpression *>(sym(1).Expression)) {
diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Warning, mem->lbracketToken,
QLatin1String("Ignored annotation")));
@@ -718,48 +716,48 @@ case 88: {
}
} break;
-case 89: {
+case 87: {
sym(1).Node = makeAstNode<AST::ElementList> (driver->nodePool(), (AST::Elision *) 0, sym(1).Expression);
} break;
-case 90: {
+case 88: {
sym(1).Node = makeAstNode<AST::ElementList> (driver->nodePool(), sym(1).Elision->finish(), sym(2).Expression);
} break;
-case 91: {
+case 89: {
AST::ElementList *node = makeAstNode<AST::ElementList> (driver->nodePool(), sym(1).ElementList,
(AST::Elision *) 0, sym(3).Expression);
node->commaToken = loc(2);
sym(1).Node = node;
} break;
-case 92: {
+case 90: {
AST::ElementList *node = makeAstNode<AST::ElementList> (driver->nodePool(), sym(1).ElementList, sym(3).Elision->finish(),
sym(4).Expression);
node->commaToken = loc(2);
sym(1).Node = node;
} break;
-case 93: {
+case 91: {
AST::Elision *node = makeAstNode<AST::Elision> (driver->nodePool());
node->commaToken = loc(1);
sym(1).Node = node;
} break;
-case 94: {
+case 92: {
AST::Elision *node = makeAstNode<AST::Elision> (driver->nodePool(), sym(1).Elision);
node->commaToken = loc(2);
sym(1).Node = node;
} break;
-case 95: {
+case 93: {
AST::PropertyNameAndValueList *node = makeAstNode<AST::PropertyNameAndValueList> (driver->nodePool(),
sym(1).PropertyName, sym(3).Expression);
node->colonToken = loc(2);
sym(1).Node = node;
} break;
-case 96: {
+case 94: {
AST::PropertyNameAndValueList *node = makeAstNode<AST::PropertyNameAndValueList> (driver->nodePool(),
sym(1).PropertyNameAndValueList, sym(3).PropertyName, sym(5).Expression);
node->commaToken = loc(2);
@@ -767,36 +765,40 @@ case 96: {
sym(1).Node = node;
} break;
-case 97: {
+case 95: {
AST::IdentifierPropertyName *node = makeAstNode<AST::IdentifierPropertyName> (driver->nodePool(), sym(1).sval);
node->propertyNameToken = loc(1);
sym(1).Node = node;
} break;
-case 98:
-case 99: {
+case 96:
+case 97: {
AST::IdentifierPropertyName *node = makeAstNode<AST::IdentifierPropertyName> (driver->nodePool(), driver->intern(lexer->characterBuffer(), lexer->characterCount()));
node->propertyNameToken = loc(1);
sym(1).Node = node;
} break;
-case 100: {
+case 98: {
AST::StringLiteralPropertyName *node = makeAstNode<AST::StringLiteralPropertyName> (driver->nodePool(), sym(1).sval);
node->propertyNameToken = loc(1);
sym(1).Node = node;
} break;
-case 101: {
+case 99: {
AST::NumericLiteralPropertyName *node = makeAstNode<AST::NumericLiteralPropertyName> (driver->nodePool(), sym(1).dval);
node->propertyNameToken = loc(1);
sym(1).Node = node;
} break;
-case 102: {
+case 100: {
AST::IdentifierPropertyName *node = makeAstNode<AST::IdentifierPropertyName> (driver->nodePool(), sym(1).sval);
node->propertyNameToken = loc(1);
sym(1).Node = node;
} break;
+case 101:
+
+case 102:
+
case 103:
case 104:
@@ -854,29 +856,25 @@ case 129:
case 130:
case 131:
-
-case 132:
-
-case 133:
{
sym(1).sval = driver->intern(lexer->characterBuffer(), lexer->characterCount());
} break;
-case 138: {
+case 136: {
AST::ArrayMemberExpression *node = makeAstNode<AST::ArrayMemberExpression> (driver->nodePool(), sym(1).Expression, sym(3).Expression);
node->lbracketToken = loc(2);
node->rbracketToken = loc(4);
sym(1).Node = node;
} break;
-case 139: {
+case 137: {
AST::FieldMemberExpression *node = makeAstNode<AST::FieldMemberExpression> (driver->nodePool(), sym(1).Expression, sym(3).sval);
node->dotToken = loc(2);
node->identifierToken = loc(3);
sym(1).Node = node;
} break;
-case 140: {
+case 138: {
AST::NewMemberExpression *node = makeAstNode<AST::NewMemberExpression> (driver->nodePool(), sym(2).Expression, sym(4).ArgumentList);
node->newToken = loc(1);
node->lparenToken = loc(3);
@@ -884,384 +882,384 @@ case 140: {
sym(1).Node = node;
} break;
-case 142: {
+case 140: {
AST::NewExpression *node = makeAstNode<AST::NewExpression> (driver->nodePool(), sym(2).Expression);
node->newToken = loc(1);
sym(1).Node = node;
} break;
-case 143: {
+case 141: {
AST::CallExpression *node = makeAstNode<AST::CallExpression> (driver->nodePool(), sym(1).Expression, sym(3).ArgumentList);
node->lparenToken = loc(2);
node->rparenToken = loc(4);
sym(1).Node = node;
} break;
-case 144: {
+case 142: {
AST::CallExpression *node = makeAstNode<AST::CallExpression> (driver->nodePool(), sym(1).Expression, sym(3).ArgumentList);
node->lparenToken = loc(2);
node->rparenToken = loc(4);
sym(1).Node = node;
} break;
-case 145: {
+case 143: {
AST::ArrayMemberExpression *node = makeAstNode<AST::ArrayMemberExpression> (driver->nodePool(), sym(1).Expression, sym(3).Expression);
node->lbracketToken = loc(2);
node->rbracketToken = loc(4);
sym(1).Node = node;
} break;
-case 146: {
+case 144: {
AST::FieldMemberExpression *node = makeAstNode<AST::FieldMemberExpression> (driver->nodePool(), sym(1).Expression, sym(3).sval);
node->dotToken = loc(2);
node->identifierToken = loc(3);
sym(1).Node = node;
} break;
-case 147: {
+case 145: {
sym(1).Node = 0;
} break;
-case 148: {
+case 146: {
sym(1).Node = sym(1).ArgumentList->finish();
} break;
-case 149: {
+case 147: {
sym(1).Node = makeAstNode<AST::ArgumentList> (driver->nodePool(), sym(1).Expression);
} break;
-case 150: {
+case 148: {
AST::ArgumentList *node = makeAstNode<AST::ArgumentList> (driver->nodePool(), sym(1).ArgumentList, sym(3).Expression);
node->commaToken = loc(2);
sym(1).Node = node;
} break;
-case 154: {
+case 152: {
AST::PostIncrementExpression *node = makeAstNode<AST::PostIncrementExpression> (driver->nodePool(), sym(1).Expression);
node->incrementToken = loc(2);
sym(1).Node = node;
} break;
-case 155: {
+case 153: {
AST::PostDecrementExpression *node = makeAstNode<AST::PostDecrementExpression> (driver->nodePool(), sym(1).Expression);
node->decrementToken = loc(2);
sym(1).Node = node;
} break;
-case 157: {
+case 155: {
AST::DeleteExpression *node = makeAstNode<AST::DeleteExpression> (driver->nodePool(), sym(2).Expression);
node->deleteToken = loc(1);
sym(1).Node = node;
} break;
-case 158: {
+case 156: {
AST::VoidExpression *node = makeAstNode<AST::VoidExpression> (driver->nodePool(), sym(2).Expression);
node->voidToken = loc(1);
sym(1).Node = node;
} break;
-case 159: {
+case 157: {
AST::TypeOfExpression *node = makeAstNode<AST::TypeOfExpression> (driver->nodePool(), sym(2).Expression);
node->typeofToken = loc(1);
sym(1).Node = node;
} break;
-case 160: {
+case 158: {
AST::PreIncrementExpression *node = makeAstNode<AST::PreIncrementExpression> (driver->nodePool(), sym(2).Expression);
node->incrementToken = loc(1);
sym(1).Node = node;
} break;
-case 161: {
+case 159: {
AST::PreDecrementExpression *node = makeAstNode<AST::PreDecrementExpression> (driver->nodePool(), sym(2).Expression);
node->decrementToken = loc(1);
sym(1).Node = node;
} break;
-case 162: {
+case 160: {
AST::UnaryPlusExpression *node = makeAstNode<AST::UnaryPlusExpression> (driver->nodePool(), sym(2).Expression);
node->plusToken = loc(1);
sym(1).Node = node;
} break;
-case 163: {
+case 161: {
AST::UnaryMinusExpression *node = makeAstNode<AST::UnaryMinusExpression> (driver->nodePool(), sym(2).Expression);
node->minusToken = loc(1);
sym(1).Node = node;
} break;
-case 164: {
+case 162: {
AST::TildeExpression *node = makeAstNode<AST::TildeExpression> (driver->nodePool(), sym(2).Expression);
node->tildeToken = loc(1);
sym(1).Node = node;
} break;
-case 165: {
+case 163: {
AST::NotExpression *node = makeAstNode<AST::NotExpression> (driver->nodePool(), sym(2).Expression);
node->notToken = loc(1);
sym(1).Node = node;
} break;
-case 167: {
+case 165: {
AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
QSOperator::Mul, sym(3).Expression);
node->operatorToken = loc(2);
sym(1).Node = node;
} break;
-case 168: {
+case 166: {
AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
QSOperator::Div, sym(3).Expression);
node->operatorToken = loc(2);
sym(1).Node = node;
} break;
-case 169: {
+case 167: {
AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
QSOperator::Mod, sym(3).Expression);
node->operatorToken = loc(2);
sym(1).Node = node;
} break;
-case 171: {
+case 169: {
AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
QSOperator::Add, sym(3).Expression);
node->operatorToken = loc(2);
sym(1).Node = node;
} break;
-case 172: {
+case 170: {
AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
QSOperator::Sub, sym(3).Expression);
node->operatorToken = loc(2);
sym(1).Node = node;
} break;
-case 174: {
+case 172: {
AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
QSOperator::LShift, sym(3).Expression);
node->operatorToken = loc(2);
sym(1).Node = node;
} break;
-case 175: {
+case 173: {
AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
QSOperator::RShift, sym(3).Expression);
node->operatorToken = loc(2);
sym(1).Node = node;
} break;
-case 176: {
+case 174: {
AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
QSOperator::URShift, sym(3).Expression);
node->operatorToken = loc(2);
sym(1).Node = node;
} break;
-case 178: {
+case 176: {
AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
QSOperator::Lt, sym(3).Expression);
node->operatorToken = loc(2);
sym(1).Node = node;
} break;
-case 179: {
+case 177: {
AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
QSOperator::Gt, sym(3).Expression);
node->operatorToken = loc(2);
sym(1).Node = node;
} break;
-case 180: {
+case 178: {
AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
QSOperator::Le, sym(3).Expression);
node->operatorToken = loc(2);
sym(1).Node = node;
} break;
-case 181: {
+case 179: {
AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
QSOperator::Ge, sym(3).Expression);
node->operatorToken = loc(2);
sym(1).Node = node;
} break;
-case 182: {
+case 180: {
AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
QSOperator::InstanceOf, sym(3).Expression);
node->operatorToken = loc(2);
sym(1).Node = node;
} break;
-case 183: {
+case 181: {
AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
QSOperator::In, sym(3).Expression);
node->operatorToken = loc(2);
sym(1).Node = node;
} break;
-case 185: {
+case 183: {
AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
QSOperator::Lt, sym(3).Expression);
node->operatorToken = loc(2);
sym(1).Node = node;
} break;
-case 186: {
+case 184: {
AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
QSOperator::Gt, sym(3).Expression);
node->operatorToken = loc(2);
sym(1).Node = node;
} break;
-case 187: {
+case 185: {
AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
QSOperator::Le, sym(3).Expression);
node->operatorToken = loc(2);
sym(1).Node = node;
} break;
-case 188: {
+case 186: {
AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
QSOperator::Ge, sym(3).Expression);
node->operatorToken = loc(2);
sym(1).Node = node;
} break;
-case 189: {
+case 187: {
AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
QSOperator::InstanceOf, sym(3).Expression);
node->operatorToken = loc(2);
sym(1).Node = node;
} break;
-case 191: {
+case 189: {
AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
QSOperator::Equal, sym(3).Expression);
node->operatorToken = loc(2);
sym(1).Node = node;
} break;
-case 192: {
+case 190: {
AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
QSOperator::NotEqual, sym(3).Expression);
node->operatorToken = loc(2);
sym(1).Node = node;
} break;
-case 193: {
+case 191: {
AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
QSOperator::StrictEqual, sym(3).Expression);
node->operatorToken = loc(2);
sym(1).Node = node;
} break;
-case 194: {
+case 192: {
AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
QSOperator::StrictNotEqual, sym(3).Expression);
node->operatorToken = loc(2);
sym(1).Node = node;
} break;
-case 196: {
+case 194: {
AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
QSOperator::Equal, sym(3).Expression);
node->operatorToken = loc(2);
sym(1).Node = node;
} break;
-case 197: {
+case 195: {
AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
QSOperator::NotEqual, sym(3).Expression);
node->operatorToken = loc(2);
sym(1).Node = node;
} break;
-case 198: {
+case 196: {
AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
QSOperator::StrictEqual, sym(3).Expression);
node->operatorToken = loc(2);
sym(1).Node = node;
} break;
-case 199: {
+case 197: {
AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
QSOperator::StrictNotEqual, sym(3).Expression);
node->operatorToken = loc(2);
sym(1).Node = node;
} break;
-case 201: {
+case 199: {
AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
QSOperator::BitAnd, sym(3).Expression);
node->operatorToken = loc(2);
sym(1).Node = node;
} break;
-case 203: {
+case 201: {
AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
QSOperator::BitAnd, sym(3).Expression);
node->operatorToken = loc(2);
sym(1).Node = node;
} break;
-case 205: {
+case 203: {
AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
QSOperator::BitXor, sym(3).Expression);
node->operatorToken = loc(2);
sym(1).Node = node;
} break;
-case 207: {
+case 205: {
AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
QSOperator::BitXor, sym(3).Expression);
node->operatorToken = loc(2);
sym(1).Node = node;
} break;
-case 209: {
+case 207: {
AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
QSOperator::BitOr, sym(3).Expression);
node->operatorToken = loc(2);
sym(1).Node = node;
} break;
-case 211: {
+case 209: {
AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
QSOperator::BitOr, sym(3).Expression);
node->operatorToken = loc(2);
sym(1).Node = node;
} break;
-case 213: {
+case 211: {
AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
QSOperator::And, sym(3).Expression);
node->operatorToken = loc(2);
sym(1).Node = node;
} break;
-case 215: {
+case 213: {
AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
QSOperator::And, sym(3).Expression);
node->operatorToken = loc(2);
sym(1).Node = node;
} break;
-case 217: {
+case 215: {
AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
QSOperator::Or, sym(3).Expression);
node->operatorToken = loc(2);
sym(1).Node = node;
} break;
-case 219: {
+case 217: {
AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
QSOperator::Or, sym(3).Expression);
node->operatorToken = loc(2);
sym(1).Node = node;
} break;
-case 221: {
+case 219: {
AST::ConditionalExpression *node = makeAstNode<AST::ConditionalExpression> (driver->nodePool(), sym(1).Expression,
sym(3).Expression, sym(5).Expression);
node->questionToken = loc(2);
@@ -1269,7 +1267,7 @@ case 221: {
sym(1).Node = node;
} break;
-case 223: {
+case 221: {
AST::ConditionalExpression *node = makeAstNode<AST::ConditionalExpression> (driver->nodePool(), sym(1).Expression,
sym(3).Expression, sym(5).Expression);
node->questionToken = loc(2);
@@ -1277,112 +1275,112 @@ case 223: {
sym(1).Node = node;
} break;
-case 225: {
+case 223: {
AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
sym(2).ival, sym(3).Expression);
node->operatorToken = loc(2);
sym(1).Node = node;
} break;
-case 227: {
+case 225: {
AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
sym(2).ival, sym(3).Expression);
node->operatorToken = loc(2);
sym(1).Node = node;
} break;
-case 228: {
+case 226: {
sym(1).ival = QSOperator::Assign;
} break;
-case 229: {
+case 227: {
sym(1).ival = QSOperator::InplaceMul;
} break;
-case 230: {
+case 228: {
sym(1).ival = QSOperator::InplaceDiv;
} break;
-case 231: {
+case 229: {
sym(1).ival = QSOperator::InplaceMod;
} break;
-case 232: {
+case 230: {
sym(1).ival = QSOperator::InplaceAdd;
} break;
-case 233: {
+case 231: {
sym(1).ival = QSOperator::InplaceSub;
} break;
-case 234: {
+case 232: {
sym(1).ival = QSOperator::InplaceLeftShift;
} break;
-case 235: {
+case 233: {
sym(1).ival = QSOperator::InplaceRightShift;
} break;
-case 236: {
+case 234: {
sym(1).ival = QSOperator::InplaceURightShift;
} break;
-case 237: {
+case 235: {
sym(1).ival = QSOperator::InplaceAnd;
} break;
-case 238: {
+case 236: {
sym(1).ival = QSOperator::InplaceXor;
} break;
-case 239: {
+case 237: {
sym(1).ival = QSOperator::InplaceOr;
} break;
-case 241: {
+case 239: {
AST::Expression *node = makeAstNode<AST::Expression> (driver->nodePool(), sym(1).Expression, sym(3).Expression);
node->commaToken = loc(2);
sym(1).Node = node;
} break;
-case 242: {
+case 240: {
sym(1).Node = 0;
} break;
-case 245: {
+case 243: {
AST::Expression *node = makeAstNode<AST::Expression> (driver->nodePool(), sym(1).Expression, sym(3).Expression);
node->commaToken = loc(2);
sym(1).Node = node;
} break;
-case 246: {
+case 244: {
sym(1).Node = 0;
} break;
-case 263: {
+case 261: {
AST::Block *node = makeAstNode<AST::Block> (driver->nodePool(), sym(2).StatementList);
node->lbraceToken = loc(1);
node->rbraceToken = loc(3);
sym(1).Node = node;
} break;
-case 264: {
+case 262: {
sym(1).Node = makeAstNode<AST::StatementList> (driver->nodePool(), sym(1).Statement);
} break;
-case 265: {
+case 263: {
sym(1).Node = makeAstNode<AST::StatementList> (driver->nodePool(), sym(1).StatementList, sym(2).Statement);
} break;
-case 266: {
+case 264: {
sym(1).Node = 0;
} break;
-case 267: {
+case 265: {
sym(1).Node = sym(1).StatementList->finish ();
} break;
-case 269: {
+case 267: {
AST::VariableStatement *node = makeAstNode<AST::VariableStatement> (driver->nodePool(),
sym(2).VariableDeclarationList->finish (/*readOnly=*/sym(1).ival == T_CONST));
node->declarationKindToken = loc(1);
@@ -1390,76 +1388,76 @@ case 269: {
sym(1).Node = node;
} break;
-case 270: {
+case 268: {
sym(1).ival = T_CONST;
} break;
-case 271: {
+case 269: {
sym(1).ival = T_VAR;
} break;
-case 272: {
+case 270: {
sym(1).Node = makeAstNode<AST::VariableDeclarationList> (driver->nodePool(), sym(1).VariableDeclaration);
} break;
-case 273: {
+case 271: {
AST::VariableDeclarationList *node = makeAstNode<AST::VariableDeclarationList> (driver->nodePool(),
sym(1).VariableDeclarationList, sym(3).VariableDeclaration);
node->commaToken = loc(2);
sym(1).Node = node;
} break;
-case 274: {
+case 272: {
sym(1).Node = makeAstNode<AST::VariableDeclarationList> (driver->nodePool(), sym(1).VariableDeclaration);
} break;
-case 275: {
+case 273: {
sym(1).Node = makeAstNode<AST::VariableDeclarationList> (driver->nodePool(), sym(1).VariableDeclarationList, sym(3).VariableDeclaration);
} break;
-case 276: {
+case 274: {
AST::VariableDeclaration *node = makeAstNode<AST::VariableDeclaration> (driver->nodePool(), sym(1).sval, sym(2).Expression);
node->identifierToken = loc(1);
sym(1).Node = node;
} break;
-case 277: {
+case 275: {
AST::VariableDeclaration *node = makeAstNode<AST::VariableDeclaration> (driver->nodePool(), sym(1).sval, sym(2).Expression);
node->identifierToken = loc(1);
sym(1).Node = node;
} break;
-case 278: {
+case 276: {
// ### TODO: AST for initializer
sym(1) = sym(2);
} break;
-case 279: {
+case 277: {
sym(1).Node = 0;
} break;
-case 281: {
+case 279: {
// ### TODO: AST for initializer
sym(1) = sym(2);
} break;
-case 282: {
+case 280: {
sym(1).Node = 0;
} break;
-case 284: {
+case 282: {
AST::EmptyStatement *node = makeAstNode<AST::EmptyStatement> (driver->nodePool());
node->semicolonToken = loc(1);
sym(1).Node = node;
} break;
-case 286: {
+case 284: {
AST::ExpressionStatement *node = makeAstNode<AST::ExpressionStatement> (driver->nodePool(), sym(1).Expression);
node->semicolonToken = loc(2);
sym(1).Node = node;
} break;
-case 287: {
+case 285: {
AST::IfStatement *node = makeAstNode<AST::IfStatement> (driver->nodePool(), sym(3).Expression, sym(5).Statement, sym(7).Statement);
node->ifToken = loc(1);
node->lparenToken = loc(2);
@@ -1468,7 +1466,7 @@ case 287: {
sym(1).Node = node;
} break;
-case 288: {
+case 286: {
AST::IfStatement *node = makeAstNode<AST::IfStatement> (driver->nodePool(), sym(3).Expression, sym(5).Statement);
node->ifToken = loc(1);
node->lparenToken = loc(2);
@@ -1476,7 +1474,7 @@ case 288: {
sym(1).Node = node;
} break;
-case 290: {
+case 288: {
AST::DoWhileStatement *node = makeAstNode<AST::DoWhileStatement> (driver->nodePool(), sym(2).Statement, sym(5).Expression);
node->doToken = loc(1);
node->whileToken = loc(3);
@@ -1486,7 +1484,7 @@ case 290: {
sym(1).Node = node;
} break;
-case 291: {
+case 289: {
AST::WhileStatement *node = makeAstNode<AST::WhileStatement> (driver->nodePool(), sym(3).Expression, sym(5).Statement);
node->whileToken = loc(1);
node->lparenToken = loc(2);
@@ -1494,7 +1492,7 @@ case 291: {
sym(1).Node = node;
} break;
-case 292: {
+case 290: {
AST::ForStatement *node = makeAstNode<AST::ForStatement> (driver->nodePool(), sym(3).Expression,
sym(5).Expression, sym(7).Expression, sym(9).Statement);
node->forToken = loc(1);
@@ -1505,7 +1503,7 @@ case 292: {
sym(1).Node = node;
} break;
-case 293: {
+case 291: {
AST::LocalForStatement *node = makeAstNode<AST::LocalForStatement> (driver->nodePool(),
sym(4).VariableDeclarationList->finish (/*readOnly=*/false), sym(6).Expression,
sym(8).Expression, sym(10).Statement);
@@ -1518,7 +1516,7 @@ case 293: {
sym(1).Node = node;
} break;
-case 294: {
+case 292: {
AST:: ForEachStatement *node = makeAstNode<AST::ForEachStatement> (driver->nodePool(), sym(3).Expression,
sym(5).Expression, sym(7).Statement);
node->forToken = loc(1);
@@ -1528,7 +1526,7 @@ case 294: {
sym(1).Node = node;
} break;
-case 295: {
+case 293: {
AST::LocalForEachStatement *node = makeAstNode<AST::LocalForEachStatement> (driver->nodePool(),
sym(4).VariableDeclaration, sym(6).Expression, sym(8).Statement);
node->forToken = loc(1);
@@ -1539,14 +1537,14 @@ case 295: {
sym(1).Node = node;
} break;
-case 297: {
+case 295: {
AST::ContinueStatement *node = makeAstNode<AST::ContinueStatement> (driver->nodePool());
node->continueToken = loc(1);
node->semicolonToken = loc(2);
sym(1).Node = node;
} break;
-case 299: {
+case 297: {
AST::ContinueStatement *node = makeAstNode<AST::ContinueStatement> (driver->nodePool(), sym(2).sval);
node->continueToken = loc(1);
node->identifierToken = loc(2);
@@ -1554,14 +1552,14 @@ case 299: {
sym(1).Node = node;
} break;
-case 301: {
+case 299: {
AST::BreakStatement *node = makeAstNode<AST::BreakStatement> (driver->nodePool());
node->breakToken = loc(1);
node->semicolonToken = loc(2);
sym(1).Node = node;
} break;
-case 303: {
+case 301: {
AST::BreakStatement *node = makeAstNode<AST::BreakStatement> (driver->nodePool(), sym(2).sval);
node->breakToken = loc(1);
node->identifierToken = loc(2);
@@ -1569,14 +1567,14 @@ case 303: {
sym(1).Node = node;
} break;
-case 305: {
+case 303: {
AST::ReturnStatement *node = makeAstNode<AST::ReturnStatement> (driver->nodePool(), sym(2).Expression);
node->returnToken = loc(1);
node->semicolonToken = loc(3);
sym(1).Node = node;
} break;
-case 306: {
+case 304: {
AST::WithStatement *node = makeAstNode<AST::WithStatement> (driver->nodePool(), sym(3).Expression, sym(5).Statement);
node->withToken = loc(1);
node->lparenToken = loc(2);
@@ -1584,7 +1582,7 @@ case 306: {
sym(1).Node = node;
} break;
-case 307: {
+case 305: {
AST::SwitchStatement *node = makeAstNode<AST::SwitchStatement> (driver->nodePool(), sym(3).Expression, sym(5).CaseBlock);
node->switchToken = loc(1);
node->lparenToken = loc(2);
@@ -1592,90 +1590,90 @@ case 307: {
sym(1).Node = node;
} break;
-case 308: {
+case 306: {
AST::CaseBlock *node = makeAstNode<AST::CaseBlock> (driver->nodePool(), sym(2).CaseClauses);
node->lbraceToken = loc(1);
node->rbraceToken = loc(3);
sym(1).Node = node;
} break;
-case 309: {
+case 307: {
AST::CaseBlock *node = makeAstNode<AST::CaseBlock> (driver->nodePool(), sym(2).CaseClauses, sym(3).DefaultClause, sym(4).CaseClauses);
node->lbraceToken = loc(1);
node->rbraceToken = loc(5);
sym(1).Node = node;
} break;
-case 310: {
+case 308: {
sym(1).Node = makeAstNode<AST::CaseClauses> (driver->nodePool(), sym(1).CaseClause);
} break;
-case 311: {
+case 309: {
sym(1).Node = makeAstNode<AST::CaseClauses> (driver->nodePool(), sym(1).CaseClauses, sym(2).CaseClause);
} break;
-case 312: {
+case 310: {
sym(1).Node = 0;
} break;
-case 313: {
+case 311: {
sym(1).Node = sym(1).CaseClauses->finish ();
} break;
-case 314: {
+case 312: {
AST::CaseClause *node = makeAstNode<AST::CaseClause> (driver->nodePool(), sym(2).Expression, sym(4).StatementList);
node->caseToken = loc(1);
node->colonToken = loc(3);
sym(1).Node = node;
} break;
-case 315: {
+case 313: {
AST::DefaultClause *node = makeAstNode<AST::DefaultClause> (driver->nodePool(), sym(3).StatementList);
node->defaultToken = loc(1);
node->colonToken = loc(2);
sym(1).Node = node;
} break;
-case 316:
-case 317: {
+case 314:
+case 315: {
AST::LabelledStatement *node = makeAstNode<AST::LabelledStatement> (driver->nodePool(), driver->intern(lexer->characterBuffer(), lexer->characterCount()), sym(3).Statement);
node->identifierToken = loc(1);
node->colonToken = loc(2);
sym(1).Node = node;
} break;
-case 318: {
+case 316: {
AST::LabelledStatement *node = makeAstNode<AST::LabelledStatement> (driver->nodePool(), sym(1).sval, sym(3).Statement);
node->identifierToken = loc(1);
node->colonToken = loc(2);
sym(1).Node = node;
} break;
-case 320: {
+case 318: {
AST::ThrowStatement *node = makeAstNode<AST::ThrowStatement> (driver->nodePool(), sym(2).Expression);
node->throwToken = loc(1);
node->semicolonToken = loc(3);
sym(1).Node = node;
} break;
-case 321: {
+case 319: {
AST::TryStatement *node = makeAstNode<AST::TryStatement> (driver->nodePool(), sym(2).Statement, sym(3).Catch);
node->tryToken = loc(1);
sym(1).Node = node;
} break;
-case 322: {
+case 320: {
AST::TryStatement *node = makeAstNode<AST::TryStatement> (driver->nodePool(), sym(2).Statement, sym(3).Finally);
node->tryToken = loc(1);
sym(1).Node = node;
} break;
-case 323: {
+case 321: {
AST::TryStatement *node = makeAstNode<AST::TryStatement> (driver->nodePool(), sym(2).Statement, sym(3).Catch, sym(4).Finally);
node->tryToken = loc(1);
sym(1).Node = node;
} break;
-case 324: {
+case 322: {
AST::Catch *node = makeAstNode<AST::Catch> (driver->nodePool(), sym(3).sval, sym(5).Block);
node->catchToken = loc(1);
node->lparenToken = loc(2);
@@ -1684,20 +1682,20 @@ case 324: {
sym(1).Node = node;
} break;
-case 325: {
+case 323: {
AST::Finally *node = makeAstNode<AST::Finally> (driver->nodePool(), sym(2).Block);
node->finallyToken = loc(1);
sym(1).Node = node;
} break;
-case 327: {
+case 325: {
AST::DebuggerStatement *node = makeAstNode<AST::DebuggerStatement> (driver->nodePool());
node->debuggerToken = loc(1);
node->semicolonToken = loc(2);
sym(1).Node = node;
} break;
-case 328: {
+case 326: {
AST::FunctionDeclaration *node = makeAstNode<AST::FunctionDeclaration> (driver->nodePool(), sym(2).sval, sym(4).FormalParameterList, sym(7).FunctionBody);
node->functionToken = loc(1);
node->identifierToken = loc(2);
@@ -1708,7 +1706,7 @@ case 328: {
sym(1).Node = node;
} break;
-case 329: {
+case 327: {
AST::FunctionExpression *node = makeAstNode<AST::FunctionExpression> (driver->nodePool(), sym(2).sval, sym(4).FormalParameterList, sym(7).FunctionBody);
node->functionToken = loc(1);
if (sym(2).sval)
@@ -1720,60 +1718,60 @@ case 329: {
sym(1).Node = node;
} break;
-case 330: {
+case 328: {
AST::FormalParameterList *node = makeAstNode<AST::FormalParameterList> (driver->nodePool(), sym(1).sval);
node->identifierToken = loc(1);
sym(1).Node = node;
} break;
-case 331: {
+case 329: {
AST::FormalParameterList *node = makeAstNode<AST::FormalParameterList> (driver->nodePool(), sym(1).FormalParameterList, sym(3).sval);
node->commaToken = loc(2);
node->identifierToken = loc(3);
sym(1).Node = node;
} break;
-case 332: {
+case 330: {
sym(1).Node = 0;
} break;
-case 333: {
+case 331: {
sym(1).Node = sym(1).FormalParameterList->finish ();
} break;
-case 334: {
+case 332: {
sym(1).Node = 0;
} break;
-case 336: {
+case 334: {
sym(1).Node = makeAstNode<AST::FunctionBody> (driver->nodePool(), sym(1).SourceElements->finish ());
} break;
-case 337: {
+case 335: {
sym(1).Node = makeAstNode<AST::Program> (driver->nodePool(), sym(1).SourceElements->finish ());
} break;
-case 338: {
+case 336: {
sym(1).Node = makeAstNode<AST::SourceElements> (driver->nodePool(), sym(1).SourceElement);
} break;
-case 339: {
+case 337: {
sym(1).Node = makeAstNode<AST::SourceElements> (driver->nodePool(), sym(1).SourceElements, sym(2).SourceElement);
} break;
-case 340: {
+case 338: {
sym(1).Node = makeAstNode<AST::StatementSourceElement> (driver->nodePool(), sym(1).Statement);
} break;
-case 341: {
+case 339: {
sym(1).Node = makeAstNode<AST::FunctionSourceElement> (driver->nodePool(), sym(1).FunctionDeclaration);
} break;
-case 342: {
+case 340: {
sym(1).sval = 0;
} break;
-case 344: {
+case 342: {
sym(1).Node = 0;
} break;
diff --git a/src/declarative/qml/parser/qdeclarativejsparser_p.h b/src/declarative/qml/parser/qdeclarativejsparser_p.h
index 70611aa110..0cbd76adfc 100644
--- a/src/declarative/qml/parser/qdeclarativejsparser_p.h
+++ b/src/declarative/qml/parser/qdeclarativejsparser_p.h
@@ -59,10 +59,10 @@
#ifndef QDECLARATIVEJSPARSER_P_H
#define QDECLARATIVEJSPARSER_P_H
-#include "private/qdeclarativejsglobal_p.h"
-#include "private/qdeclarativejsgrammar_p.h"
-#include "private/qdeclarativejsast_p.h"
-#include "private/qdeclarativejsengine_p.h"
+#include "qdeclarativejsglobal_p.h"
+#include "qdeclarativejsgrammar_p.h"
+#include "qdeclarativejsast_p.h"
+#include "qdeclarativejsengine_p.h"
#include <QtCore/QList>
#include <QtCore/QString>
@@ -235,9 +235,9 @@ protected:
-#define J_SCRIPT_REGEXPLITERAL_RULE1 78
+#define J_SCRIPT_REGEXPLITERAL_RULE1 76
-#define J_SCRIPT_REGEXPLITERAL_RULE2 79
+#define J_SCRIPT_REGEXPLITERAL_RULE2 77
QT_QML_END_NAMESPACE
diff --git a/src/declarative/qml/qdeclarative.h b/src/declarative/qml/qdeclarative.h
index 399c20709b..da9fc76f4a 100644
--- a/src/declarative/qml/qdeclarative.h
+++ b/src/declarative/qml/qdeclarative.h
@@ -53,6 +53,9 @@
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(QDeclarativeListProperty<TYPE>)
@@ -392,6 +395,8 @@ int qmlRegisterCustomType(const char *uri, int versionMajor, int versionMinor,
class QDeclarativeContext;
class QDeclarativeEngine;
+class QScriptValue;
+class QScriptEngine;
Q_DECLARATIVE_EXPORT void qmlExecuteDeferred(QObject *);
Q_DECLARATIVE_EXPORT QDeclarativeContext *qmlContext(const QObject *);
Q_DECLARATIVE_EXPORT QDeclarativeEngine *qmlEngine(const QObject *);
@@ -405,6 +410,143 @@ QObject *qmlAttachedPropertiesObject(const QObject *obj, bool create = true)
return qmlAttachedPropertiesObject(&idx, obj, &T::staticMetaObject, create);
}
+/*!
+ This function may be used to register a module API provider \a callback in a particular \a uri
+ with a version specified in \a versionMajor and \a versionMinor.
+
+ Installing a module API into a uri allows developers to provide arbitrary functionality
+ (methods and properties) in a namespace that doesn't necessarily contain elements.
+
+ A module API may be either a QObject or a QScriptValue. Only one module API provider
+ may be registered into any given namespace (combination of \a uri, \a majorVersion and \a minorVersion).
+ This function should be used to register a module API provider function which returns a QScriptValue as a module API.
+
+ Usage:
+ \code
+ // first, define the module API provider function (callback).
+ static QScriptValue *example_qscriptvalue_module_api_provider(QDeclarativeEngine *engine, QScriptEngine *scriptEngine)
+ {
+ Q_UNUSED(engine)
+
+ static int seedValue = 5;
+ QScriptValue example = scriptEngine->newObject();
+ example.setProperty("someProperty", seedValue++);
+ return example;
+ }
+
+ // second, register the module API provider with QML by calling this function in an initialization function.
+ ...
+ qmlRegisterModuleApi("Qt.example.qscriptvalueApi", 1, 0, example_qscriptvalue_module_api_provider);
+ ...
+ \endcode
+
+ In order to use the registered module API in QML, you must import the module API.
+ \qml
+ import QtQuick 2.0
+ import Qt.example.qscriptvalueApi 1.0 as ExampleApi
+ Item {
+ id: root
+ property int someValue: ExampleApi.someProperty
+ }
+ \endqml
+ */
+inline int qmlRegisterModuleApi(const char *uri, int versionMajor, int versionMinor,
+ QScriptValue (*callback)(QDeclarativeEngine *, QScriptEngine *))
+{
+ QDeclarativePrivate::RegisterModuleApi api = {
+ 0,
+
+ uri, versionMajor, versionMinor,
+
+ callback, 0
+ };
+
+ return QDeclarativePrivate::qmlregister(QDeclarativePrivate::ModuleApiRegistration, &api);
+}
+
+/*!
+ This function may be used to register a module API provider \a callback in a particular \a uri
+ with a version specified in \a versionMajor and \a versionMinor.
+
+ Installing a module API into a uri allows developers to provide arbitrary functionality
+ (methods and properties) in a namespace that doesn't necessarily contain elements.
+
+ A module API may be either a QObject or a QScriptValue. Only one module API provider
+ may be registered into any given namespace (combination of \a uri, \a majorVersion and \a minorVersion).
+ This function should be used to register a module API provider function which returns a QObject as a module API.
+
+ Usage:
+ \code
+ // first, define your QObject which provides the functionality.
+ class ModuleApiExample : public QObject
+ {
+ Q_OBJECT
+ Q_PROPERTY (int someProperty READ someProperty WRITE setSomeProperty NOTIFY somePropertyChanged)
+
+ public:
+ ModuleApiExample(QObject* parent = 0)
+ : QObject(parent), m_someProperty(0)
+ {
+ }
+
+ ~ModuleApiExample() {}
+
+ Q_INVOKABLE int doSomething() { setSomeProperty(5); return m_someProperty; }
+
+ int someProperty() const { return m_someProperty; }
+ void setSomeProperty(int val) { m_someProperty = val; emit somePropertyChanged(val); }
+
+ signals:
+ void somePropertyChanged(int newValue);
+
+ private:
+ int m_someProperty;
+ };
+
+ // second, define the module API provider function (callback).
+ static QObject *example_qobject_module_api_provider(QDeclarativeEngine *engine, QScriptEngine *scriptEngine)
+ {
+ Q_UNUSED(engine)
+ Q_UNUSED(scriptEngine)
+
+ ModuleApiExample *example = new ModuleApiExample();
+ return example;
+ }
+
+ // third, register the module API provider with QML by calling this function in an initialization function.
+ ...
+ qmlRegisterModuleApi("Qt.example.qobjectApi", 1, 0, example_qobject_module_api_provider);
+ ...
+ \endcode
+
+ In order to use the registered module API in QML, you must import the module API.
+ \qml
+ import QtQuick 2.0
+ import Qt.example.qobjectApi 1.0 as ExampleApi
+ Item {
+ id: root
+ property int someValue: ExampleApi.someProperty
+
+ Component.onCompleted: {
+ someValue = ExampleApi.doSomething()
+ }
+ }
+ \endqml
+ */
+inline int qmlRegisterModuleApi(const char *uri, int versionMajor, int versionMinor,
+ QObject *(*callback)(QDeclarativeEngine *, QScriptEngine *))
+{
+ QDeclarativePrivate::RegisterModuleApi api = {
+ 0,
+
+ uri, versionMajor, versionMinor,
+
+ 0, callback
+ };
+
+ return QDeclarativePrivate::qmlregister(QDeclarativePrivate::ModuleApiRegistration, &api);
+}
+
QT_END_NAMESPACE
QML_DECLARE_TYPE(QObject)
diff --git a/src/declarative/qml/qdeclarativebinding.cpp b/src/declarative/qml/qdeclarativebinding.cpp
index ca3bc37ab4..6c46de69e4 100644
--- a/src/declarative/qml/qdeclarativebinding.cpp
+++ b/src/declarative/qml/qdeclarativebinding.cpp
@@ -357,13 +357,17 @@ void QDeclarativeBinding::update(QDeclarativePropertyPrivate::WriteFlags flags)
} else {
QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(d->context()->engine);
+ ep->referenceScarceResources(); // "hold" scarce resources in memory during evaluation.
bool isUndefined = false;
QVariant value;
QScriptValue scriptValue = d->scriptValue(0, &isUndefined);
- if (wasDeleted)
+
+ if (wasDeleted) {
+ ep->dereferenceScarceResources(); // "release" scarce resources if top-level expression evaluation is complete.
return;
+ }
if (d->property.propertyTypeCategory() == QDeclarativeProperty::List) {
value = ep->scriptValueToVariant(scriptValue, qMetaTypeId<QList<QObject *> >());
@@ -420,8 +424,10 @@ void QDeclarativeBinding::update(QDeclarativePropertyPrivate::WriteFlags flags)
} else if (d->property.object() &&
!QDeclarativePropertyPrivate::write(d->property, value, flags)) {
- if (wasDeleted)
+ if (wasDeleted) {
+ ep->dereferenceScarceResources(); // "release" scarce resources if top-level expression evaluation is complete.
return;
+ }
QUrl url = QUrl(d->url);
int line = d->line;
@@ -440,14 +446,21 @@ void QDeclarativeBinding::update(QDeclarativePropertyPrivate::WriteFlags flags)
QLatin1String(QMetaType::typeName(d->property.propertyType())));
}
- if (wasDeleted)
+ if (wasDeleted) {
+ ep->dereferenceScarceResources(); // "release" scarce resources if top-level expression evaluation is complete.
return;
+ }
if (d->error.isValid()) {
if (!d->addError(ep)) ep->warning(this->error());
} else {
d->removeError();
}
+
+ // at this point, the binding has been evaluated. If any scarce
+ // resources were copied during the evaluation of the binding,
+ // we need to release those copies.
+ ep->dereferenceScarceResources(); // "release" scarce resources if top-level expression evaluation is complete.
}
d->updating = false;
diff --git a/src/declarative/qml/qdeclarativecompiledbindings.cpp b/src/declarative/qml/qdeclarativecompiledbindings.cpp
deleted file mode 100644
index 313fe5896c..0000000000
--- a/src/declarative/qml/qdeclarativecompiledbindings.cpp
+++ /dev/null
@@ -1,2906 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
-** All rights reserved.
-** Contact: Nokia Corporation (qt-info@nokia.com)
-**
-** This file is part of the QtDeclarative 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 COMPILEDBINDINGS_DEBUG
-// #define REGISTER_CLEANUP_DEBUG
-
-#include "private/qdeclarativecompiledbindings_p.h"
-
-#include <QtDeclarative/qdeclarativeinfo.h>
-#include <private/qdeclarativecontext_p.h>
-#include <private/qdeclarativejsast_p.h>
-#include <private/qdeclarativejsengine_p.h>
-#include <private/qdeclarativeexpression_p.h>
-#include <QtCore/qcoreapplication.h>
-#include <QtCore/qdebug.h>
-#include <QtCore/qnumeric.h>
-#include <private/qdeclarativeanchors_p_p.h>
-#include <private/qdeclarativeglobal_p.h>
-#include <private/qdeclarativefastproperties_p.h>
-#include <private/qdeclarativedebugtrace_p.h>
-
-QT_BEGIN_NAMESPACE
-
-DEFINE_BOOL_CONFIG_OPTION(qmlExperimental, QML_EXPERIMENTAL);
-DEFINE_BOOL_CONFIG_OPTION(qmlDisableOptimizer, QML_DISABLE_OPTIMIZER);
-DEFINE_BOOL_CONFIG_OPTION(qmlDisableFastProperties, QML_DISABLE_FAST_PROPERTIES);
-DEFINE_BOOL_CONFIG_OPTION(bindingsDump, QML_BINDINGS_DUMP);
-
-Q_GLOBAL_STATIC(QDeclarativeFastProperties, fastProperties);
-
-#if defined(Q_CC_GNU) && (!defined(Q_CC_INTEL) || __INTEL_COMPILER >= 1200)
-# define QML_THREADED_INTERPRETER
-#endif
-
-#define FOR_EACH_QML_INSTR(F) \
- F(Noop) /* Nop */ \
- F(BindingId) /* id */ \
- F(Subscribe) /* subscribe */ \
- F(SubscribeId) /* subscribe */ \
- F(FetchAndSubscribe) /* fetchAndSubscribe */ \
- F(LoadId) /* load */ \
- F(LoadScope) /* load */ \
- F(LoadRoot) /* load */ \
- F(LoadAttached) /* attached */ \
- F(ConvertIntToReal) /* unaryop */ \
- F(ConvertRealToInt) /* unaryop */ \
- F(Real) /* real_value */ \
- F(Int) /* int_value */ \
- F(Bool) /* bool_value */ \
- F(String) /* string_value */ \
- F(AddReal) /* binaryop */ \
- F(AddInt) /* binaryop */ \
- F(AddString) /* binaryop */ \
- F(MinusReal) /* binaryop */ \
- F(MinusInt) /* binaryop */ \
- F(CompareReal) /* binaryop */ \
- F(CompareString) /* binaryop */ \
- F(NotCompareReal) /* binaryop */ \
- F(NotCompareString) /* binaryop */ \
- F(GreaterThanReal) /* binaryop */ \
- F(MaxReal) /* binaryop */ \
- F(MinReal) /* binaryop */ \
- F(NewString) /* construct */ \
- F(NewUrl) /* construct */ \
- F(CleanupUrl) /* cleanup */ \
- F(CleanupString) /* cleanup */ \
- F(Copy) /* copy */ \
- F(Fetch) /* fetch */ \
- F(Store) /* store */ \
- F(Skip) /* skip */ \
- F(Done) /* done */ \
- /* Speculative property resolution */ \
- F(InitString) /* initstring */ \
- F(FindGeneric) /* find */ \
- F(FindGenericTerminal) /* find */ \
- F(FindProperty) /* find */ \
- F(FindPropertyTerminal) /* find */ \
- F(CleanupGeneric) /* cleanup */ \
- F(ConvertGenericToReal) /* unaryop */ \
- F(ConvertGenericToBool) /* unaryop */ \
- F(ConvertGenericToString) /* unaryop */ \
- F(ConvertGenericToUrl) /* unaryop */
-
-#define QML_INSTR_ENUM(I) I,
-#define QML_INSTR_ADDR(I) &&op_##I,
-
-#ifdef QML_THREADED_INTERPRETER
-# define QML_BEGIN_INSTR(I) op_##I:
-# define QML_END_INSTR(I) ++instr; goto *instr->common.code;
-# define QML_INSTR_HEADER void *code;
-#else
-# define QML_BEGIN_INSTR(I) case Instr::I:
-# define QML_END_INSTR(I) break;
-# define QML_INSTR_HEADER
-#endif
-
-
-using namespace QDeclarativeJS;
-
-namespace {
-// Supported types: int, qreal, QString (needs constr/destr), QObject*, bool
-struct Register {
- void setUndefined() { type = 0; }
- void setUnknownButDefined() { type = -1; }
- void setNaN() { setqreal(qSNaN()); }
- bool isUndefined() const { return type == 0; }
-
- void setQObject(QObject *o) { *((QObject **)data) = o; type = QMetaType::QObjectStar; }
- QObject *getQObject() const { return *((QObject **)data); }
-
- void setqreal(qreal v) { *((qreal *)data) = v; type = QMetaType::QReal; }
- qreal getqreal() const { return *((qreal *)data); }
-
- void setint(int v) { *((int *)data) = v; type = QMetaType::Int; }
- int getint() const { return *((int *)data); }
-
- void setbool(bool v) { *((bool *)data) = v; type = QMetaType::Bool; }
- bool getbool() const { return *((bool *)data); }
-
- 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; }
-
- int gettype() const { return type; }
- void settype(int t) { type = t; }
-
- int type; // Optional type
- void *data[2]; // Object stored here
-
-#ifdef REGISTER_CLEANUP_DEBUG
- Register() {
- type = 0;
- }
-
- ~Register() {
- int allowedTypes[] = { QMetaType::QObjectStar, QMetaType::QReal, QMetaType::Int, QMetaType::Bool, 0 };
- bool found = (type == 0);
- int *ctype = allowedTypes;
- while (!found && *ctype) {
- found = (*ctype == type);
- ++ctype;
- }
- if (!found)
- qWarning("Register leaked of type %d", type);
- }
-#endif
-};
-}
-
-class QDeclarativeCompiledBindingsPrivate : public QObjectPrivate
-{
- Q_DECLARE_PUBLIC(QDeclarativeCompiledBindings)
-
-public:
- QDeclarativeCompiledBindingsPrivate();
- virtual ~QDeclarativeCompiledBindingsPrivate();
-
- struct Binding : public QDeclarativeAbstractBinding, public QDeclarativeDelayedError {
- Binding() : enabled(false), updating(0), property(0),
- scope(0), target(0), parent(0) {}
-
- // Inherited from QDeclarativeAbstractBinding
- virtual void setEnabled(bool, QDeclarativePropertyPrivate::WriteFlags flags);
- virtual void update(QDeclarativePropertyPrivate::WriteFlags flags);
- virtual void destroy();
-
- int index:30;
- bool enabled:1;
- bool updating:1;
- int property;
- QObject *scope;
- QObject *target;
-
- QDeclarativeCompiledBindingsPrivate *parent;
- };
-
- typedef QDeclarativeNotifierEndpoint Subscription;
- Subscription *subscriptions;
- QScriptDeclarativeClass::PersistentIdentifier *identifiers;
-
- void run(Binding *, QDeclarativePropertyPrivate::WriteFlags flags);
-
- const char *programData;
- Binding *m_bindings;
- quint32 *m_signalTable;
-
- static int methodCount;
-
- void init();
- void run(int instr, QDeclarativeContextData *context,
- QDeclarativeDelayedError *error, QObject *scope, QObject *output, QDeclarativePropertyPrivate::WriteFlags storeFlags);
-
-
- inline void unsubscribe(int subIndex);
- inline void subscribeId(QDeclarativeContextData *p, int idIndex, int subIndex);
- inline void subscribe(QObject *o, int notifyIndex, int subIndex);
-
- QDeclarativePropertyCache::Data *findproperty(QObject *obj,
- const QScriptDeclarativeClass::Identifier &name,
- QDeclarativeEnginePrivate *enginePriv,
- QDeclarativePropertyCache::Data &local);
- bool findproperty(QObject *obj,
- Register *output,
- QDeclarativeEnginePrivate *enginePriv,
- int subIdx,
- const QScriptDeclarativeClass::Identifier &name,
- bool isTerminal);
- void findgeneric(Register *output, // value output
- int subIdx, // Subscription index in config
- QDeclarativeContextData *context, // Context to search in
- const QScriptDeclarativeClass::Identifier &name,
- bool isTerminal);
-};
-
-QDeclarativeCompiledBindingsPrivate::QDeclarativeCompiledBindingsPrivate()
-: subscriptions(0), identifiers(0)
-{
-}
-
-QDeclarativeCompiledBindingsPrivate::~QDeclarativeCompiledBindingsPrivate()
-{
- delete [] subscriptions; subscriptions = 0;
- delete [] identifiers; identifiers = 0;
-}
-
-int QDeclarativeCompiledBindingsPrivate::methodCount = -1;
-
-QDeclarativeCompiledBindings::QDeclarativeCompiledBindings(const char *program, QDeclarativeContextData *context)
-: QObject(*(new QDeclarativeCompiledBindingsPrivate))
-{
- Q_D(QDeclarativeCompiledBindings);
-
- if (d->methodCount == -1)
- d->methodCount = QDeclarativeCompiledBindings::staticMetaObject.methodCount();
-
- d->programData = program;
-
- d->init();
-
- QDeclarativeAbstractExpression::setContext(context);
-}
-
-QDeclarativeCompiledBindings::~QDeclarativeCompiledBindings()
-{
- Q_D(QDeclarativeCompiledBindings);
-
- delete [] d->m_bindings;
-}
-
-QDeclarativeAbstractBinding *QDeclarativeCompiledBindings::configBinding(int index, QObject *target,
- QObject *scope, int property)
-{
- Q_D(QDeclarativeCompiledBindings);
-
- QDeclarativeCompiledBindingsPrivate::Binding *rv = d->m_bindings + index;
-
- rv->index = index;
- rv->property = property;
- rv->target = target;
- rv->scope = scope;
- rv->parent = d;
-
- addref(); // This is decremented in Binding::destroy()
-
- return rv;
-}
-
-void QDeclarativeCompiledBindingsPrivate::Binding::setEnabled(bool e, QDeclarativePropertyPrivate::WriteFlags flags)
-{
- if (enabled != e) {
- enabled = e;
-
- if (e) update(flags);
- }
-}
-
-void QDeclarativeCompiledBindingsPrivate::Binding::update(QDeclarativePropertyPrivate::WriteFlags flags)
-{
- QDeclarativeDebugTrace::startRange(QDeclarativeDebugTrace::Binding);
- parent->run(this, flags);
- QDeclarativeDebugTrace::endRange(QDeclarativeDebugTrace::Binding);
-}
-
-void QDeclarativeCompiledBindingsPrivate::Binding::destroy()
-{
- enabled = false;
- removeFromObject();
- clear();
- parent->q_func()->release();
-}
-
-int QDeclarativeCompiledBindings::qt_metacall(QMetaObject::Call c, int id, void **)
-{
- Q_D(QDeclarativeCompiledBindings);
-
- if (c == QMetaObject::InvokeMetaMethod && id >= d->methodCount) {
- id -= d->methodCount;
-
- quint32 *reeval = d->m_signalTable + d->m_signalTable[id];
- quint32 count = *reeval;
- ++reeval;
- for (quint32 ii = 0; ii < count; ++ii) {
- d->run(d->m_bindings + reeval[ii], QDeclarativePropertyPrivate::DontRemoveBinding);
- }
- }
- return -1;
-}
-
-void QDeclarativeCompiledBindingsPrivate::run(Binding *binding, QDeclarativePropertyPrivate::WriteFlags flags)
-{
- Q_Q(QDeclarativeCompiledBindings);
-
- if (!binding->enabled)
- return;
-
- QDeclarativeContextData *context = q->QDeclarativeAbstractExpression::context();
- if (!context || !context->isValid())
- return;
-
- if (binding->updating) {
- QString name;
- if (binding->property & 0xFFFF0000) {
- QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(context->engine);
-
- QDeclarativeValueType *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) << QCoreApplication::translate("QDeclarativeCompiledBindings", "Binding loop detected for property \"%1\"").arg(name);
- return;
- }
-
- binding->updating = true;
- if (binding->property & 0xFFFF0000) {
- QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(context->engine);
-
- QDeclarativeValueType *vt = ep->valueTypes[(binding->property >> 16) & 0xFF];
- Q_ASSERT(vt);
- vt->read(binding->target, binding->property & 0xFFFF);
-
- QObject *target = vt;
- run(binding->index, context, binding, binding->scope, target, flags);
-
- vt->write(binding->target, binding->property & 0xFFFF, flags);
- } else {
- run(binding->index, context, binding, binding->scope, binding->target, flags);
- }
- binding->updating = false;
-}
-
-namespace {
-// This structure is exactly 8-bytes in size
-struct Instr {
- enum {
- FOR_EACH_QML_INSTR(QML_INSTR_ENUM)
- };
-
- union {
- struct {
- QML_INSTR_HEADER
- quint8 type;
- quint8 packing[7];
- } common;
- struct {
- QML_INSTR_HEADER
- quint8 type;
- quint8 packing;
- quint16 column;
- quint32 line;
- } id;
- struct {
- QML_INSTR_HEADER
- quint8 type;
- quint8 packing[3];
- quint16 subscriptions;
- quint16 identifiers;
- } init;
- struct {
- QML_INSTR_HEADER
- quint8 type;
- qint8 reg;
- quint16 offset;
- quint32 index;
- } subscribe;
- struct {
- QML_INSTR_HEADER
- quint8 type;
- qint8 reg;
- quint8 packing[2];
- quint32 index;
- } load;
- struct {
- QML_INSTR_HEADER
- quint8 type;
- qint8 output;
- qint8 reg;
- quint8 exceptionId;
- quint32 id;
- } attached;
- struct {
- QML_INSTR_HEADER
- quint8 type;
- qint8 output;
- qint8 reg;
- quint8 exceptionId;
- quint32 index;
- } store;
- struct {
- QML_INSTR_HEADER
- quint8 type;
- qint8 output;
- qint8 objectReg;
- quint8 exceptionId;
- quint16 subscription;
- quint16 function;
- } fetchAndSubscribe;
- struct {
- QML_INSTR_HEADER
- quint8 type;
- qint8 output;
- qint8 objectReg;
- quint8 exceptionId;
- quint32 index;
- } fetch;
- struct {
- QML_INSTR_HEADER
- quint8 type;
- qint8 reg;
- qint8 src;
- quint8 packing[5];
- } copy;
- struct {
- QML_INSTR_HEADER
- quint8 type;
- qint8 reg;
- quint8 packing[6];
- } construct;
- struct {
- QML_INSTR_HEADER
- quint8 type;
- qint8 reg;
- quint8 packing[2];
- float value;
- } real_value;
- struct {
- QML_INSTR_HEADER
- quint8 type;
- qint8 reg;
- quint8 packing[2];
- int value;
- } int_value;
- struct {
- QML_INSTR_HEADER
- quint8 type;
- qint8 reg;
- bool value;
- quint8 packing[5];
- } bool_value;
- struct {
- QML_INSTR_HEADER
- quint8 type;
- qint8 reg;
- quint16 length;
- quint32 offset;
- } string_value;
- struct {
- QML_INSTR_HEADER
- quint8 type;
- qint8 output;
- qint8 src1;
- qint8 src2;
- quint8 packing[4];
- } binaryop;
- struct {
- QML_INSTR_HEADER
- quint8 type;
- qint8 output;
- qint8 src;
- quint8 packing[5];
- } unaryop;
- struct {
- QML_INSTR_HEADER
- quint8 type;
- qint8 reg;
- quint8 packing[2];
- quint32 count;
- } skip;
- struct {
- QML_INSTR_HEADER
- quint8 type;
- qint8 reg;
- qint8 src;
- quint8 exceptionId;
- quint16 name;
- quint16 subscribeIndex;
- } find;
- struct {
- QML_INSTR_HEADER
- quint8 type;
- qint8 reg;
- quint8 packing[6];
- } cleanup;
- struct {
- QML_INSTR_HEADER
- quint8 type;
- quint8 packing[1];
- quint16 offset;
- quint32 dataIdx;
- } initstring;
- };
-};
-
-struct Program {
- quint32 bindings;
- quint32 dataLength;
- quint32 signalTableOffset;
- quint32 exceptionDataOffset;
- quint16 subscriptions;
- quint16 identifiers;
- quint16 instructionCount;
- quint16 compiled;
-
- const char *data() const { return ((const char *)this) + sizeof(Program); }
- const Instr *instructions() const { return (const Instr *)(data() + dataLength); }
-};
-}
-
-struct QDeclarativeBindingCompilerPrivate
-{
- struct Result {
- Result() : unknownType(false), metaObject(0), type(-1), reg(-1) {}
- bool operator==(const Result &o) const {
- return unknownType == o.unknownType &&
- metaObject == o.metaObject &&
- type == o.type &&
- reg == o.reg;
- }
- bool operator!=(const Result &o) const {
- return !(*this == o);
- }
- bool unknownType;
- const QMetaObject *metaObject;
- int type;
- int reg;
-
- QSet<QString> subscriptionSet;
- };
-
- QDeclarativeBindingCompilerPrivate() : registers(0) {}
-
- void resetInstanceState();
- int commitCompile();
-
- QDeclarativeParser::Object *context;
- QDeclarativeParser::Object *component;
- QDeclarativeParser::Property *destination;
- QHash<QString, QDeclarativeParser::Object *> ids;
- QDeclarativeImports imports;
- QDeclarativeEnginePrivate *engine;
-
- QString contextName() const { return QLatin1String("$$$SCOPE_") + QString::number((quintptr)context, 16); }
-
- bool compile(QDeclarativeJS::AST::Node *);
-
- bool parseExpression(QDeclarativeJS::AST::Node *, Result &);
-
- bool tryName(QDeclarativeJS::AST::Node *);
- bool parseName(QDeclarativeJS::AST::Node *, Result &);
-
- bool tryArith(QDeclarativeJS::AST::Node *);
- bool parseArith(QDeclarativeJS::AST::Node *, Result &);
- bool numberArith(Result &, const Result &, const Result &, QSOperator::Op op);
- bool stringArith(Result &, const Result &, const Result &, QSOperator::Op op);
-
- bool tryLogic(QDeclarativeJS::AST::Node *);
- bool parseLogic(QDeclarativeJS::AST::Node *, Result &);
-
- bool tryConditional(QDeclarativeJS::AST::Node *);
- bool parseConditional(QDeclarativeJS::AST::Node *, Result &);
-
- bool tryConstant(QDeclarativeJS::AST::Node *);
- bool parseConstant(QDeclarativeJS::AST::Node *, Result &);
-
- bool tryMethod(QDeclarativeJS::AST::Node *);
- bool parseMethod(QDeclarativeJS::AST::Node *, Result &);
-
- bool buildName(QStringList &, QDeclarativeJS::AST::Node *, QList<QDeclarativeJS::AST::ExpressionNode *> *nodes = 0);
- bool fetch(Result &type, const QMetaObject *, int reg, int idx, const QStringList &, QDeclarativeJS::AST::ExpressionNode *);
-
- quint32 registers;
- QHash<int, QPair<int, int> > registerCleanups;
- int acquireReg(int cleanup = Instr::Noop, int cleanupType = 0);
- void registerCleanup(int reg, int cleanup, int cleanupType = 0);
- void releaseReg(int);
-
- int registerLiteralString(const QString &);
- int registerString(const QString &);
- QHash<QString, QPair<int, int> > registeredStrings;
- QByteArray data;
-
- bool subscription(const QStringList &, Result *);
- int subscriptionIndex(const QStringList &);
- bool subscriptionNeutral(const QSet<QString> &base, const QSet<QString> &lhs, const QSet<QString> &rhs);
-
- quint8 exceptionId(QDeclarativeJS::AST::ExpressionNode *);
- QVector<quint64> exceptions;
-
- QSet<int> usedSubscriptionIds;
- QSet<QString> subscriptionSet;
- QHash<QString, int> subscriptionIds;
- QVector<Instr> bytecode;
-
- // Committed binding data
- struct {
- QList<int> offsets;
- QList<QSet<int> > dependencies;
-
- QVector<Instr> bytecode;
- QByteArray data;
- QHash<QString, int> subscriptionIds;
- QVector<quint64> exceptions;
-
- QHash<QString, QPair<int, int> > registeredStrings;
-
- int count() const { return offsets.count(); }
- } committed;
-
- QByteArray buildSignalTable() const;
- QByteArray buildExceptionData() const;
-};
-
-void QDeclarativeCompiledBindingsPrivate::unsubscribe(int subIndex)
-{
- QDeclarativeCompiledBindingsPrivate::Subscription *sub = (subscriptions + subIndex);
- sub->disconnect();
-}
-
-void QDeclarativeCompiledBindingsPrivate::subscribeId(QDeclarativeContextData *p, int idIndex, int subIndex)
-{
- Q_Q(QDeclarativeCompiledBindings);
-
- unsubscribe(subIndex);
-
- if (p->idValues[idIndex]) {
- QDeclarativeCompiledBindingsPrivate::Subscription *sub = (subscriptions + subIndex);
- sub->target = q;
- sub->targetMethod = methodCount + subIndex;
- sub->connect(&p->idValues[idIndex].bindings);
- }
-}
-
-void QDeclarativeCompiledBindingsPrivate::subscribe(QObject *o, int notifyIndex, int subIndex)
-{
- Q_Q(QDeclarativeCompiledBindings);
-
- QDeclarativeCompiledBindingsPrivate::Subscription *sub = (subscriptions + subIndex);
- sub->target = q;
- sub->targetMethod = methodCount + 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, QDeclarativeContextData *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) {
- base = QUrl(QString::fromUtf8(var->toByteArray()));
- } else if (vt == QVariant::String) {
- base = QUrl(var->toString());
- } else {
- if (ok) *ok = false;
- return QUrl();
- }
- } else if (type == QMetaType::QString) {
- base = QUrl(*reg->getstringptr());
- } else {
- if (ok) *ok = false;
- return QUrl();
- }
-
- if (!base.isEmpty() && base.isRelative())
- return context->url.resolved(base);
- else
- return base;
-}
-
-static QObject *variantToQObject(const QVariant &value, bool *ok)
-{
- if (ok) *ok = true;
-
- if (value.userType() == QMetaType::QObjectStar) {
- return qvariant_cast<QObject*>(value);
- } else {
- if (ok) *ok = false;
- return 0;
- }
-}
-
-bool QDeclarativeCompiledBindingsPrivate::findproperty(QObject *obj, Register *output,
- QDeclarativeEnginePrivate *enginePriv,
- int subIdx, const QScriptDeclarativeClass::Identifier &name,
- bool isTerminal)
-{
- if (!obj) {
- output->setUndefined();
- return false;
- }
-
- QDeclarativePropertyCache::Data local;
- QDeclarativePropertyCache::Data *property =
- QDeclarativePropertyCache::property(QDeclarativeEnginePrivate::get(enginePriv), obj, name, local);
-
- if (property) {
- if (subIdx != -1)
- subscribe(obj, property->notifyIndex, subIdx);
-
- if (property->flags & QDeclarativePropertyCache::Data::IsQObjectDerived) {
- void *args[] = { output->typeDataPtr(), 0 };
- QMetaObject::metacall(obj, QMetaObject::ReadProperty, property->coreIndex, args);
- output->settype(QMetaType::QObjectStar);
- } else if (property->propType == qMetaTypeId<QVariant>()) {
- QVariant v;
- void *args[] = { &v, 0 };
- QMetaObject::metacall(obj, QMetaObject::ReadProperty, property->coreIndex, args);
-
- if (isTerminal) {
- new (output->typeDataPtr()) QVariant(v);
- output->settype(qMetaTypeId<QVariant>());
- } else {
- bool ok;
- output->setQObject(variantToQObject(v, &ok));
- if (!ok)
- output->setUndefined();
- else
- output->settype(QMetaType::QObjectStar);
- }
-
- } else {
- if (!isTerminal) {
- output->setUndefined();
- } else if (property->propType == QMetaType::QReal) {
- void *args[] = { output->typeDataPtr(), 0 };
- QMetaObject::metacall(obj, QMetaObject::ReadProperty, property->coreIndex, args);
- output->settype(QMetaType::QReal);
- } else if (property->propType == QMetaType::Int) {
- void *args[] = { output->typeDataPtr(), 0 };
- QMetaObject::metacall(obj, QMetaObject::ReadProperty, property->coreIndex, args);
- output->settype(QMetaType::Int);
- } else if (property->propType == QMetaType::Bool) {
- void *args[] = { output->typeDataPtr(), 0 };
- QMetaObject::metacall(obj, QMetaObject::ReadProperty, property->coreIndex, args);
- output->settype(QMetaType::Bool);
- } else if (property->propType == QMetaType::QString) {
- new (output->typeDataPtr()) QString();
- void *args[] = { output->typeDataPtr(), 0 };
- QMetaObject::metacall(obj, QMetaObject::ReadProperty, property->coreIndex, args);
- output->settype(QMetaType::QString);
- } else {
- new (output->typeDataPtr())
- QVariant(obj->metaObject()->property(property->coreIndex).read(obj));
- output->settype(qMetaTypeId<QVariant>());
- }
- }
-
- return true;
- } else {
- output->setUndefined();
- return false;
- }
-}
-
-void QDeclarativeCompiledBindingsPrivate::findgeneric(Register *output,
- int subIdx,
- QDeclarativeContextData *context,
- const QScriptDeclarativeClass::Identifier &name,
- bool isTerminal)
-{
- QDeclarativeEnginePrivate *enginePriv = QDeclarativeEnginePrivate::get(context->engine);
-
- while (context) {
-
- int contextPropertyIndex = context->propertyNames?context->propertyNames->value(name):-1;
-
-
- if (contextPropertyIndex != -1) {
-
- if (contextPropertyIndex < context->idValueCount) {
- output->setQObject(context->idValues[contextPropertyIndex]);
- output->settype(QMetaType::QObjectStar);
-
- if (subIdx != -1)
- subscribeId(context, contextPropertyIndex, subIdx);
-
- } else {
- QDeclarativeContextPrivate *cp = context->asQDeclarativeContextPrivate();
- const QVariant &value = cp->propertyValues.at(contextPropertyIndex);
-
- if (isTerminal) {
- new (output->typeDataPtr()) QVariant(value);
- output->settype(qMetaTypeId<QVariant>());
- } else {
- bool ok;
- output->setQObject(variantToQObject(value, &ok));
- if (!ok) { output->setUndefined(); }
- else { output->settype(QMetaType::QObjectStar); }
- return;
- }
-
- if (subIdx != -1)
- subscribe(context->asQDeclarativeContext(), contextPropertyIndex + cp->notifyIndex, subIdx);
-
-
- }
-
- return;
- }
-
- if (QObject *root = context->contextObject) {
-
- if (findproperty(root, output, enginePriv, subIdx, name, isTerminal))
- return;
-
- }
-
- context = context->parent;
- }
-
- output->setUndefined();
-}
-
-void QDeclarativeCompiledBindingsPrivate::init()
-{
- Program *program = (Program *)programData;
- if (program->subscriptions)
- subscriptions = new QDeclarativeCompiledBindingsPrivate::Subscription[program->subscriptions];
- if (program->identifiers)
- identifiers = new QScriptDeclarativeClass::PersistentIdentifier[program->identifiers];
-
- m_signalTable = (quint32 *)(program->data() + program->signalTableOffset);
- m_bindings = new QDeclarativeCompiledBindingsPrivate::Binding[program->bindings];
-}
-
-static void throwException(int id, QDeclarativeDelayedError *error,
- Program *program, QDeclarativeContextData *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(QDeclarativeEnginePrivate::get(context->engine)))
- QDeclarativeEnginePrivate::warning(context->engine, error->error);
-}
-
-static void dumpInstruction(const Instr *instr)
-{
- switch (instr->common.type) {
- case Instr::Noop:
- qWarning().nospace() << "\t" << "Noop";
- break;
- case Instr::BindingId:
- qWarning().nospace() << instr->id.line << ":" << instr->id.column << ":";
- break;
- case Instr::Subscribe:
- qWarning().nospace() << "\t" << "Subscribe" << "\t\t" << instr->subscribe.offset << "\t" << instr->subscribe.reg << "\t" << instr->subscribe.index;
- break;
- case Instr::SubscribeId:
- qWarning().nospace() << "\t" << "SubscribeId" << "\t\t" << instr->subscribe.offset << "\t" << instr->subscribe.reg << "\t" << instr->subscribe.index;
- break;
- case Instr::FetchAndSubscribe:
- qWarning().nospace() << "\t" << "FetchAndSubscribe" << "\t" << instr->fetchAndSubscribe.output << "\t" << instr->fetchAndSubscribe.objectReg << "\t" << instr->fetchAndSubscribe.subscription;
- break;
- case Instr::LoadId:
- qWarning().nospace() << "\t" << "LoadId" << "\t\t\t" << instr->load.index << "\t" << instr->load.reg;
- break;
- case Instr::LoadScope:
- qWarning().nospace() << "\t" << "LoadScope" << "\t\t" << instr->load.index << "\t" << instr->load.reg;
- break;
- case Instr::LoadRoot:
- qWarning().nospace() << "\t" << "LoadRoot" << "\t\t" << instr->load.index << "\t" << instr->load.reg;
- break;
- case Instr::LoadAttached:
- qWarning().nospace() << "\t" << "LoadAttached" << "\t\t" << instr->attached.output << "\t" << instr->attached.reg << "\t" << instr->attached.id;
- break;
- case Instr::ConvertIntToReal:
- qWarning().nospace() << "\t" << "ConvertIntToReal" << "\t" << instr->unaryop.output << "\t" << instr->unaryop.src;
- break;
- case Instr::ConvertRealToInt:
- qWarning().nospace() << "\t" << "ConvertRealToInt" << "\t" << instr->unaryop.output << "\t" << instr->unaryop.src;
- break;
- case Instr::Real:
- qWarning().nospace() << "\t" << "Real" << "\t\t\t" << instr->real_value.reg << "\t" << instr->real_value.value;
- break;
- case Instr::Int:
- qWarning().nospace() << "\t" << "Int" << "\t\t\t" << instr->int_value.reg << "\t" << instr->int_value.value;
- break;
- case Instr::Bool:
- qWarning().nospace() << "\t" << "Bool" << "\t\t\t" << instr->bool_value.reg << "\t" << instr->bool_value.value;
- break;
- case Instr::String:
- qWarning().nospace() << "\t" << "String" << "\t\t\t" << instr->string_value.reg << "\t" << instr->string_value.offset << "\t" << instr->string_value.length;
- break;
- case Instr::AddReal:
- qWarning().nospace() << "\t" << "AddReal" << "\t\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2;
- break;
- case Instr::AddInt:
- qWarning().nospace() << "\t" << "AddInt" << "\t\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2;
- break;
- case Instr::AddString:
- qWarning().nospace() << "\t" << "AddString" << "\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2;
- break;
- case Instr::MinusReal:
- qWarning().nospace() << "\t" << "MinusReal" << "\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2;
- break;
- case Instr::MinusInt:
- qWarning().nospace() << "\t" << "MinusInt" << "\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2;
- break;
- case Instr::CompareReal:
- qWarning().nospace() << "\t" << "CompareReal" << "\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2;
- break;
- case Instr::CompareString:
- qWarning().nospace() << "\t" << "CompareString" << "\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2;
- break;
- case Instr::NotCompareReal:
- qWarning().nospace() << "\t" << "NotCompareReal" << "\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2;
- break;
- case Instr::NotCompareString:
- qWarning().nospace() << "\t" << "NotCompareString" << "\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2;
- break;
- case Instr::GreaterThanReal:
- qWarning().nospace() << "\t" << "GreaterThanReal" << "\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2;
- break;
- case Instr::MaxReal:
- qWarning().nospace() << "\t" << "MaxReal" << "\t\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2;
- break;
- case Instr::MinReal:
- qWarning().nospace() << "\t" << "MinReal" << "\t\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2;
- break;
- case Instr::NewString:
- qWarning().nospace() << "\t" << "NewString" << "\t\t" << instr->construct.reg;
- break;
- case Instr::NewUrl:
- qWarning().nospace() << "\t" << "NewUrl" << "\t\t\t" << instr->construct.reg;
- break;
- case Instr::CleanupString:
- qWarning().nospace() << "\t" << "CleanupString" << "\t\t" << instr->cleanup.reg;
- break;
- case Instr::CleanupUrl:
- qWarning().nospace() << "\t" << "CleanupUrl" << "\t\t" << instr->cleanup.reg;
- break;
- case Instr::Fetch:
- qWarning().nospace() << "\t" << "Fetch" << "\t\t\t" << instr->fetch.output << "\t" << instr->fetch.index << "\t" << instr->fetch.objectReg;
- break;
- case Instr::Store:
- qWarning().nospace() << "\t" << "Store" << "\t\t\t" << instr->store.output << "\t" << instr->store.index << "\t" << instr->store.reg;
- break;
- case Instr::Copy:
- qWarning().nospace() << "\t" << "Copy" << "\t\t\t" << instr->copy.reg << "\t" << instr->copy.src;
- break;
- case Instr::Skip:
- qWarning().nospace() << "\t" << "Skip" << "\t\t\t" << instr->skip.reg << "\t" << instr->skip.count;
- break;
- case Instr::Done:
- qWarning().nospace() << "\t" << "Done";
- break;
- case Instr::InitString:
- qWarning().nospace() << "\t" << "InitString" << "\t\t" << instr->initstring.offset << "\t" << instr->initstring.dataIdx;
- break;
- case Instr::FindGeneric:
- qWarning().nospace() << "\t" << "FindGeneric" << "\t\t" << instr->find.reg << "\t" << instr->find.name;
- break;
- case Instr::FindGenericTerminal:
- qWarning().nospace() << "\t" << "FindGenericTerminal" << "\t" << instr->find.reg << "\t" << instr->find.name;
- break;
- case Instr::FindProperty:
- qWarning().nospace() << "\t" << "FindProperty" << "\t\t" << instr->find.reg << "\t" << instr->find.src << "\t" << instr->find.name;
- break;
- case Instr::FindPropertyTerminal:
- qWarning().nospace() << "\t" << "FindPropertyTerminal" << "\t" << instr->find.reg << "\t" << instr->find.src << "\t" << instr->find.name;
- break;
- case Instr::CleanupGeneric:
- qWarning().nospace() << "\t" << "CleanupGeneric" << "\t\t" << instr->cleanup.reg;
- break;
- case Instr::ConvertGenericToReal:
- qWarning().nospace() << "\t" << "ConvertGenericToReal" << "\t" << instr->unaryop.output << "\t" << instr->unaryop.src;
- break;
- case Instr::ConvertGenericToBool:
- qWarning().nospace() << "\t" << "ConvertGenericToBool" << "\t" << instr->unaryop.output << "\t" << instr->unaryop.src;
- break;
- case Instr::ConvertGenericToString:
- qWarning().nospace() << "\t" << "ConvertGenericToString" << "\t" << instr->unaryop.output << "\t" << instr->unaryop.src;
- break;
- case Instr::ConvertGenericToUrl:
- qWarning().nospace() << "\t" << "ConvertGenericToUrl" << "\t" << instr->unaryop.output << "\t" << instr->unaryop.src;
- break;
- default:
- qWarning().nospace() << "\t" << "Unknown";
- break;
- }
-}
-
-void QDeclarativeCompiledBindingsPrivate::run(int instrIndex,
- QDeclarativeContextData *context, QDeclarativeDelayedError *error,
- QObject *scope, QObject *output, QDeclarativePropertyPrivate::WriteFlags storeFlags)
-{
- Q_Q(QDeclarativeCompiledBindings);
-
- error->removeError();
-
- Register registers[32];
-
- QDeclarativeEnginePrivate *engine = QDeclarativeEnginePrivate::get(context->engine);
- Program *program = (Program *)programData;
- const Instr *instr = program->instructions();
- instr += instrIndex;
- const char *data = program->data();
-
-#ifdef QML_THREADED_INTERPRETER
- static void *decode_instr[] = {
- FOR_EACH_QML_INSTR(QML_INSTR_ADDR)
- };
-
- if (!program->compiled) {
- program->compiled = true;
- const Instr *inop = program->instructions();
- for (int i = 0; i < program->instructionCount; ++i) {
- Instr *op = (Instr *) inop++;
- op->common.code = decode_instr[op->common.type];
- }
- }
-
- goto *instr->common.code;
-#else
- // return;
-
-#ifdef COMPILEDBINDINGS_DEBUG
- qWarning().nospace() << "Begin binding run";
-#endif
-
- while (instr) {
- switch (instr->common.type) {
-
-#ifdef COMPILEDBINDINGS_DEBUG
- dumpInstruction(instr);
-#endif
-
-#endif
-
- QML_BEGIN_INSTR(Noop)
- QML_END_INSTR(Noop)
-
- QML_BEGIN_INSTR(BindingId)
- QML_END_INSTR(BindingId)
-
- QML_BEGIN_INSTR(SubscribeId)
- subscribeId(context, instr->subscribe.index, instr->subscribe.offset);
- QML_END_INSTR(SubscribeId)
-
- QML_BEGIN_INSTR(Subscribe)
- {
- QObject *o = 0;
- const Register &object = registers[instr->subscribe.reg];
- if (!object.isUndefined()) o = object.getQObject();
- subscribe(o, instr->subscribe.index, instr->subscribe.offset);
- }
- QML_END_INSTR(Subscribe)
-
- QML_BEGIN_INSTR(FetchAndSubscribe)
- {
- const Register &input = registers[instr->fetchAndSubscribe.objectReg];
- Register &output = registers[instr->fetchAndSubscribe.output];
-
- if (input.isUndefined()) {
- throwException(instr->fetchAndSubscribe.exceptionId, error, program, context);
- return;
- }
-
- QObject *object = input.getQObject();
- if (!object) {
- output.setUndefined();
- } else {
- int subIdx = instr->fetchAndSubscribe.subscription;
- QDeclarativeCompiledBindingsPrivate::Subscription *sub = 0;
- if (subIdx != -1) {
- sub = (subscriptions + subIdx);
- sub->target = q;
- sub->targetMethod = methodCount + subIdx;
- }
- fastProperties()->accessor(instr->fetchAndSubscribe.function)(object, output.typeDataPtr(), sub);
- }
- }
- QML_END_INSTR(FetchAndSubscribe)
-
- QML_BEGIN_INSTR(LoadId)
- registers[instr->load.reg].setQObject(context->idValues[instr->load.index].data());
- QML_END_INSTR(LoadId)
-
- QML_BEGIN_INSTR(LoadScope)
- registers[instr->load.reg].setQObject(scope);
- QML_END_INSTR(LoadScope)
-
- QML_BEGIN_INSTR(LoadRoot)
- registers[instr->load.reg].setQObject(context->contextObject);
- QML_END_INSTR(LoadRoot)
-
- QML_BEGIN_INSTR(LoadAttached)
- {
- const Register &input = registers[instr->attached.reg];
- Register &output = registers[instr->attached.output];
- if (input.isUndefined()) {
- throwException(instr->attached.exceptionId, error, program, context);
- return;
- }
-
- QObject *object = registers[instr->attached.reg].getQObject();
- if (!object) {
- output.setUndefined();
- } else {
- QObject *attached =
- qmlAttachedPropertiesObjectById(instr->attached.id,
- registers[instr->attached.reg].getQObject(),
- true);
- Q_ASSERT(attached);
- output.setQObject(attached);
- }
- }
- QML_END_INSTR(LoadAttached)
-
- QML_BEGIN_INSTR(ConvertIntToReal)
- {
- const Register &input = registers[instr->unaryop.src];
- Register &output = registers[instr->unaryop.output];
- if (input.isUndefined()) output.setUndefined();
- else output.setqreal(qreal(input.getint()));
- }
- QML_END_INSTR(ConvertIntToReal)
-
- QML_BEGIN_INSTR(ConvertRealToInt)
- {
- const Register &input = registers[instr->unaryop.src];
- Register &output = registers[instr->unaryop.output];
- if (input.isUndefined()) output.setUndefined();
- else output.setint(qRound(input.getqreal()));
- }
- QML_END_INSTR(ConvertRealToInt)
-
- QML_BEGIN_INSTR(Real)
- registers[instr->real_value.reg].setqreal(instr->real_value.value);
- QML_END_INSTR(Real)
-
- QML_BEGIN_INSTR(Int)
- registers[instr->int_value.reg].setint(instr->int_value.value);
- QML_END_INSTR(Int)
-
- QML_BEGIN_INSTR(Bool)
- registers[instr->bool_value.reg].setbool(instr->bool_value.value);
- QML_END_INSTR(Bool)
-
- QML_BEGIN_INSTR(String)
- {
- Register &output = registers[instr->string_value.reg];
- new (output.getstringptr())
- QString((QChar *)(data + instr->string_value.offset), instr->string_value.length);
- output.settype(QMetaType::QString);
- }
- QML_END_INSTR(String)
-
- QML_BEGIN_INSTR(AddReal)
- {
- const Register &lhs = registers[instr->binaryop.src1];
- const Register &rhs = registers[instr->binaryop.src2];
- Register &output = registers[instr->binaryop.output];
- if (lhs.isUndefined() || rhs.isUndefined()) output.setNaN();
- else output.setqreal(lhs.getqreal() + rhs.getqreal());
- }
- QML_END_INSTR(AddReal)
-
- QML_BEGIN_INSTR(AddInt)
- {
- const Register &lhs = registers[instr->binaryop.src1];
- const Register &rhs = registers[instr->binaryop.src2];
- Register &output = registers[instr->binaryop.output];
- if (lhs.isUndefined() || rhs.isUndefined()) output.setNaN();
- else output.setint(lhs.getint() + rhs.getint());
- }
- QML_END_INSTR(AddInt)
-
- QML_BEGIN_INSTR(AddString)
- {
- const Register &lhs = registers[instr->binaryop.src1];
- const Register &rhs = registers[instr->binaryop.src2];
- Register &output = registers[instr->binaryop.output];
- if (lhs.isUndefined() && rhs.isUndefined()) { output.setNaN(); }
- else {
- if (lhs.isUndefined())
- new (output.getstringptr())
- QString(QLatin1String("undefined") + *registers[instr->binaryop.src2].getstringptr());
- else if (rhs.isUndefined())
- new (output.getstringptr())
- QString(*registers[instr->binaryop.src1].getstringptr() + QLatin1String("undefined"));
- else
- new (output.getstringptr())
- QString(*registers[instr->binaryop.src1].getstringptr() +
- *registers[instr->binaryop.src2].getstringptr());
- output.settype(QMetaType::QString);
- }
- }
- QML_END_INSTR(AddString)
-
- QML_BEGIN_INSTR(MinusReal)
- {
- const Register &lhs = registers[instr->binaryop.src1];
- const Register &rhs = registers[instr->binaryop.src2];
- Register &output = registers[instr->binaryop.output];
- if (lhs.isUndefined() || rhs.isUndefined()) output.setNaN();
- else output.setqreal(lhs.getqreal() - rhs.getqreal());
- }
- QML_END_INSTR(MinusReal)
-
- QML_BEGIN_INSTR(MinusInt)
- {
- const Register &lhs = registers[instr->binaryop.src1];
- const Register &rhs = registers[instr->binaryop.src2];
- Register &output = registers[instr->binaryop.output];
- if (lhs.isUndefined() || rhs.isUndefined()) output.setNaN();
- else output.setint(lhs.getint() - rhs.getint());
- }
- QML_END_INSTR(MinusInt)
-
- QML_BEGIN_INSTR(CompareReal)
- {
- const Register &lhs = registers[instr->binaryop.src1];
- const Register &rhs = registers[instr->binaryop.src2];
- Register &output = registers[instr->binaryop.output];
- if (lhs.isUndefined() || rhs.isUndefined()) output.setbool(lhs.isUndefined() == rhs.isUndefined());
- else output.setbool(lhs.getqreal() == rhs.getqreal());
- }
- QML_END_INSTR(CompareReal)
-
- QML_BEGIN_INSTR(CompareString)
- {
- const Register &lhs = registers[instr->binaryop.src1];
- const Register &rhs = registers[instr->binaryop.src2];
- Register &output = registers[instr->binaryop.output];
- if (lhs.isUndefined() || rhs.isUndefined()) output.setbool(lhs.isUndefined() == rhs.isUndefined());
- else output.setbool(*lhs.getstringptr() == *rhs.getstringptr());
- }
- QML_END_INSTR(CompareString)
-
- QML_BEGIN_INSTR(NotCompareReal)
- {
- const Register &lhs = registers[instr->binaryop.src1];
- const Register &rhs = registers[instr->binaryop.src2];
- Register &output = registers[instr->binaryop.output];
- if (lhs.isUndefined() || rhs.isUndefined()) output.setbool(lhs.isUndefined() != rhs.isUndefined());
- else output.setbool(lhs.getqreal() != rhs.getqreal());
- }
- QML_END_INSTR(NotCompareReal)
-
- QML_BEGIN_INSTR(NotCompareString)
- {
- const Register &lhs = registers[instr->binaryop.src1];
- const Register &rhs = registers[instr->binaryop.src2];
- Register &output = registers[instr->binaryop.output];
- if (lhs.isUndefined() || rhs.isUndefined()) output.setbool(lhs.isUndefined() != rhs.isUndefined());
- else output.setbool(*lhs.getstringptr() != *rhs.getstringptr());
- }
- QML_END_INSTR(NotCompareString)
-
- QML_BEGIN_INSTR(GreaterThanReal)
- {
- const Register &lhs = registers[instr->binaryop.src1];
- const Register &rhs = registers[instr->binaryop.src2];
- Register &output = registers[instr->binaryop.output];
- if (lhs.isUndefined() || rhs.isUndefined()) output.setbool(false);
- else output.setbool(lhs.getqreal() > rhs.getqreal());
- }
- QML_END_INSTR(GreaterThanReal)
-
- QML_BEGIN_INSTR(MaxReal)
- {
- const Register &lhs = registers[instr->binaryop.src1];
- const Register &rhs = registers[instr->binaryop.src2];
- Register &output = registers[instr->binaryop.output];
- if (lhs.isUndefined() || rhs.isUndefined()) output.setNaN();
- else output.setqreal(qMax(lhs.getqreal(), rhs.getqreal()));
- }
- QML_END_INSTR(MaxReal)
-
- QML_BEGIN_INSTR(MinReal)
- {
- const Register &lhs = registers[instr->binaryop.src1];
- const Register &rhs = registers[instr->binaryop.src2];
- Register &output = registers[instr->binaryop.output];
- if (lhs.isUndefined() || rhs.isUndefined()) output.setNaN();
- else output.setqreal(qMin(lhs.getqreal(), rhs.getqreal()));
- }
- QML_END_INSTR(MinReal)
-
- QML_BEGIN_INSTR(NewString)
- {
- Register &output = registers[instr->construct.reg];
- new (output.getstringptr()) QString;
- output.settype(QMetaType::QString);
- }
- QML_END_INSTR(NewString)
-
- QML_BEGIN_INSTR(NewUrl)
- {
- Register &output = registers[instr->construct.reg];
- new (output.geturlptr()) QUrl;
- output.settype(QMetaType::QUrl);
- }
- QML_END_INSTR(NewUrl)
-
- QML_BEGIN_INSTR(CleanupString)
- registers[instr->cleanup.reg].getstringptr()->~QString();
-#ifdef REGISTER_CLEANUP_DEBUG
- registers[instr->cleanup.reg].setUndefined();
-#endif
- QML_END_INSTR(CleanupString)
-
- QML_BEGIN_INSTR(CleanupUrl)
- registers[instr->cleanup.reg].geturlptr()->~QUrl();
-#ifdef REGISTER_CLEANUP_DEBUG
- registers[instr->cleanup.reg].setUndefined();
-#endif
- QML_END_INSTR(CleanupUrl)
-
- QML_BEGIN_INSTR(Fetch)
- {
- const Register &input = registers[instr->fetch.objectReg];
- Register &output = registers[instr->fetch.output];
-
- if (input.isUndefined()) {
- throwException(instr->fetch.exceptionId, error, program, context);
- return;
- }
-
- QObject *object = input.getQObject();
- if (!object) {
- output.setUndefined();
- } else {
- void *argv[] = { output.typeDataPtr(), 0 };
- QMetaObject::metacall(object, QMetaObject::ReadProperty, instr->fetch.index, argv);
- }
- }
- QML_END_INSTR(Fetch)
-
- QML_BEGIN_INSTR(Store)
- {
- Register &data = registers[instr->store.reg];
- if (data.isUndefined()) {
- throwException(instr->store.exceptionId, error, program, context,
- QLatin1String("Unable to assign undefined value"));
- return;
- }
-
- int status = -1;
- void *argv[] = { data.typeDataPtr(), 0, &status, &storeFlags };
- QMetaObject::metacall(output, QMetaObject::WriteProperty,
- instr->store.index, argv);
- }
- QML_END_INSTR(Store)
-
- QML_BEGIN_INSTR(Copy)
- registers[instr->copy.reg] = registers[instr->copy.src];
- QML_END_INSTR(Copy)
-
- QML_BEGIN_INSTR(Skip)
- if (instr->skip.reg == -1 || !registers[instr->skip.reg].getbool())
- instr += instr->skip.count;
- QML_END_INSTR(Skip)
-
- QML_BEGIN_INSTR(Done)
- return;
- QML_END_INSTR(Done)
-
- QML_BEGIN_INSTR(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_END_INSTR(InitString)
-
- QML_BEGIN_INSTR(FindGenericTerminal)
- // We start the search in the parent context, as we know that the
- // name is not present in the current context or it would have been
- // found during the static compile
- findgeneric(registers + instr->find.reg, instr->find.subscribeIndex,
- context->parent,
- identifiers[instr->find.name].identifier,
- instr->common.type == Instr::FindGenericTerminal);
- QML_END_INSTR(FindGenericTerminal)
-
- QML_BEGIN_INSTR(FindGeneric)
- // We start the search in the parent context, as we know that the
- // name is not present in the current context or it would have been
- // found during the static compile
- findgeneric(registers + instr->find.reg, instr->find.subscribeIndex,
- context->parent,
- identifiers[instr->find.name].identifier,
- instr->common.type == Instr::FindGenericTerminal);
- QML_END_INSTR(FindGeneric)
-
- QML_BEGIN_INSTR(FindPropertyTerminal)
- {
- const Register &object = registers[instr->find.src];
- if (object.isUndefined()) {
- throwException(instr->find.exceptionId, error, program, context);
- return;
- }
-
- findproperty(object.getQObject(), registers + instr->find.reg,
- QDeclarativeEnginePrivate::get(context->engine),
- instr->find.subscribeIndex, identifiers[instr->find.name].identifier,
- instr->common.type == Instr::FindPropertyTerminal);
- }
- QML_END_INSTR(FindPropertyTerminal)
-
- QML_BEGIN_INSTR(FindProperty)
- {
- const Register &object = registers[instr->find.src];
- if (object.isUndefined()) {
- throwException(instr->find.exceptionId, error, program, context);
- return;
- }
-
- findproperty(object.getQObject(), registers + instr->find.reg,
- QDeclarativeEnginePrivate::get(context->engine),
- instr->find.subscribeIndex, identifiers[instr->find.name].identifier,
- instr->common.type == Instr::FindPropertyTerminal);
- }
- QML_END_INSTR(FindProperty)
-
- QML_BEGIN_INSTR(CleanupGeneric)
- {
- int type = registers[instr->cleanup.reg].gettype();
- if (type == qMetaTypeId<QVariant>()) {
- registers[instr->cleanup.reg].getvariantptr()->~QVariant();
-#ifdef REGISTER_CLEANUP_DEBUG
- registers[instr->cleanup.reg].setUndefined();
-#endif
- } else if (type == QMetaType::QString) {
- registers[instr->cleanup.reg].getstringptr()->~QString();
-#ifdef REGISTER_CLEANUP_DEBUG
- registers[instr->cleanup.reg].setUndefined();
-#endif
- } else if (type == QMetaType::QUrl) {
- registers[instr->cleanup.reg].geturlptr()->~QUrl();
-#ifdef REGISTER_CLEANUP_DEBUG
- registers[instr->cleanup.reg].setUndefined();
-#endif
- }
- }
- QML_END_INSTR(CleanupGeneric)
-
- QML_BEGIN_INSTR(ConvertGenericToReal)
- {
- Register &output = registers[instr->unaryop.output];
- Register &input = registers[instr->unaryop.src];
- bool ok = true;
- output.setqreal(toReal(&input, input.gettype(), &ok));
- if (!ok) output.setUndefined();
- }
- QML_END_INSTR(ConvertGenericToReal)
-
- QML_BEGIN_INSTR(ConvertGenericToBool)
- {
- Register &output = registers[instr->unaryop.output];
- Register &input = registers[instr->unaryop.src];
- bool ok = true;
- output.setbool(toBool(&input, input.gettype(), &ok));
- if (!ok) output.setUndefined();
- }
- QML_END_INSTR(ConvertGenericToBool)
-
- QML_BEGIN_INSTR(ConvertGenericToString)
- {
- Register &output = registers[instr->unaryop.output];
- Register &input = registers[instr->unaryop.src];
- bool ok = true;
- QString str = toString(&input, input.gettype(), &ok);
- if (ok) { new (output.getstringptr()) QString(str); output.settype(QMetaType::QString); }
- else { output.setUndefined(); }
- }
- QML_END_INSTR(ConvertGenericToString)
-
- QML_BEGIN_INSTR(ConvertGenericToUrl)
- {
- Register &output = registers[instr->unaryop.output];
- Register &input = registers[instr->unaryop.src];
- bool ok = true;
- QUrl url = toUrl(&input, input.gettype(), context, &ok);
- if (ok) { new (output.geturlptr()) QUrl(url); output.settype(QMetaType::QUrl); }
- else { output.setUndefined(); }
- }
- QML_END_INSTR(ConvertGenericToUrl)
-
-#ifdef QML_THREADED_INTERPRETER
- // nothing to do
-#else
- default:
- qFatal("EEK");
- break;
- } // switch
-
- ++instr;
- } // while
-#endif
-}
-
-void QDeclarativeBindingCompiler::dump(const QByteArray &programData)
-{
- const Program *program = (const Program *)programData.constData();
-
- qWarning() << "Program.bindings:" << program->bindings;
- qWarning() << "Program.dataLength:" << program->dataLength;
- qWarning() << "Program.subscriptions:" << program->subscriptions;
- qWarning() << "Program.indentifiers:" << program->identifiers;
-
- int count = program->instructionCount;
- const Instr *instr = program->instructions();
-
- while (count--) {
-
- dumpInstruction(instr);
- ++instr;
- }
-}
-
-/*!
-Clear the state associated with attempting to compile a specific binding.
-This does not clear the global "committed binding" states.
-*/
-void QDeclarativeBindingCompilerPrivate::resetInstanceState()
-{
- registers = 0;
- registerCleanups.clear();
- data = committed.data;
- exceptions = committed.exceptions;
- usedSubscriptionIds.clear();
- subscriptionSet.clear();
- subscriptionIds = committed.subscriptionIds;
- registeredStrings = committed.registeredStrings;
- bytecode.clear();
-}
-
-/*!
-Mark the last compile as successful, and add it to the "committed data"
-section.
-
-Returns the index for the committed binding.
-*/
-int QDeclarativeBindingCompilerPrivate::commitCompile()
-{
- int rv = committed.count();
- committed.offsets << committed.bytecode.count();
- committed.dependencies << usedSubscriptionIds;
- committed.bytecode << bytecode;
- committed.data = data;
- committed.exceptions = exceptions;
- committed.subscriptionIds = subscriptionIds;
- committed.registeredStrings = registeredStrings;
- return rv;
-}
-
-bool QDeclarativeBindingCompilerPrivate::compile(QDeclarativeJS::AST::Node *node)
-{
- resetInstanceState();
-
- if (destination->type == -1)
- return false;
-
- if (bindingsDump()) {
- QDeclarativeJS::AST::ExpressionNode *n = node->expressionCast();
- if (n) {
- Instr id;
- id.common.type = Instr::BindingId;
- id.id.column = n->firstSourceLocation().startColumn;
- id.id.line = n->firstSourceLocation().startLine;
- bytecode << id;
- }
- }
-
- Result type;
-
- if (!parseExpression(node, type))
- return false;
-
- if (subscriptionSet.count() > 0xFFFF ||
- registeredStrings.count() > 0xFFFF)
- return false;
-
- if (type.unknownType) {
- if (!qmlExperimental())
- return false;
-
- if (destination->type != QMetaType::QReal &&
- destination->type != QVariant::String &&
- destination->type != QMetaType::Bool &&
- destination->type != QVariant::Url)
- return false;
-
- int convertReg = acquireReg();
- if (convertReg == -1)
- return false;
-
- if (destination->type == QMetaType::QReal) {
- Instr convert;
- convert.common.type = Instr::ConvertGenericToReal;
- convert.unaryop.output = convertReg;
- convert.unaryop.src = type.reg;
- bytecode << convert;
- } else if (destination->type == QVariant::String) {
- Instr convert;
- convert.common.type = Instr::ConvertGenericToString;
- convert.unaryop.output = convertReg;
- convert.unaryop.src = type.reg;
- bytecode << convert;
- } else if (destination->type == QMetaType::Bool) {
- Instr convert;
- convert.common.type = Instr::ConvertGenericToBool;
- convert.unaryop.output = convertReg;
- convert.unaryop.src = type.reg;
- bytecode << convert;
- } else if (destination->type == QVariant::Url) {
- Instr convert;
- convert.common.type = Instr::ConvertGenericToUrl;
- convert.unaryop.output = convertReg;
- convert.unaryop.src = type.reg;
- bytecode << convert;
- }
-
- Instr cleanup;
- cleanup.common.type = Instr::CleanupGeneric;
- cleanup.cleanup.reg = type.reg;
- bytecode << cleanup;
-
- Instr instr;
- instr.common.type = Instr::Store;
- instr.store.output = 0;
- instr.store.index = destination->index;
- instr.store.reg = convertReg;
- instr.store.exceptionId = exceptionId(node->expressionCast());
- bytecode << instr;
-
- if (destination->type == QVariant::String) {
- Instr cleanup;
- cleanup.common.type = Instr::CleanupString;
- cleanup.cleanup.reg = convertReg;
- bytecode << cleanup;
- } else if (destination->type == QVariant::Url) {
- Instr cleanup;
- cleanup.common.type = Instr::CleanupUrl;
- cleanup.cleanup.reg = convertReg;
- bytecode << cleanup;
- }
-
- releaseReg(convertReg);
-
- Instr done;
- done.common.type = Instr::Done;
- bytecode << done;
-
- } else {
- // Can we store the final value?
- if (type.type == QVariant::Int &&
- destination->type == QMetaType::QReal) {
- Instr instr;
- instr.common.type = Instr::ConvertIntToReal;
- instr.unaryop.output = type.reg;
- instr.unaryop.src = type.reg;
- bytecode << instr;
- type.type = QMetaType::QReal;
- } else if (type.type == QMetaType::QReal &&
- destination->type == QVariant::Int) {
- Instr instr;
- instr.common.type = Instr::ConvertRealToInt;
- instr.unaryop.output = type.reg;
- instr.unaryop.src = type.reg;
- bytecode << instr;
- type.type = QVariant::Int;
- } else if (type.type == destination->type) {
- } else {
- const QMetaObject *from = type.metaObject;
- const QMetaObject *to = engine->rawMetaObjectForType(destination->type);
-
- if (QDeclarativePropertyPrivate::canConvert(from, to))
- type.type = destination->type;
- }
-
- if (type.type == destination->type) {
- Instr instr;
- instr.common.type = Instr::Store;
- instr.store.output = 0;
- instr.store.index = destination->index;
- instr.store.reg = type.reg;
- instr.store.exceptionId = exceptionId(node->expressionCast());
- bytecode << instr;
-
- releaseReg(type.reg);
-
- Instr done;
- done.common.type = Instr::Done;
- bytecode << done;
- } else {
- return false;
- }
- }
-
- return true;
-}
-
-bool QDeclarativeBindingCompilerPrivate::parseExpression(QDeclarativeJS::AST::Node *node, Result &type)
-{
- while (node->kind == AST::Node::Kind_NestedExpression)
- node = static_cast<AST::NestedExpression *>(node)->expression;
-
- if (tryArith(node)) {
- if (!parseArith(node, type)) return false;
- } else if (tryLogic(node)) {
- if (!parseLogic(node, type)) return false;
- } else if (tryConditional(node)) {
- if (!parseConditional(node, type)) return false;
- } else if (tryName(node)) {
- if (!parseName(node, type)) return false;
- } else if (tryConstant(node)) {
- if (!parseConstant(node, type)) return false;
- } else if (tryMethod(node)) {
- if (!parseMethod(node, type)) return false;
- } else {
- return false;
- }
- return true;
-}
-
-bool QDeclarativeBindingCompilerPrivate::tryName(QDeclarativeJS::AST::Node *node)
-{
- return node->kind == AST::Node::Kind_IdentifierExpression ||
- node->kind == AST::Node::Kind_FieldMemberExpression;
-}
-
-bool QDeclarativeBindingCompilerPrivate::parseName(AST::Node *node, Result &type)
-{
- QStringList nameParts;
- QList<AST::ExpressionNode *> nameNodes;
- if (!buildName(nameParts, node, &nameNodes))
- return false;
-
- int reg = acquireReg();
- if (reg == -1)
- return false;
- type.reg = reg;
-
- QDeclarativeParser::Object *absType = 0;
-
- QStringList subscribeName;
-
- bool wasAttachedObject = false;
-
- for (int ii = 0; ii < nameParts.count(); ++ii) {
- const QString &name = nameParts.at(ii);
-
- // We don't handle signal properties or attached properties
- if (name.length() > 2 && name.startsWith(QLatin1String("on")) &&
- name.at(2).isUpper())
- return false;
-
- QDeclarativeType *attachType = 0;
- if (name.at(0).isUpper()) {
- // Could be an attached property
- if (ii == nameParts.count() - 1)
- return false;
- if (nameParts.at(ii + 1).at(0).isUpper())
- return false;
-
- QDeclarativeImportedNamespace *ns = 0;
- if (!imports.resolveType(name.toUtf8(), &attachType, 0, 0, 0, &ns))
- return false;
- if (ns || !attachType || !attachType->attachedPropertiesType())
- return false;
-
- wasAttachedObject = true;
- }
-
- if (ii == 0) {
-
- if (attachType) {
- Instr instr;
- instr.common.type = Instr::LoadScope;
- instr.load.index = 0;
- instr.load.reg = reg;
- bytecode << instr;
-
- Instr attach;
- attach.common.type = Instr::LoadAttached;
- attach.attached.output = reg;
- attach.attached.reg = reg;
- attach.attached.id = attachType->attachedPropertiesId();
- attach.attached.exceptionId = exceptionId(nameNodes.at(ii));
- bytecode << attach;
-
- subscribeName << contextName();
- subscribeName << QLatin1String("$$$ATTACH_") + name;
-
- absType = 0;
- type.metaObject = attachType->attachedPropertiesType();
-
- continue;
- } else if (ids.contains(name)) {
- QDeclarativeParser::Object *idObject = ids.value(name);
- absType = idObject;
- type.metaObject = absType->metaObject();
-
- // We check if the id object is the root or
- // scope object to avoid a subscription
- if (idObject == component) {
- Instr instr;
- instr.common.type = Instr::LoadRoot;
- instr.load.index = 0;
- instr.load.reg = reg;
- bytecode << instr;
- } else if (idObject == context) {
- Instr instr;
- instr.common.type = Instr::LoadScope;
- instr.load.index = 0;
- instr.load.reg = reg;
- bytecode << instr;
- } else {
- Instr instr;
- instr.common.type = Instr::LoadId;
- instr.load.index = idObject->idIndex;
- instr.load.reg = reg;
- bytecode << instr;
-
- subscribeName << QLatin1String("$$$ID_") + name;
-
- if (subscription(subscribeName, &type)) {
- Instr sub;
- sub.common.type = Instr::SubscribeId;
- sub.subscribe.offset = subscriptionIndex(subscribeName);
- sub.subscribe.reg = reg;
- sub.subscribe.index = instr.load.index;
- bytecode << sub;
- }
- }
-
- } else {
-
- QByteArray utf8Name = name.toUtf8();
- const char *cname = utf8Name.constData();
-
- int d0Idx = (context == component)?-1:context->metaObject()->indexOfProperty(cname);
- int d1Idx = -1;
- if (d0Idx == -1)
- d1Idx = component->metaObject()->indexOfProperty(cname);
-
- if (d0Idx != -1) {
- Instr instr;
- instr.common.type = Instr::LoadScope;
- instr.load.index = 0;
- instr.load.reg = reg;
- bytecode << instr;
-
- subscribeName << contextName();
- subscribeName << name;
-
- if (!fetch(type, context->metaObject(), reg, d0Idx, subscribeName, nameNodes.at(ii)))
- return false;
- } else if(d1Idx != -1) {
- Instr instr;
- instr.common.type = Instr::LoadRoot;
- instr.load.index = 0;
- instr.load.reg = reg;
- bytecode << instr;
-
- subscribeName << QLatin1String("$$$ROOT");
- subscribeName << name;
-
- if (!fetch(type, component->metaObject(), reg, d1Idx, subscribeName, nameNodes.at(ii)))
- return false;
- } else if (qmlExperimental()) {
- Instr find;
- if (nameParts.count() == 1)
- find.common.type = Instr::FindGenericTerminal;
- else
- find.common.type = Instr::FindGeneric;
-
- find.find.reg = reg;
- find.find.src = -1;
- find.find.name = registerString(name);
- find.find.exceptionId = exceptionId(nameNodes.at(ii));
-
- subscribeName << QString(QLatin1String("$$$Generic_") + name);
- if (subscription(subscribeName, &type))
- find.find.subscribeIndex = subscriptionIndex(subscribeName);
- else
- find.find.subscribeIndex = -1;
-
- bytecode << find;
- type.unknownType = true;
- }
-
- if (!type.unknownType && type.type == -1)
- return false; // Couldn't fetch that type
- }
-
- } else {
-
- if (attachType) {
- Instr attach;
- attach.common.type = Instr::LoadAttached;
- attach.attached.output = reg;
- attach.attached.reg = reg;
- attach.attached.id = attachType->attachedPropertiesId();
- bytecode << attach;
-
- absType = 0;
- type.metaObject = attachType->attachedPropertiesType();
-
- subscribeName << QLatin1String("$$$ATTACH_") + name;
- continue;
- }
-
- const QMetaObject *mo = 0;
- if (absType)
- mo = absType->metaObject();
- else if (type.metaObject)
- mo = type.metaObject;
-
- QByteArray utf8Name = name.toUtf8();
- const char *cname = utf8Name.constData();
- int idx = mo?mo->indexOfProperty(cname):-1;
- if (absType && idx == -1)
- return false;
-
- subscribeName << name;
-
- if (absType || (wasAttachedObject && idx != -1) || (mo && mo->property(idx).isFinal())) {
- absType = 0;
- if (!fetch(type, mo, reg, idx, subscribeName, nameNodes.at(ii)))
- return false;
- } else {
-
- Instr prop;
- if (ii == nameParts.count() -1 )
- prop.common.type = Instr::FindPropertyTerminal;
- else
- prop.common.type = Instr::FindProperty;
-
- prop.find.reg = reg;
- prop.find.src = reg;
- prop.find.name = registerString(name);
- prop.find.exceptionId = exceptionId(nameNodes.at(ii));
-
- if (subscription(subscribeName, &type))
- prop.find.subscribeIndex = subscriptionIndex(subscribeName);
- else
- prop.find.subscribeIndex = -1;
-
- type.unknownType = true;
- type.metaObject = 0;
- type.type = -1;
- type.reg = reg;
- bytecode << prop;
- }
- }
-
- wasAttachedObject = false;
- }
-
- return true;
-}
-
-bool QDeclarativeBindingCompilerPrivate::tryArith(QDeclarativeJS::AST::Node *node)
-{
- if (node->kind != AST::Node::Kind_BinaryExpression)
- return false;
-
- AST::BinaryExpression *expression = static_cast<AST::BinaryExpression *>(node);
- if (expression->op == QSOperator::Add ||
- expression->op == QSOperator::Sub)
- return true;
- else
- return false;
-}
-
-bool QDeclarativeBindingCompilerPrivate::parseArith(QDeclarativeJS::AST::Node *node, Result &type)
-{
- AST::BinaryExpression *expression = static_cast<AST::BinaryExpression *>(node);
-
- type.reg = acquireReg();
- if (type.reg == -1)
- return false;
-
- Result lhs;
- Result rhs;
-
- if (!parseExpression(expression->left, lhs)) return false;
- if (!parseExpression(expression->right, rhs)) return false;
-
- if ((lhs.type == QVariant::Int || lhs.type == QMetaType::QReal) &&
- (rhs.type == QVariant::Int || rhs.type == QMetaType::QReal))
- return numberArith(type, lhs, rhs, (QSOperator::Op)expression->op);
- else if(expression->op == QSOperator::Sub)
- return numberArith(type, lhs, rhs, (QSOperator::Op)expression->op);
- else if ((lhs.type == QMetaType::QString || lhs.unknownType) &&
- (rhs.type == QMetaType::QString || rhs.unknownType) &&
- (lhs.type == QMetaType::QString || rhs.type == QMetaType::QString))
- return stringArith(type, lhs, rhs, (QSOperator::Op)expression->op);
- else
- return false;
-}
-
-bool QDeclarativeBindingCompilerPrivate::numberArith(Result &type, const Result &lhs, const Result &rhs, QSOperator::Op op)
-{
- bool nativeReal = rhs.type == QMetaType::QReal ||
- lhs.type == QMetaType::QReal ||
- lhs.unknownType ||
- rhs.unknownType;
-
- if (nativeReal && lhs.type == QMetaType::Int) {
- Instr convert;
- convert.common.type = Instr::ConvertIntToReal;
- convert.unaryop.output = lhs.reg;
- convert.unaryop.src = lhs.reg;
- bytecode << convert;
- }
-
- if (nativeReal && rhs.type == QMetaType::Int) {
- Instr convert;
- convert.common.type = Instr::ConvertIntToReal;
- convert.unaryop.output = rhs.reg;
- convert.unaryop.src = rhs.reg;
- bytecode << convert;
- }
-
- int lhsTmp = -1;
- int rhsTmp = -1;
-
- if (lhs.unknownType) {
- if (!qmlExperimental())
- return false;
-
- lhsTmp = acquireReg();
- if (lhsTmp == -1)
- return false;
-
- Instr conv;
- conv.common.type = Instr::ConvertGenericToReal;
- conv.unaryop.output = lhsTmp;
- conv.unaryop.src = lhs.reg;
- bytecode << conv;
- }
-
- if (rhs.unknownType) {
- if (!qmlExperimental())
- return false;
-
- rhsTmp = acquireReg();
- if (rhsTmp == -1)
- return false;
-
- Instr conv;
- conv.common.type = Instr::ConvertGenericToReal;
- conv.unaryop.output = rhsTmp;
- conv.unaryop.src = rhs.reg;
- bytecode << conv;
- }
-
- Instr arith;
- if (op == QSOperator::Add) {
- arith.common.type = nativeReal?Instr::AddReal:Instr::AddInt;
- } else if (op == QSOperator::Sub) {
- arith.common.type = nativeReal?Instr::MinusReal:Instr::MinusInt;
- } else {
- qFatal("Unsupported arithmetic operator");
- }
-
- arith.binaryop.output = type.reg;
- arith.binaryop.src1 = (lhsTmp == -1)?lhs.reg:lhsTmp;
- arith.binaryop.src2 = (rhsTmp == -1)?rhs.reg:rhsTmp;
- bytecode << arith;
-
- type.metaObject = 0;
- type.type = nativeReal?QMetaType::QReal:QMetaType::Int;
- type.subscriptionSet.unite(lhs.subscriptionSet);
- type.subscriptionSet.unite(rhs.subscriptionSet);
-
- if (lhsTmp != -1) releaseReg(lhsTmp);
- if (rhsTmp != -1) releaseReg(rhsTmp);
- releaseReg(lhs.reg);
- releaseReg(rhs.reg);
-
- return true;
-}
-
-bool QDeclarativeBindingCompilerPrivate::stringArith(Result &type, const Result &lhs, const Result &rhs, QSOperator::Op op)
-{
- if (op != QSOperator::Add)
- return false;
-
- int lhsTmp = -1;
- int rhsTmp = -1;
-
- if (lhs.unknownType) {
- if (!qmlExperimental())
- return false;
-
- lhsTmp = acquireReg(Instr::CleanupString);
- if (lhsTmp == -1)
- return false;
-
- Instr convert;
- convert.common.type = Instr::ConvertGenericToString;
- convert.unaryop.output = lhsTmp;
- convert.unaryop.src = lhs.reg;
- bytecode << convert;
- }
-
- if (rhs.unknownType) {
- if (!qmlExperimental())
- return false;
-
- rhsTmp = acquireReg(Instr::CleanupString);
- if (rhsTmp == -1)
- return false;
-
- Instr convert;
- convert.common.type = Instr::ConvertGenericToString;
- convert.unaryop.output = rhsTmp;
- convert.unaryop.src = rhs.reg;
- bytecode << convert;
- }
-
- type.reg = acquireReg(Instr::CleanupString);
- if (type.reg == -1)
- return false;
-
- type.type = QMetaType::QString;
-
- Instr add;
- add.common.type = Instr::AddString;
- add.binaryop.output = type.reg;
- add.binaryop.src1 = (lhsTmp == -1)?lhs.reg:lhsTmp;
- add.binaryop.src2 = (rhsTmp == -1)?rhs.reg:rhsTmp;
- bytecode << add;
-
- if (lhsTmp != -1) releaseReg(lhsTmp);
- if (rhsTmp != -1) releaseReg(rhsTmp);
- releaseReg(lhs.reg);
- releaseReg(rhs.reg);
-
- return true;
-}
-
-bool QDeclarativeBindingCompilerPrivate::tryLogic(QDeclarativeJS::AST::Node *node)
-{
- if (node->kind != AST::Node::Kind_BinaryExpression)
- return false;
-
- AST::BinaryExpression *expression = static_cast<AST::BinaryExpression *>(node);
- if (expression->op == QSOperator::Gt ||
- expression->op == QSOperator::Equal ||
- expression->op == QSOperator::NotEqual)
- return true;
- else
- return false;
-}
-
-bool QDeclarativeBindingCompilerPrivate::parseLogic(QDeclarativeJS::AST::Node *node, Result &type)
-{
- AST::BinaryExpression *expression = static_cast<AST::BinaryExpression *>(node);
-
- Result lhs;
- Result rhs;
-
- if (!parseExpression(expression->left, lhs)) return false;
- if (!parseExpression(expression->right, rhs)) return false;
-
- type.reg = acquireReg();
- if (type.reg == -1)
- return false;
-
- type.metaObject = 0;
- type.type = QVariant::Bool;
-
- if (lhs.type == QMetaType::QReal && rhs.type == QMetaType::QReal) {
-
- Instr op;
- if (expression->op == QSOperator::Gt)
- op.common.type = Instr::GreaterThanReal;
- else if (expression->op == QSOperator::Equal)
- op.common.type = Instr::CompareReal;
- else if (expression->op == QSOperator::NotEqual)
- op.common.type = Instr::NotCompareReal;
- else
- return false;
- op.binaryop.output = type.reg;
- op.binaryop.src1 = lhs.reg;
- op.binaryop.src2 = rhs.reg;
- bytecode << op;
-
-
- } else if (lhs.type == QMetaType::QString && rhs.type == QMetaType::QString) {
-
- Instr op;
- if (expression->op == QSOperator::Equal)
- op.common.type = Instr::CompareString;
- else if (expression->op == QSOperator::NotEqual)
- op.common.type = Instr::NotCompareString;
- else
- return false;
- op.binaryop.output = type.reg;
- op.binaryop.src1 = lhs.reg;
- op.binaryop.src2 = rhs.reg;
- bytecode << op;
-
- } else {
- return false;
- }
-
- releaseReg(lhs.reg);
- releaseReg(rhs.reg);
-
- return true;
-}
-
-bool QDeclarativeBindingCompilerPrivate::tryConditional(QDeclarativeJS::AST::Node *node)
-{
- return (node->kind == AST::Node::Kind_ConditionalExpression);
-}
-
-bool QDeclarativeBindingCompilerPrivate::parseConditional(QDeclarativeJS::AST::Node *node, Result &type)
-{
- AST::ConditionalExpression *expression = static_cast<AST::ConditionalExpression *>(node);
-
- AST::Node *test = expression->expression;
- if (test->kind == AST::Node::Kind_NestedExpression)
- test = static_cast<AST::NestedExpression*>(test)->expression;
-
- Result etype;
- if (!parseExpression(test, etype)) return false;
-
- if (etype.type != QVariant::Bool)
- return false;
-
- Instr skip;
- skip.common.type = Instr::Skip;
- skip.skip.reg = etype.reg;
- skip.skip.count = 0;
- int skipIdx = bytecode.count();
- bytecode << skip;
-
- // Release to allow reuse of reg
- releaseReg(etype.reg);
-
- QSet<QString> preSubSet = subscriptionSet;
-
- // int preConditionalSubscriptions = subscriptionSet.count();
-
- Result ok;
- if (!parseExpression(expression->ok, ok)) return false;
- if (ok.unknownType) return false;
-
- int skipIdx2 = bytecode.count();
- skip.skip.reg = -1;
- bytecode << skip;
-
- // Release to allow reuse of reg
- releaseReg(ok.reg);
- bytecode[skipIdx].skip.count = bytecode.count() - skipIdx - 1;
-
- subscriptionSet = preSubSet;
-
- Result ko;
- if (!parseExpression(expression->ko, ko)) return false;
- if (ko.unknownType) return false;
-
- // Release to allow reuse of reg
- releaseReg(ko.reg);
- bytecode[skipIdx2].skip.count = bytecode.count() - skipIdx2 - 1;
-
- if (ok != ko)
- return false; // Must be same type and in same register
-
- subscriptionSet = preSubSet;
-
- if (!subscriptionNeutral(subscriptionSet, ok.subscriptionSet, ko.subscriptionSet))
- return false; // Conditionals cannot introduce new subscriptions
-
- type = ok;
-
- return true;
-}
-
-bool QDeclarativeBindingCompilerPrivate::tryConstant(QDeclarativeJS::AST::Node *node)
-{
- return node->kind == AST::Node::Kind_TrueLiteral ||
- node->kind == AST::Node::Kind_FalseLiteral ||
- node->kind == AST::Node::Kind_NumericLiteral ||
- node->kind == AST::Node::Kind_StringLiteral;
-}
-
-bool QDeclarativeBindingCompilerPrivate::parseConstant(QDeclarativeJS::AST::Node *node, Result &type)
-{
- type.metaObject = 0;
- type.type = -1;
- type.reg = acquireReg();
- if (type.reg == -1)
- return false;
-
- if (node->kind == AST::Node::Kind_TrueLiteral) {
- type.type = QVariant::Bool;
- Instr instr;
- instr.common.type = Instr::Bool;
- instr.bool_value.reg = type.reg;
- instr.bool_value.value = true;
- bytecode << instr;
- return true;
- } else if (node->kind == AST::Node::Kind_FalseLiteral) {
- type.type = QVariant::Bool;
- Instr instr;
- instr.common.type = Instr::Bool;
- instr.bool_value.reg = type.reg;
- instr.bool_value.value = false;
- bytecode << instr;
- return true;
- } else if (node->kind == AST::Node::Kind_NumericLiteral) {
- qreal value = qreal(static_cast<AST::NumericLiteral *>(node)->value);
-
- if (qreal(float(value)) != value)
- return false;
-
- type.type = QMetaType::QReal;
- Instr instr;
- instr.common.type = Instr::Real;
- instr.real_value.reg = type.reg;
- instr.real_value.value = float(value);
- bytecode << instr;
- return true;
- } else if (node->kind == AST::Node::Kind_StringLiteral) {
- QString str = static_cast<AST::StringLiteral *>(node)->value->asString();
- type.type = QMetaType::QString;
- type.reg = registerLiteralString(str);
- return true;
- } else {
- return false;
- }
-}
-
-bool QDeclarativeBindingCompilerPrivate::tryMethod(QDeclarativeJS::AST::Node *node)
-{
- return node->kind == AST::Node::Kind_CallExpression;
-}
-
-bool QDeclarativeBindingCompilerPrivate::parseMethod(QDeclarativeJS::AST::Node *node, Result &result)
-{
- AST::CallExpression *expr = static_cast<AST::CallExpression *>(node);
-
- QStringList name;
- if (!buildName(name, expr->base))
- return false;
-
- if (name.count() != 2 || name.at(0) != QLatin1String("Math"))
- return false;
-
- QString method = name.at(1);
-
- AST::ArgumentList *args = expr->arguments;
- if (!args) return false;
- AST::ExpressionNode *arg0 = args->expression;
- args = args->next;
- if (!args) return false;
- AST::ExpressionNode *arg1 = args->expression;
- if (args->next != 0) return false;
- if (!arg0 || !arg1) return false;
-
- Result r0;
- if (!parseExpression(arg0, r0)) return false;
- Result r1;
- if (!parseExpression(arg1, r1)) return false;
-
- if (r0.type != QMetaType::QReal || r1.type != QMetaType::QReal)
- return false;
-
- Instr op;
- if (method == QLatin1String("max")) {
- op.common.type = Instr::MaxReal;
- } else if (method == QLatin1String("min")) {
- op.common.type = Instr::MinReal;
- } else {
- return false;
- }
- // We release early to reuse registers
- releaseReg(r0.reg);
- releaseReg(r1.reg);
-
- op.binaryop.output = acquireReg();
- if (op.binaryop.output == -1)
- return false;
-
- op.binaryop.src1 = r0.reg;
- op.binaryop.src2 = r1.reg;
- bytecode << op;
-
- result.type = QMetaType::QReal;
- result.reg = op.binaryop.output;
-
- return true;
-}
-
-bool QDeclarativeBindingCompilerPrivate::buildName(QStringList &name,
- QDeclarativeJS::AST::Node *node,
- QList<QDeclarativeJS::AST::ExpressionNode *> *nodes)
-{
- if (node->kind == AST::Node::Kind_IdentifierExpression) {
- name << static_cast<AST::IdentifierExpression*>(node)->name->asString();
- 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->asString();
- if (nodes) *nodes << expr;
- } else {
- return false;
- }
-
- return true;
-}
-
-bool QDeclarativeBindingCompilerPrivate::fetch(Result &rv, const QMetaObject *mo, int reg,
- int idx, const QStringList &subName,
- QDeclarativeJS::AST::ExpressionNode *node)
-{
- QMetaProperty prop = mo->property(idx);
- rv.metaObject = 0;
- rv.type = 0;
-
- //XXX binding optimizer doesn't handle properties with a revision
- if (prop.revision() > 0)
- return false;
-
- int fastFetchIndex = fastProperties()->accessorIndexForProperty(mo, idx);
-
- Instr fetch;
-
- if (!qmlDisableFastProperties() && fastFetchIndex != -1) {
- fetch.common.type = Instr::FetchAndSubscribe;
- fetch.fetchAndSubscribe.objectReg = reg;
- fetch.fetchAndSubscribe.output = reg;
- fetch.fetchAndSubscribe.function = fastFetchIndex;
- fetch.fetchAndSubscribe.subscription = subscriptionIndex(subName);
- fetch.fetchAndSubscribe.exceptionId = exceptionId(node);
- } else {
- if (subscription(subName, &rv) && prop.hasNotifySignal() && prop.notifySignalIndex() != -1) {
- Instr sub;
- sub.common.type = Instr::Subscribe;
- sub.subscribe.offset = subscriptionIndex(subName);
- sub.subscribe.reg = reg;
- sub.subscribe.index = prop.notifySignalIndex();
- bytecode << sub;
- }
-
- fetch.common.type = Instr::Fetch;
- fetch.fetch.objectReg = reg;
- fetch.fetch.index = idx;
- fetch.fetch.output = reg;
- fetch.fetch.exceptionId = exceptionId(node);
- }
-
- rv.type = prop.userType();
- rv.metaObject = engine->metaObjectForType(rv.type);
- rv.reg = reg;
-
- if (rv.type == QMetaType::QString) {
- int tmp = acquireReg();
- if (tmp == -1)
- return false;
- Instr copy;
- copy.common.type = Instr::Copy;
- copy.copy.reg = tmp;
- copy.copy.src = reg;
- bytecode << copy;
- releaseReg(tmp);
- fetch.fetch.objectReg = tmp;
-
- Instr setup;
- setup.common.type = Instr::NewString;
- setup.construct.reg = reg;
- bytecode << setup;
- registerCleanup(reg, Instr::CleanupString);
- }
-
- bytecode << fetch;
-
- if (!rv.metaObject &&
- rv.type != QMetaType::QReal &&
- rv.type != QMetaType::Int &&
- rv.type != QMetaType::Bool &&
- rv.type != qMetaTypeId<QDeclarativeAnchorLine>() &&
- rv.type != QMetaType::QString) {
- rv.metaObject = 0;
- rv.type = 0;
- return false; // Unsupported type (string not supported yet);
- }
-
- return true;
-}
-
-void QDeclarativeBindingCompilerPrivate::registerCleanup(int reg, int cleanup, int cleanupType)
-{
- registerCleanups.insert(reg, qMakePair(cleanup, cleanupType));
-}
-
-int QDeclarativeBindingCompilerPrivate::acquireReg(int cleanup, int cleanupType)
-{
- for (int ii = 0; ii < 32; ++ii) {
- if (!(registers & (1 << ii))) {
- registers |= (1 << ii);
-
- if (cleanup != Instr::Noop)
- registerCleanup(ii, cleanup, cleanupType);
-
- return ii;
- }
- }
- return -1;
-}
-
-void QDeclarativeBindingCompilerPrivate::releaseReg(int reg)
-{
- Q_ASSERT(reg >= 0 && reg <= 31);
-
- if (registerCleanups.contains(reg)) {
- QPair<int, int> c = registerCleanups[reg];
- registerCleanups.remove(reg);
- Instr cleanup;
- cleanup.common.type = (quint8)c.first;
- cleanup.cleanup.reg = reg;
- bytecode << cleanup;
- }
-
- quint32 mask = 1 << reg;
- registers &= ~mask;
-}
-
-// Returns a reg
-int QDeclarativeBindingCompilerPrivate::registerLiteralString(const QString &str)
-{
- QByteArray strdata((const char *)str.constData(), str.length() * sizeof(QChar));
- int offset = data.count();
- data += strdata;
-
- int reg = acquireReg(Instr::CleanupString);
- if (reg == -1)
- return false;
-
- Instr string;
- string.common.type = Instr::String;
- string.string_value.reg = reg;
- string.string_value.offset = offset;
- string.string_value.length = str.length();
- bytecode << string;
-
- return reg;
-}
-
-// Returns an identifier offset
-int QDeclarativeBindingCompilerPrivate::registerString(const QString &string)
-{
- Q_ASSERT(!string.isEmpty());
-
- QHash<QString, QPair<int, int> >::ConstIterator iter = registeredStrings.find(string);
-
- if (iter == registeredStrings.end()) {
- 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.insert(string, qMakePair(registeredStrings.count(), rv));
- }
-
- Instr reg;
- reg.common.type = Instr::InitString;
- reg.initstring.offset = iter->first;
- reg.initstring.dataIdx = iter->second;
- bytecode << reg;
- return reg.initstring.offset;
-}
-
-bool QDeclarativeBindingCompilerPrivate::subscription(const QStringList &sub, Result *result)
-{
- QString str = sub.join(QLatin1String("."));
- result->subscriptionSet.insert(str);
-
- if (subscriptionSet.contains(str)) {
- return false;
- } else {
- subscriptionSet.insert(str);
- return true;
- }
-}
-
-int QDeclarativeBindingCompilerPrivate::subscriptionIndex(const QStringList &sub)
-{
- QString str = sub.join(QLatin1String("."));
- QHash<QString, int>::ConstIterator iter = subscriptionIds.find(str);
- if (iter == subscriptionIds.end())
- iter = subscriptionIds.insert(str, subscriptionIds.count());
- usedSubscriptionIds.insert(*iter);
- return *iter;
-}
-
-/*
- Returns true if lhs contains no subscriptions that aren't also in base or rhs AND
- rhs contains no subscriptions that aren't also in base or lhs.
-*/
-bool QDeclarativeBindingCompilerPrivate::subscriptionNeutral(const QSet<QString> &base,
- const QSet<QString> &lhs,
- const QSet<QString> &rhs)
-{
- QSet<QString> difflhs = lhs;
- difflhs.subtract(rhs);
- QSet<QString> diffrhs = rhs;
- diffrhs.subtract(lhs);
-
- difflhs.unite(diffrhs);
- difflhs.subtract(base);
-
- return difflhs.isEmpty();
-}
-
-quint8 QDeclarativeBindingCompilerPrivate::exceptionId(QDeclarativeJS::AST::ExpressionNode *n)
-{
- quint8 rv = 0xFF;
- if (n && exceptions.count() < 0xFF) {
- rv = (quint8)exceptions.count();
- QDeclarativeJS::AST::SourceLocation l = n->firstSourceLocation();
- quint64 e = l.startLine;
- e <<= 32;
- e |= l.startColumn;
- exceptions.append(e);
- }
- return rv;
-}
-
-QDeclarativeBindingCompiler::QDeclarativeBindingCompiler()
-: d(new QDeclarativeBindingCompilerPrivate)
-{
-}
-
-QDeclarativeBindingCompiler::~QDeclarativeBindingCompiler()
-{
- delete d; d = 0;
-}
-
-/*
-Returns true if any bindings were compiled.
-*/
-bool QDeclarativeBindingCompiler::isValid() const
-{
- return !d->committed.bytecode.isEmpty();
-}
-
-/*
--1 on failure, otherwise the binding index to use.
-*/
-int QDeclarativeBindingCompiler::compile(const Expression &expression, QDeclarativeEnginePrivate *engine)
-{
- if (!expression.expression.asAST()) return false;
-
- if (!qmlExperimental() && expression.property->isValueTypeSubProperty)
- return -1;
-
- if (qmlDisableOptimizer())
- return -1;
-
- d->context = expression.context;
- d->component = expression.component;
- d->destination = expression.property;
- d->ids = expression.ids;
- d->imports = expression.imports;
- d->engine = engine;
-
- if (d->compile(expression.expression.asAST())) {
- return d->commitCompile();
- } else {
- return -1;
- }
-}
-
-
-QByteArray QDeclarativeBindingCompilerPrivate::buildSignalTable() const
-{
- QHash<int, QList<int> > table;
-
- for (int ii = 0; ii < committed.count(); ++ii) {
- const QSet<int> &deps = committed.dependencies.at(ii);
- for (QSet<int>::ConstIterator iter = deps.begin(); iter != deps.end(); ++iter)
- table[*iter].append(ii);
- }
-
- QVector<quint32> header;
- QVector<quint32> data;
- for (int ii = 0; ii < committed.subscriptionIds.count(); ++ii) {
- header.append(committed.subscriptionIds.count() + data.count());
- const QList<int> &bindings = table[ii];
- data.append(bindings.count());
- for (int jj = 0; jj < bindings.count(); ++jj)
- data.append(bindings.at(jj));
- }
- header << data;
-
- return QByteArray((const char *)header.constData(), header.count() * sizeof(quint32));
-}
-
-QByteArray QDeclarativeBindingCompilerPrivate::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 QDeclarativeBindingCompiler::program() const
-{
- QByteArray programData;
-
- if (isValid()) {
- Program prog;
- prog.bindings = d->committed.count();
-
- QVector<Instr> bytecode;
- Instr skip;
- skip.common.type = Instr::Skip;
- skip.skip.reg = -1;
- for (int ii = 0; ii < d->committed.count(); ++ii) {
- skip.skip.count = d->committed.count() - ii - 1;
- skip.skip.count+= d->committed.offsets.at(ii);
- bytecode << skip;
- }
- bytecode << d->committed.bytecode;
-
- 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();
- prog.compiled = false;
- int size = sizeof(Program) + bytecode.count() * sizeof(Instr);
- size += prog.dataLength;
-
- programData.resize(size);
- memcpy(programData.data(), &prog, sizeof(Program));
- if (prog.dataLength)
- memcpy((char *)((Program *)programData.data())->data(), data.constData(),
- data.size());
- memcpy((char *)((Program *)programData.data())->instructions(), bytecode.constData(),
- bytecode.count() * sizeof(Instr));
- }
-
- return programData;
-}
-
-
-
-QT_END_NAMESPACE
diff --git a/src/declarative/qml/qdeclarativecompiledbindings_p.h b/src/declarative/qml/qdeclarativecompiledbindings_p.h
deleted file mode 100644
index e7b6937753..0000000000
--- a/src/declarative/qml/qdeclarativecompiledbindings_p.h
+++ /dev/null
@@ -1,116 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
-** All rights reserved.
-** Contact: Nokia Corporation (qt-info@nokia.com)
-**
-** This file is part of the QtDeclarative 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 QDECLARATIVEBINDINGOPTIMIZATIONS_P_H
-#define QDECLARATIVEBINDINGOPTIMIZATIONS_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/qdeclarativeexpression_p.h"
-#include "private/qdeclarativebinding_p.h"
-
-QT_BEGIN_HEADER
-
-QT_BEGIN_NAMESPACE
-
-struct QDeclarativeBindingCompilerPrivate;
-class QDeclarativeBindingCompiler
-{
-public:
- QDeclarativeBindingCompiler();
- ~QDeclarativeBindingCompiler();
-
- // Returns true if bindings were compiled
- bool isValid() const;
-
- struct Expression
- {
- QDeclarativeParser::Object *component;
- QDeclarativeParser::Object *context;
- QDeclarativeParser::Property *property;
- QDeclarativeParser::Variant expression;
- QHash<QString, QDeclarativeParser::Object *> ids;
- QDeclarativeImports imports;
- };
-
- // -1 on failure, otherwise the binding index to use
- int compile(const Expression &, QDeclarativeEnginePrivate *);
-
- // Returns the compiled program
- QByteArray program() const;
-
- static void dump(const QByteArray &);
-private:
- QDeclarativeBindingCompilerPrivate *d;
-};
-
-class QDeclarativeCompiledBindingsPrivate;
-class QDeclarativeCompiledBindings : public QObject, public QDeclarativeAbstractExpression, public QDeclarativeRefCount
-{
-public:
- QDeclarativeCompiledBindings(const char *program, QDeclarativeContextData *context);
- virtual ~QDeclarativeCompiledBindings();
-
- QDeclarativeAbstractBinding *configBinding(int index, QObject *target, QObject *scope, int property);
-
-protected:
- int qt_metacall(QMetaObject::Call, int, void **);
-
-private:
- Q_DISABLE_COPY(QDeclarativeCompiledBindings)
- Q_DECLARE_PRIVATE(QDeclarativeCompiledBindings)
-};
-
-QT_END_NAMESPACE
-
-QT_END_HEADER
-
-#endif // QDECLARATIVEBINDINGOPTIMIZATIONS_P_H
-
diff --git a/src/declarative/qml/qdeclarativecompileddata.cpp b/src/declarative/qml/qdeclarativecompileddata.cpp
index 913098c51d..2ea41d857f 100644
--- a/src/declarative/qml/qdeclarativecompileddata.cpp
+++ b/src/declarative/qml/qdeclarativecompileddata.cpp
@@ -97,70 +97,6 @@ int QDeclarativeCompiledData::indexForUrl(const QUrl &data)
return idx;
}
-int QDeclarativeCompiledData::indexForFloat(float *data, int count)
-{
- Q_ASSERT(count > 0);
-
- for (int ii = 0; ii <= floatData.count() - count; ++ii) {
- bool found = true;
- for (int jj = 0; jj < count; ++jj) {
- if (floatData.at(ii + jj) != data[jj]) {
- found = false;
- break;
- }
- }
-
- if (found)
- return ii;
- }
-
- int idx = floatData.count();
- for (int ii = 0; ii < count; ++ii)
- floatData << data[ii];
-
- return idx;
-}
-
-int QDeclarativeCompiledData::indexForInt(int *data, int count)
-{
- Q_ASSERT(count > 0);
-
- for (int ii = 0; ii <= intData.count() - count; ++ii) {
- bool found = true;
- for (int jj = 0; jj < count; ++jj) {
- if (intData.at(ii + jj) != data[jj]) {
- found = false;
- break;
- }
- }
-
- if (found)
- return ii;
- }
-
- int idx = intData.count();
- for (int ii = 0; ii < count; ++ii)
- intData << data[ii];
-
- return idx;
-}
-
-int QDeclarativeCompiledData::indexForLocation(const QDeclarativeParser::Location &l)
-{
- // ### FIXME
- int rv = locations.count();
- locations << l;
- return rv;
-}
-
-int QDeclarativeCompiledData::indexForLocation(const QDeclarativeParser::LocationSpan &l)
-{
- // ### FIXME
- int rv = locations.count();
- locations << l.start << l.end;
- return rv;
-}
-
QDeclarativeCompiledData::QDeclarativeCompiledData(QDeclarativeEngine *engine)
: QDeclarativeCleanup(engine), importCache(0), root(0), rootPropertyCache(0)
{
@@ -181,6 +117,9 @@ QDeclarativeCompiledData::~QDeclarativeCompiledData()
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();
@@ -243,13 +182,42 @@ void QDeclarativeCompiledData::dumpInstructions()
{
if (!name.isEmpty())
qWarning() << name;
- qWarning().nospace() << "Index\tLine\tOperation\t\tData1\tData2\tData3\tComments";
+ qWarning().nospace() << "Index\tOperation\t\tData1\tData2\tData3\tComments";
qWarning().nospace() << "-------------------------------------------------------------------------------";
- for (int ii = 0; ii < bytecode.count(); ++ii) {
- dump(&bytecode[ii], ii);
+
+ const char *instructionStream = bytecode.constData();
+ const char *endInstructionStream = bytecode.constData() + bytecode.size();
+
+ int instructionCount = 0;
+ while (instructionStream < endInstructionStream) {
+ QDeclarativeInstruction *instr = (QDeclarativeInstruction *)instructionStream;
+ dump(instr, instructionCount);
+ instructionStream += instr->size();
+ instructionCount++;
}
+
qWarning().nospace() << "-------------------------------------------------------------------------------";
}
+int QDeclarativeCompiledData::addInstruction(const QDeclarativeInstruction &instr)
+{
+ int ptrOffset = bytecode.size();
+ int size = instr.size();
+ bytecode.resize(bytecode.size() + size);
+ char *data = bytecode.data() + ptrOffset;
+ qMemCopy(data, &instr, size);
+
+ return ptrOffset;
+}
+
+int QDeclarativeCompiledData::nextInstructionIndex()
+{
+ return bytecode.size();
+}
+
+QDeclarativeInstruction *QDeclarativeCompiledData::instruction(int index)
+{
+ return (QDeclarativeInstruction *)(bytecode.constData() + index);
+}
QT_END_NAMESPACE
diff --git a/src/declarative/qml/qdeclarativecompiler.cpp b/src/declarative/qml/qdeclarativecompiler.cpp
index e642a67102..e66a3fe792 100644
--- a/src/declarative/qml/qdeclarativecompiler.cpp
+++ b/src/declarative/qml/qdeclarativecompiler.cpp
@@ -63,7 +63,7 @@
#include "private/qdeclarativeglobal_p.h"
#include "private/qdeclarativescriptparser_p.h"
#include "private/qdeclarativebinding_p.h"
-#include "private/qdeclarativecompiledbindings_p.h"
+#include "private/qdeclarativev4compiler_p.h"
#include "private/qdeclarativeglobalscriptclass_p.h"
#include <QColor>
@@ -79,7 +79,6 @@ QT_BEGIN_NAMESPACE
DEFINE_BOOL_CONFIG_OPTION(compilerDump, QML_COMPILER_DUMP);
DEFINE_BOOL_CONFIG_OPTION(compilerStatDump, QML_COMPILER_STATS);
-DEFINE_BOOL_CONFIG_OPTION(bindingsDump, QML_BINDINGS_DUMP);
using namespace QDeclarativeParser;
@@ -123,13 +122,26 @@ bool QDeclarativeCompiler::isAttachedPropertyName(const QByteArray &name)
/*!
Returns true if \a name refers to a signal property, false otherwise.
- Signal property names are those that start with "on", followed by a capital
- letter.
+ 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 QDeclarativeCompiler::isSignalPropertyName(const QByteArray &name)
{
- return name.length() >= 3 && name.startsWith("on") &&
- 'A' <= name.at(2) && 'Z' >= name.at(2);
+ if (name.length() < 3) return false;
+ if (!name.startsWith("on")) return false;
+ int ns = name.size();
+ for (int i = 2; i < ns; ++i) {
+ char curr = name.at(i);
+ if (curr == '_') continue;
+ if (curr >= 'A' && curr <= 'Z') return true;
+ return false;
+ }
+ return false; // consists solely of underscores - invalid.
}
/*!
@@ -201,6 +213,9 @@ bool QDeclarativeCompiler::testLiteralAssignment(const QMetaProperty &prop,
case QVariant::String:
if (!v->value.isString()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: string 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;
@@ -320,24 +335,29 @@ bool QDeclarativeCompiler::testLiteralAssignment(const QMetaProperty &prop,
void QDeclarativeCompiler::genLiteralAssignment(const QMetaProperty &prop,
QDeclarativeParser::Value *v)
{
- QString string = v->value.asString();
-
QDeclarativeInstruction instr;
- instr.line = v->location.start.line;
if (prop.isEnumType()) {
int value;
- if (prop.isFlagType()) {
- value = prop.enumerator().keysToValue(string.toUtf8().constData());
- } else
- value = prop.enumerator().keyToValue(string.toUtf8().constData());
+ if (v->value.isNumber()) {
+ // Preresolved enum
+ value = (int)v->value.asNumber();
+ } else {
+ // Must be a string
+ if (prop.isFlagType()) {
+ value = prop.enumerator().keysToValue(v->value.asString().toUtf8().constData());
+ } else
+ value = prop.enumerator().keyToValue(v->value.asString().toUtf8().constData());
+ }
- instr.type = QDeclarativeInstruction::StoreInteger;
+ instr.setType(QDeclarativeInstruction::StoreInteger);
instr.storeInteger.propertyIndex = prop.propertyIndex();
instr.storeInteger.value = value;
- output->bytecode << instr;
+ output->addInstruction(instr);
return;
}
+ QString string = v->value.asString();
+
int type = prop.userType();
switch(type) {
case -1:
@@ -345,20 +365,20 @@ void QDeclarativeCompiler::genLiteralAssignment(const QMetaProperty &prop,
if (v->value.isNumber()) {
double n = v->value.asNumber();
if (double(int(n)) == n) {
- instr.type = QDeclarativeInstruction::StoreVariantInteger;
+ instr.setType(QDeclarativeInstruction::StoreVariantInteger);
instr.storeInteger.propertyIndex = prop.propertyIndex();
instr.storeInteger.value = int(n);
} else {
- instr.type = QDeclarativeInstruction::StoreVariantDouble;
+ instr.setType(QDeclarativeInstruction::StoreVariantDouble);
instr.storeDouble.propertyIndex = prop.propertyIndex();
instr.storeDouble.value = n;
}
} else if(v->value.isBoolean()) {
- instr.type = QDeclarativeInstruction::StoreVariantBool;
+ instr.setType(QDeclarativeInstruction::StoreVariantBool);
instr.storeBool.propertyIndex = prop.propertyIndex();
instr.storeBool.value = v->value.asBoolean();
} else {
- instr.type = QDeclarativeInstruction::StoreVariant;
+ instr.setType(QDeclarativeInstruction::StoreVariant);
instr.storeString.propertyIndex = prop.propertyIndex();
instr.storeString.value = output->indexForString(string);
}
@@ -366,14 +386,21 @@ void QDeclarativeCompiler::genLiteralAssignment(const QMetaProperty &prop,
break;
case QVariant::String:
{
- instr.type = QDeclarativeInstruction::StoreString;
+ instr.setType(QDeclarativeInstruction::StoreString);
instr.storeString.propertyIndex = prop.propertyIndex();
instr.storeString.value = output->indexForString(string);
}
break;
+ case QVariant::ByteArray:
+ {
+ instr.setType(QDeclarativeInstruction::StoreByteArray);
+ instr.storeByteArray.propertyIndex = prop.propertyIndex();
+ instr.storeByteArray.value = output->indexForByteArray(string.toLatin1());
+ }
+ break;
case QVariant::Url:
{
- instr.type = QDeclarativeInstruction::StoreUrl;
+ instr.setType(QDeclarativeInstruction::StoreUrl);
QUrl u = string.isEmpty() ? QUrl() : output->url.resolved(QUrl(string));
instr.storeUrl.propertyIndex = prop.propertyIndex();
instr.storeUrl.value = output->indexForUrl(u);
@@ -381,28 +408,28 @@ void QDeclarativeCompiler::genLiteralAssignment(const QMetaProperty &prop,
break;
case QVariant::UInt:
{
- instr.type = QDeclarativeInstruction::StoreInteger;
+ instr.setType(QDeclarativeInstruction::StoreInteger);
instr.storeInteger.propertyIndex = prop.propertyIndex();
instr.storeInteger.value = uint(v->value.asNumber());
}
break;
case QVariant::Int:
{
- instr.type = QDeclarativeInstruction::StoreInteger;
+ instr.setType(QDeclarativeInstruction::StoreInteger);
instr.storeInteger.propertyIndex = prop.propertyIndex();
instr.storeInteger.value = int(v->value.asNumber());
}
break;
case QMetaType::Float:
{
- instr.type = QDeclarativeInstruction::StoreFloat;
+ instr.setType(QDeclarativeInstruction::StoreFloat);
instr.storeFloat.propertyIndex = prop.propertyIndex();
instr.storeFloat.value = float(v->value.asNumber());
}
break;
case QVariant::Double:
{
- instr.type = QDeclarativeInstruction::StoreDouble;
+ instr.setType(QDeclarativeInstruction::StoreDouble);
instr.storeDouble.propertyIndex = prop.propertyIndex();
instr.storeDouble.value = v->value.asNumber();
}
@@ -410,7 +437,7 @@ void QDeclarativeCompiler::genLiteralAssignment(const QMetaProperty &prop,
case QVariant::Color:
{
QColor c = QDeclarativeStringConverters::colorFromString(string);
- instr.type = QDeclarativeInstruction::StoreColor;
+ instr.setType(QDeclarativeInstruction::StoreColor);
instr.storeColor.propertyIndex = prop.propertyIndex();
instr.storeColor.value = c.rgba();
}
@@ -419,7 +446,7 @@ void QDeclarativeCompiler::genLiteralAssignment(const QMetaProperty &prop,
case QVariant::Date:
{
QDate d = QDeclarativeStringConverters::dateFromString(string);
- instr.type = QDeclarativeInstruction::StoreDate;
+ instr.setType(QDeclarativeInstruction::StoreDate);
instr.storeDate.propertyIndex = prop.propertyIndex();
instr.storeDate.value = d.toJulianDay();
}
@@ -427,80 +454,90 @@ void QDeclarativeCompiler::genLiteralAssignment(const QMetaProperty &prop,
case QVariant::Time:
{
QTime time = QDeclarativeStringConverters::timeFromString(string);
- int data[] = { time.hour(), time.minute(),
- time.second(), time.msec() };
- int index = output->indexForInt(data, 4);
- instr.type = QDeclarativeInstruction::StoreTime;
+ instr.setType(QDeclarativeInstruction::StoreTime);
instr.storeTime.propertyIndex = prop.propertyIndex();
- instr.storeTime.valueIndex = index;
+ instr.storeTime.time = *(QDeclarativeInstruction::instr_storeTime::QTime *)&time;
}
break;
case QVariant::DateTime:
{
QDateTime dateTime = QDeclarativeStringConverters::dateTimeFromString(string);
- int data[] = { dateTime.date().toJulianDay(),
- dateTime.time().hour(),
- dateTime.time().minute(),
- dateTime.time().second(),
- dateTime.time().msec() };
- int index = output->indexForInt(data, 5);
- instr.type = QDeclarativeInstruction::StoreDateTime;
+ QTime time = dateTime.time();
+ instr.setType(QDeclarativeInstruction::StoreDateTime);
instr.storeDateTime.propertyIndex = prop.propertyIndex();
- instr.storeDateTime.valueIndex = index;
+ instr.storeDateTime.date = dateTime.date().toJulianDay();
+ instr.storeDateTime.time = *(QDeclarativeInstruction::instr_storeTime::QTime *)&time;
}
break;
#endif // QT_NO_DATESTRING
case QVariant::Point:
+ {
+ bool ok;
+ QPoint point = QDeclarativeStringConverters::pointFFromString(string, &ok).toPoint();
+ instr.setType(QDeclarativeInstruction::StorePoint);
+ instr.storePoint.propertyIndex = prop.propertyIndex();
+ instr.storePoint.point.xp = point.x();
+ instr.storePoint.point.yp = point.y();
+ }
+ break;
case QVariant::PointF:
{
bool ok;
- QPointF point =
- QDeclarativeStringConverters::pointFFromString(string, &ok);
- float data[] = { float(point.x()), float(point.y()) };
- int index = output->indexForFloat(data, 2);
- if (type == QVariant::PointF)
- instr.type = QDeclarativeInstruction::StorePointF;
- else
- instr.type = QDeclarativeInstruction::StorePoint;
- instr.storeRealPair.propertyIndex = prop.propertyIndex();
- instr.storeRealPair.valueIndex = index;
+ QPointF point = QDeclarativeStringConverters::pointFFromString(string, &ok);
+ instr.setType(QDeclarativeInstruction::StorePointF);
+ instr.storePointF.propertyIndex = prop.propertyIndex();
+ instr.storePointF.point.xp = point.x();
+ instr.storePointF.point.yp = point.y();
}
break;
case QVariant::Size:
+ {
+ bool ok;
+ QSize size = QDeclarativeStringConverters::sizeFFromString(string, &ok).toSize();
+ instr.setType(QDeclarativeInstruction::StoreSize);
+ instr.storeSize.propertyIndex = prop.propertyIndex();
+ instr.storeSize.size.wd = size.width();
+ instr.storeSize.size.ht = size.height();
+ }
+ break;
case QVariant::SizeF:
{
bool ok;
QSizeF size = QDeclarativeStringConverters::sizeFFromString(string, &ok);
- float data[] = { float(size.width()), float(size.height()) };
- int index = output->indexForFloat(data, 2);
- if (type == QVariant::SizeF)
- instr.type = QDeclarativeInstruction::StoreSizeF;
- else
- instr.type = QDeclarativeInstruction::StoreSize;
- instr.storeRealPair.propertyIndex = prop.propertyIndex();
- instr.storeRealPair.valueIndex = index;
+ instr.setType(QDeclarativeInstruction::StoreSizeF);
+ instr.storeSizeF.propertyIndex = prop.propertyIndex();
+ instr.storeSizeF.size.wd = size.width();
+ instr.storeSizeF.size.ht = size.height();
}
break;
case QVariant::Rect:
+ {
+ bool ok;
+ QRect rect = QDeclarativeStringConverters::rectFFromString(string, &ok).toRect();
+ instr.setType(QDeclarativeInstruction::StoreRect);
+ instr.storeRect.propertyIndex = prop.propertyIndex();
+ instr.storeRect.rect.x1 = rect.left();
+ instr.storeRect.rect.y1 = rect.top();
+ instr.storeRect.rect.x2 = rect.right();
+ instr.storeRect.rect.y2 = rect.bottom();
+ }
+ break;
case QVariant::RectF:
{
bool ok;
QRectF rect = QDeclarativeStringConverters::rectFFromString(string, &ok);
- float data[] = { float(rect.x()), float(rect.y()),
- float(rect.width()), float(rect.height()) };
- int index = output->indexForFloat(data, 4);
- if (type == QVariant::RectF)
- instr.type = QDeclarativeInstruction::StoreRectF;
- else
- instr.type = QDeclarativeInstruction::StoreRect;
- instr.storeRect.propertyIndex = prop.propertyIndex();
- instr.storeRect.valueIndex = index;
+ instr.setType(QDeclarativeInstruction::StoreRectF);
+ instr.storeRectF.propertyIndex = prop.propertyIndex();
+ instr.storeRectF.rect.xp = rect.left();
+ instr.storeRectF.rect.yp = rect.top();
+ instr.storeRectF.rect.w = rect.width();
+ instr.storeRectF.rect.h = rect.height();
}
break;
case QVariant::Bool:
{
bool b = v->value.asBoolean();
- instr.type = QDeclarativeInstruction::StoreBool;
+ instr.setType(QDeclarativeInstruction::StoreBool);
instr.storeBool.propertyIndex = prop.propertyIndex();
instr.storeBool.value = b;
}
@@ -508,31 +545,25 @@ void QDeclarativeCompiler::genLiteralAssignment(const QMetaProperty &prop,
case QVariant::Vector3D:
{
bool ok;
- QVector3D vector =
- QDeclarativeStringConverters::vector3DFromString(string, &ok);
- float data[] = { float(vector.x()), float(vector.y()), float(vector.z()) };
- int index = output->indexForFloat(data, 3);
- instr.type = QDeclarativeInstruction::StoreVector3D;
- instr.storeRealPair.propertyIndex = prop.propertyIndex();
- instr.storeRealPair.valueIndex = index;
+ QVector3D vector = QDeclarativeStringConverters::vector3DFromString(string, &ok);
+ instr.setType(QDeclarativeInstruction::StoreVector3D);
+ instr.storeVector3D.propertyIndex = prop.propertyIndex();
+ instr.storeVector3D.vector.xp = vector.x();
+ instr.storeVector3D.vector.yp = vector.y();
+ instr.storeVector3D.vector.zp = vector.z();
}
break;
default:
{
int t = prop.userType();
- int index = output->customTypeData.count();
- instr.type = QDeclarativeInstruction::AssignCustomType;
+ instr.setType(QDeclarativeInstruction::AssignCustomType);
instr.assignCustomType.propertyIndex = prop.propertyIndex();
- instr.assignCustomType.valueIndex = index;
-
- QDeclarativeCompiledData::CustomTypeData data;
- data.index = output->indexForString(string);
- data.type = t;
- output->customTypeData << data;
+ instr.assignCustomType.primitive = output->indexForString(string);
+ instr.assignCustomType.type = t;
}
break;
}
- output->bytecode << instr;
+ output->addInstruction(instr);
}
/*!
@@ -542,9 +573,6 @@ void QDeclarativeCompiler::reset(QDeclarativeCompiledData *data)
{
data->types.clear();
data->primitives.clear();
- data->floatData.clear();
- data->intData.clear();
- data->customTypeData.clear();
data->datas.clear();
data->bytecode.clear();
}
@@ -642,12 +670,35 @@ void QDeclarativeCompiler::compileTree(QDeclarativeParser::Object *tree)
compileState.root = tree;
componentStat.lineNumber = tree->location.start.line;
+ // Build global import scripts
+ QStringList importedScriptIndexes;
+
+ foreach (const QDeclarativeTypeData::ScriptReference &script, unit->resolvedScripts()) {
+ importedScriptIndexes.append(script.qualifier);
+
+ QDeclarativeInstruction import;
+ import.setType(QDeclarativeInstruction::StoreImportedScript);
+ import.storeScript.value = output->scripts.count();
+
+ QDeclarativeScriptData *scriptData = script.script->scriptData();
+ scriptData->addref();
+ output->scripts << scriptData;
+ output->addInstruction(import);
+ }
+
+ // 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 QDeclarativeTypeNameCache(engine);
+ for (int ii = 0; ii < importedScriptIndexes.count(); ++ii)
+ output->importCache->add(importedScriptIndexes.at(ii), ii);
+ unit->imports().populateCache(output->importCache, engine);
+
if (!buildObject(tree, BindingContext()) || !completeComponentBuild())
return;
QDeclarativeInstruction init;
- init.type = QDeclarativeInstruction::Init;
- init.line = 0;
+ init.setType(QDeclarativeInstruction::Init);
init.init.bindingsSize = compileState.bindings.count();
init.init.parserStatusSize = compileState.parserStatusCount;
init.init.contextCache = genContextCache();
@@ -655,53 +706,17 @@ void QDeclarativeCompiler::compileTree(QDeclarativeParser::Object *tree)
init.init.compiledBinding = -1;
else
init.init.compiledBinding = output->indexForByteArray(compileState.compiledBindingData);
- output->bytecode << init;
-
- // Build global import scripts
- QHash<QString, Object::ScriptBlock> importedScripts;
- QStringList importedScriptIndexes;
-
- foreach (const QDeclarativeTypeData::ScriptReference &script, unit->resolvedScripts()) {
- QString scriptCode = script.script->scriptSource();
- Object::ScriptBlock::Pragmas pragmas = script.script->pragmas();
-
- Q_ASSERT(!importedScripts.contains(script.qualifier));
-
- if (!scriptCode.isEmpty()) {
- Object::ScriptBlock &scriptBlock = importedScripts[script.qualifier];
-
- scriptBlock.code = scriptCode;
- scriptBlock.file = script.script->finalUrl().toString();
- scriptBlock.pragmas = pragmas;
- }
- }
-
- for (QHash<QString, Object::ScriptBlock>::Iterator iter = importedScripts.begin();
- iter != importedScripts.end(); ++iter) {
-
- importedScriptIndexes.append(iter.key());
-
- QDeclarativeInstruction import;
- import.type = QDeclarativeInstruction::StoreImportedScript;
- import.line = 0;
- import.storeScript.value = output->scripts.count();
- output->scripts << *iter;
- output->bytecode << import;
- }
+ output->addInstruction(init);
genObject(tree);
QDeclarativeInstruction def;
- init.line = 0;
- def.type = QDeclarativeInstruction::SetDefault;
- output->bytecode << def;
-
- output->importCache = new QDeclarativeTypeNameCache(engine);
+ def.setType(QDeclarativeInstruction::SetDefault);
+ output->addInstruction(def);
- for (int ii = 0; ii < importedScriptIndexes.count(); ++ii)
- output->importCache->add(importedScriptIndexes.at(ii), ii);
-
- unit->imports().populateCache(output->importCache, engine);
+ QDeclarativeInstruction done;
+ done.setType(QDeclarativeInstruction::Done);
+ output->addInstruction(done);
Q_ASSERT(tree->metatype);
@@ -909,19 +924,19 @@ void QDeclarativeCompiler::genObject(QDeclarativeParser::Object *obj)
!output->types.at(obj->type).type->isExtendedType() && obj != compileState.root) {
QDeclarativeInstruction create;
- create.type = QDeclarativeInstruction::CreateSimpleObject;
- create.line = obj->location.start.line;
+ create.setType(QDeclarativeInstruction::CreateSimpleObject);
create.createSimple.create = output->types.at(obj->type).type->createFunction();
create.createSimple.typeSize = output->types.at(obj->type).type->createSize();
create.createSimple.type = obj->type;
+ create.createSimple.line = obj->location.start.line;
create.createSimple.column = obj->location.start.column;
- output->bytecode << create;
+ output->addInstruction(create);
} else {
QDeclarativeInstruction create;
- create.type = QDeclarativeInstruction::CreateObject;
- create.line = obj->location.start.line;
+ create.setType(QDeclarativeInstruction::CreateObject);
+ create.create.line = obj->location.start.line;
create.create.column = obj->location.start.column;
create.create.data = -1;
if (!obj->custom.isEmpty())
@@ -935,15 +950,14 @@ void QDeclarativeCompiler::genObject(QDeclarativeParser::Object *obj)
} else {
create.create.bindingBits = -1;
}
- output->bytecode << create;
+ output->addInstruction(create);
}
// Setup the synthesized meta object if necessary
if (!obj->metadata.isEmpty()) {
QDeclarativeInstruction meta;
- meta.type = QDeclarativeInstruction::StoreMetaObject;
- meta.line = 0;
+ meta.setType(QDeclarativeInstruction::StoreMetaObject);
meta.storeMeta.data = output->indexForByteArray(obj->metadata);
meta.storeMeta.aliasData = output->indexForByteArray(obj->synthdata);
meta.storeMeta.propertyCache = output->propertyCaches.count();
@@ -968,7 +982,7 @@ void QDeclarativeCompiler::genObject(QDeclarativeParser::Object *obj)
}
output->propertyCaches << propertyCache;
- output->bytecode << meta;
+ output->addInstruction(meta);
} else if (obj == unitRoot) {
output->rootPropertyCache = tr.createPropertyCache(engine);
output->rootPropertyCache->addref();
@@ -977,20 +991,18 @@ void QDeclarativeCompiler::genObject(QDeclarativeParser::Object *obj)
// Set the object id
if (!obj->id.isEmpty()) {
QDeclarativeInstruction id;
- id.type = QDeclarativeInstruction::SetId;
- id.line = 0;
+ id.setType(QDeclarativeInstruction::SetId);
id.setId.value = output->indexForString(obj->id);
id.setId.index = obj->idIndex;
- output->bytecode << id;
+ output->addInstruction(id);
}
// Begin the class
if (tr.type && obj->parserStatusCast != -1) {
QDeclarativeInstruction begin;
- begin.type = QDeclarativeInstruction::BeginObject;
+ begin.setType(QDeclarativeInstruction::BeginObject);
begin.begin.castValue = obj->parserStatusCast;
- begin.line = obj->location.start.line;
- output->bytecode << begin;
+ output->addInstruction(begin);
}
genObjectBody(obj);
@@ -1001,12 +1013,12 @@ void QDeclarativeCompiler::genObjectBody(QDeclarativeParser::Object *obj)
typedef QPair<Property *, int> PropPair;
foreach(const PropPair &prop, obj->scriptStringProperties) {
QDeclarativeInstruction ss;
- ss.type = QDeclarativeInstruction::StoreScriptString;
+ ss.setType(QDeclarativeInstruction::StoreScriptString);
ss.storeScriptString.propertyIndex = prop.first->index;
ss.storeScriptString.value =
output->indexForString(prop.first->values.at(0)->value.asScript());
ss.storeScriptString.scope = prop.second;
- output->bytecode << ss;
+ output->addInstruction(ss);
}
bool seenDefer = false;
@@ -1020,19 +1032,18 @@ void QDeclarativeCompiler::genObjectBody(QDeclarativeParser::Object *obj)
}
if (seenDefer) {
QDeclarativeInstruction defer;
- defer.type = QDeclarativeInstruction::Defer;
- defer.line = 0;
+ defer.setType(QDeclarativeInstruction::Defer);
defer.defer.deferCount = 0;
- int deferIdx = output->bytecode.count();
- output->bytecode << defer;
+ int deferIdx = output->addInstruction(defer);
+ int nextInstructionIndex = output->nextInstructionIndex();
QDeclarativeInstruction init;
- init.type = QDeclarativeInstruction::Init;
+ init.setType(QDeclarativeInstruction::Init);
init.init.bindingsSize = compileState.bindings.count(); // XXX - bigger than necessary
init.init.parserStatusSize = compileState.parserStatusCount; // XXX - bigger than necessary
init.init.contextCache = -1;
init.init.compiledBinding = -1;
- output->bytecode << init;
+ output->addInstruction(init);
foreach(Property *prop, obj->valueProperties) {
if (!prop->isDeferred)
@@ -1040,8 +1051,11 @@ void QDeclarativeCompiler::genObjectBody(QDeclarativeParser::Object *obj)
genValueProperty(prop, obj);
}
- output->bytecode[deferIdx].defer.deferCount =
- output->bytecode.count() - deferIdx - 1;
+ QDeclarativeInstruction done;
+ done.setType(QDeclarativeInstruction::Done);
+ output->addInstruction(done);
+
+ output->instruction(deferIdx)->defer.deferCount = output->nextInstructionIndex() - nextInstructionIndex;
}
foreach(Property *prop, obj->signalProperties) {
@@ -1053,25 +1067,25 @@ void QDeclarativeCompiler::genObjectBody(QDeclarativeParser::Object *obj)
genObject(v->object);
QDeclarativeInstruction assign;
- assign.type = QDeclarativeInstruction::AssignSignalObject;
- assign.line = v->location.start.line;
+ assign.setType(QDeclarativeInstruction::AssignSignalObject);
+ assign.assignSignalObject.line = v->location.start.line;
assign.assignSignalObject.signal =
output->indexForByteArray(prop->name);
- output->bytecode << assign;
+ output->addInstruction(assign);
} else if (v->type == Value::SignalExpression) {
BindingContext ctxt = compileState.signalExpressions.value(v);
QDeclarativeInstruction store;
- store.type = QDeclarativeInstruction::StoreSignal;
- store.line = v->location.start.line;
+ store.setType(QDeclarativeInstruction::StoreSignal);
store.storeSignal.signalIndex = prop->index;
store.storeSignal.value =
output->indexForString(v->value.asScript().trimmed());
store.storeSignal.context = ctxt.stack;
store.storeSignal.name = output->indexForByteArray(prop->name);
- output->bytecode << store;
+ store.storeSignal.line = v->location.start.line;
+ output->addInstruction(store);
}
@@ -1079,42 +1093,39 @@ void QDeclarativeCompiler::genObjectBody(QDeclarativeParser::Object *obj)
foreach(Property *prop, obj->attachedProperties) {
QDeclarativeInstruction fetch;
- fetch.type = QDeclarativeInstruction::FetchAttached;
- fetch.line = prop->location.start.line;
+ fetch.setType(QDeclarativeInstruction::FetchAttached);
fetch.fetchAttached.id = prop->index;
- output->bytecode << fetch;
+ fetch.fetchAttached.line = prop->location.start.line;
+ output->addInstruction(fetch);
genObjectBody(prop->value);
QDeclarativeInstruction pop;
- pop.type = QDeclarativeInstruction::PopFetchedObject;
- pop.line = prop->location.start.line;
- output->bytecode << pop;
+ pop.setType(QDeclarativeInstruction::PopFetchedObject);
+ output->addInstruction(pop);
}
foreach(Property *prop, obj->groupedProperties) {
QDeclarativeInstruction fetch;
- fetch.type = QDeclarativeInstruction::FetchObject;
+ fetch.setType(QDeclarativeInstruction::FetchObject);
fetch.fetch.property = prop->index;
- fetch.line = prop->location.start.line;
- output->bytecode << fetch;
+ fetch.fetch.line = prop->location.start.line;
+ output->addInstruction(fetch);
if (!prop->value->metadata.isEmpty()) {
QDeclarativeInstruction meta;
- meta.type = QDeclarativeInstruction::StoreMetaObject;
- meta.line = 0;
+ meta.setType(QDeclarativeInstruction::StoreMetaObject);
meta.storeMeta.data = output->indexForByteArray(prop->value->metadata);
meta.storeMeta.aliasData = output->indexForByteArray(prop->value->synthdata);
meta.storeMeta.propertyCache = -1;
- output->bytecode << meta;
+ output->addInstruction(meta);
}
genObjectBody(prop->value);
QDeclarativeInstruction pop;
- pop.type = QDeclarativeInstruction::PopFetchedObject;
- pop.line = prop->location.start.line;
- output->bytecode << pop;
+ pop.setType(QDeclarativeInstruction::PopFetchedObject);
+ output->addInstruction(pop);
}
foreach(Property *prop, obj->valueTypeProperties) {
@@ -1138,11 +1149,10 @@ void QDeclarativeCompiler::genObjectBody(QDeclarativeParser::Object *obj)
void QDeclarativeCompiler::genValueTypeProperty(QDeclarativeParser::Object *obj,QDeclarativeParser::Property *prop)
{
QDeclarativeInstruction fetch;
- fetch.type = QDeclarativeInstruction::FetchValueType;
+ fetch.setType(QDeclarativeInstruction::FetchValueType);
fetch.fetchValue.property = prop->index;
fetch.fetchValue.type = prop->type;
fetch.fetchValue.bindingSkipList = 0;
- fetch.line = prop->location.start.line;
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
@@ -1155,19 +1165,18 @@ void QDeclarativeCompiler::genValueTypeProperty(QDeclarativeParser::Object *obj,
}
}
- output->bytecode << fetch;
+ output->addInstruction(fetch);
foreach(Property *vprop, prop->value->valueProperties) {
genPropertyAssignment(vprop, prop->value, prop);
}
QDeclarativeInstruction pop;
- pop.type = QDeclarativeInstruction::PopValueType;
+ pop.setType(QDeclarativeInstruction::PopValueType);
pop.fetchValue.property = prop->index;
pop.fetchValue.type = prop->type;
pop.fetchValue.bindingSkipList = 0;
- pop.line = prop->location.start.line;
- output->bytecode << pop;
+ output->addInstruction(pop);
}
void QDeclarativeCompiler::genComponent(QDeclarativeParser::Object *obj)
@@ -1176,18 +1185,18 @@ void QDeclarativeCompiler::genComponent(QDeclarativeParser::Object *obj)
Q_ASSERT(root);
QDeclarativeInstruction create;
- create.type = QDeclarativeInstruction::CreateComponent;
- create.line = root->location.start.line;
+ create.setType(QDeclarativeInstruction::CreateComponent);
+ create.createComponent.line = root->location.start.line;
create.createComponent.column = root->location.start.column;
create.createComponent.endLine = root->location.end.line;
- output->bytecode << create;
- int count = output->bytecode.count();
+ int createInstruction = output->addInstruction(create);
+ int nextInstructionIndex = output->nextInstructionIndex();
ComponentCompileState oldCompileState = compileState;
compileState = componentState(root);
QDeclarativeInstruction init;
- init.type = QDeclarativeInstruction::Init;
+ init.setType(QDeclarativeInstruction::Init);
init.init.bindingsSize = compileState.bindings.count();
init.init.parserStatusSize = compileState.parserStatusCount;
init.init.contextCache = genContextCache();
@@ -1195,28 +1204,29 @@ void QDeclarativeCompiler::genComponent(QDeclarativeParser::Object *obj)
init.init.compiledBinding = -1;
else
init.init.compiledBinding = output->indexForByteArray(compileState.compiledBindingData);
- init.line = obj->location.start.line;
- output->bytecode << init;
+ output->addInstruction(init);
genObject(root);
QDeclarativeInstruction def;
- init.line = 0;
- def.type = QDeclarativeInstruction::SetDefault;
- output->bytecode << def;
+ def.setType(QDeclarativeInstruction::SetDefault);
+ output->addInstruction(def);
+
+ QDeclarativeInstruction done;
+ done.setType(QDeclarativeInstruction::Done);
+ output->addInstruction(done);
- output->bytecode[count - 1].createComponent.count =
- output->bytecode.count() - count;
+ output->instruction(createInstruction)->createComponent.count =
+ output->nextInstructionIndex() - nextInstructionIndex;
compileState = oldCompileState;
if (!obj->id.isEmpty()) {
QDeclarativeInstruction id;
- id.type = QDeclarativeInstruction::SetId;
- id.line = 0;
+ id.setType(QDeclarativeInstruction::SetId);
id.setId.value = output->indexForString(obj->id);
id.setId.index = obj->idIndex;
- output->bytecode << id;
+ output->addInstruction(id);
}
}
@@ -1283,6 +1293,7 @@ bool QDeclarativeCompiler::buildComponentFromRoot(QDeclarativeParser::Object *ob
compileState = ComponentCompileState();
compileState.root = obj;
+ compileState.nested = true;
componentStat = ComponentStat();
componentStat.lineNumber = obj->location.start.line;
@@ -1342,8 +1353,15 @@ bool QDeclarativeCompiler::buildSignal(QDeclarativeParser::Property *prop, QDecl
QByteArray name = prop->name;
Q_ASSERT(name.startsWith("on"));
name = name.mid(2);
- if(name[0] >= 'A' && name[0] <= 'Z')
- name[0] = name[0] - 'A' + 'a';
+
+ // 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[firstAlphaIndex] >= 'A' && name[firstAlphaIndex] <= 'Z') {
+ name[firstAlphaIndex] = name[firstAlphaIndex] - 'A' + 'a';
+ break;
+ }
+ }
bool notInRevision = false;
int sigIdx = indexOfSignal(obj, name, &notInRevision);
@@ -1442,8 +1460,6 @@ bool QDeclarativeCompiler::buildProperty(QDeclarativeParser::Property *prop,
unit->imports().resolveType(prop->name, &type, 0, 0, 0, &typeNamespace);
if (typeNamespace) {
- // ### We might need to indicate that this property is a namespace
- // for the DOM API
COMPILE_CHECK(buildPropertyInNamespace(typeNamespace, prop, obj,
ctxt));
return true;
@@ -1607,12 +1623,11 @@ void QDeclarativeCompiler::genListProperty(QDeclarativeParser::Property *prop,
int listType = enginePrivate->listType(prop->type);
QDeclarativeInstruction fetch;
- fetch.type = QDeclarativeInstruction::FetchQList;
- fetch.line = prop->location.start.line;
+ fetch.setType(QDeclarativeInstruction::FetchQList);
fetch.fetchQmlList.property = prop->index;
bool listTypeIsInterface = QDeclarativeMetaType::isInterface(listType);
fetch.fetchQmlList.type = listType;
- output->bytecode << fetch;
+ output->addInstruction(fetch);
for (int ii = 0; ii < prop->values.count(); ++ii) {
QDeclarativeParser::Value *v = prop->values.at(ii);
@@ -1622,14 +1637,13 @@ void QDeclarativeCompiler::genListProperty(QDeclarativeParser::Property *prop,
genObject(v->object);
if (listTypeIsInterface) {
QDeclarativeInstruction assign;
- assign.type = QDeclarativeInstruction::AssignObjectList;
- assign.line = prop->location.start.line;
- output->bytecode << assign;
+ assign.setType(QDeclarativeInstruction::AssignObjectList);
+ assign.assignObjectList.line = prop->location.start.line;
+ output->addInstruction(assign);
} else {
QDeclarativeInstruction store;
- store.type = QDeclarativeInstruction::StoreObjectQList;
- store.line = prop->location.start.line;
- output->bytecode << store;
+ store.setType(QDeclarativeInstruction::StoreObjectQList);
+ output->addInstruction(store);
}
} else if (v->type == Value::PropertyBinding) {
@@ -1641,9 +1655,8 @@ void QDeclarativeCompiler::genListProperty(QDeclarativeParser::Property *prop,
}
QDeclarativeInstruction pop;
- pop.type = QDeclarativeInstruction::PopQList;
- pop.line = prop->location.start.line;
- output->bytecode << pop;
+ pop.setType(QDeclarativeInstruction::PopQList);
+ output->addInstruction(pop);
}
void QDeclarativeCompiler::genPropertyAssignment(QDeclarativeParser::Property *prop,
@@ -1664,26 +1677,26 @@ void QDeclarativeCompiler::genPropertyAssignment(QDeclarativeParser::Property *p
if (QDeclarativeMetaType::isInterface(prop->type)) {
QDeclarativeInstruction store;
- store.type = QDeclarativeInstruction::StoreInterface;
- store.line = v->object->location.start.line;
+ store.setType(QDeclarativeInstruction::StoreInterface);
+ store.storeObject.line = v->object->location.start.line;
store.storeObject.propertyIndex = prop->index;
- output->bytecode << store;
+ output->addInstruction(store);
} else if (prop->type == -1) {
QDeclarativeInstruction store;
- store.type = QDeclarativeInstruction::StoreVariantObject;
- store.line = v->object->location.start.line;
+ store.setType(QDeclarativeInstruction::StoreVariantObject);
+ store.storeObject.line = v->object->location.start.line;
store.storeObject.propertyIndex = prop->index;
- output->bytecode << store;
+ output->addInstruction(store);
} else {
QDeclarativeInstruction store;
- store.type = QDeclarativeInstruction::StoreObject;
- store.line = v->object->location.start.line;
+ store.setType(QDeclarativeInstruction::StoreObject);
+ store.storeObject.line = v->object->location.start.line;
store.storeObject.propertyIndex = prop->index;
- output->bytecode << store;
+ output->addInstruction(store);
}
} else if (v->type == Value::PropertyBinding) {
@@ -1710,8 +1723,7 @@ void QDeclarativeCompiler::genPropertyAssignment(QDeclarativeParser::Property *p
genObject(v->object);
QDeclarativeInstruction store;
- store.type = QDeclarativeInstruction::StoreValueSource;
- store.line = v->object->location.start.line;
+ store.setType(QDeclarativeInstruction::StoreValueSource);
if (valueTypeProperty) {
store.assignValueSource.property = genValueTypeData(prop, valueTypeProperty);
store.assignValueSource.owner = 1;
@@ -1721,14 +1733,13 @@ void QDeclarativeCompiler::genPropertyAssignment(QDeclarativeParser::Property *p
}
QDeclarativeType *valueType = toQmlType(v->object);
store.assignValueSource.castValue = valueType->propertyValueSourceCast();
- output->bytecode << store;
+ output->addInstruction(store);
} else if (v->type == Value::ValueInterceptor) {
genObject(v->object);
QDeclarativeInstruction store;
- store.type = QDeclarativeInstruction::StoreValueInterceptor;
- store.line = v->object->location.start.line;
+ store.setType(QDeclarativeInstruction::StoreValueInterceptor);
if (valueTypeProperty) {
store.assignValueInterceptor.property = genValueTypeData(prop, valueTypeProperty);
store.assignValueInterceptor.owner = 1;
@@ -1738,7 +1749,7 @@ void QDeclarativeCompiler::genPropertyAssignment(QDeclarativeParser::Property *p
}
QDeclarativeType *valueType = toQmlType(v->object);
store.assignValueInterceptor.castValue = valueType->propertyValueInterceptorCast();
- output->bytecode << store;
+ output->addInstruction(store);
}
}
@@ -2227,20 +2238,35 @@ bool QDeclarativeCompiler::testQualifiedEnumAssignment(const QMetaProperty &prop
objTypeName = objType->qmlTypeName();
}
- if (!type || objTypeName != type->qmlTypeName())
+ if (!type)
return true;
QString enumValue = parts.at(1);
- int value;
- if (prop.isFlagType()) {
- value = prop.enumerator().keysToValue(enumValue.toUtf8().constData());
- } else
- value = prop.enumerator().keyToValue(enumValue.toUtf8().constData());
+ int value = -1;
+
+ if (objTypeName == type->qmlTypeName()) {
+ // When these two match, we can short cut the search
+ if (prop.isFlagType()) {
+ value = prop.enumerator().keysToValue(enumValue.toUtf8().constData());
+ } else {
+ value = prop.enumerator().keyToValue(enumValue.toUtf8().constData());
+ }
+ } else {
+ // Otherwise we have to search the whole type
+ // This matches the logic in QDeclarativeTypeNameScriptClass
+ QByteArray enumName = enumValue.toUtf8();
+ const QMetaObject *metaObject = type->baseMetaObject();
+ for (int ii = metaObject->enumeratorCount() - 1; value == -1 && ii >= 0; --ii) {
+ QMetaEnum e = metaObject->enumerator(ii);
+ value = e.keyToValue(enumName.constData());
+ }
+ }
+
if (value == -1)
return true;
v->type = Value::Literal;
- v->value = QDeclarativeParser::Variant(enumValue);
+ v->value = QDeclarativeParser::Variant((double)value);
*isAssignment = true;
return true;
@@ -2412,7 +2438,7 @@ bool QDeclarativeCompiler::buildDynamicMeta(QDeclarativeParser::Object *obj, Dyn
newClassName.append("_QML_");
int idx = classIndexCounter()->fetchAndAddRelaxed(1);
newClassName.append(QByteArray::number(idx));
- if (compileState.root == obj) {
+ if (compileState.root == obj && !compileState.nested) {
QString path = output->url.path();
int lastSlash = path.lastIndexOf(QLatin1Char('/'));
if (lastSlash > -1) {
@@ -2810,7 +2836,7 @@ void QDeclarativeCompiler::genBindingAssignment(QDeclarativeParser::Value *bindi
const BindingReference &ref = compileState.bindings.value(binding);
if (ref.dataType == BindingReference::Experimental) {
QDeclarativeInstruction store;
- store.type = QDeclarativeInstruction::StoreCompiledBinding;
+ store.setType(QDeclarativeInstruction::StoreCompiledBinding);
store.assignBinding.value = ref.compiledIndex;
store.assignBinding.context = ref.bindingContext.stack;
store.assignBinding.owner = ref.bindingContext.owner;
@@ -2820,20 +2846,20 @@ void QDeclarativeCompiler::genBindingAssignment(QDeclarativeParser::Value *bindi
((prop->index & 0xFF) << 24);
else
store.assignBinding.property = prop->index;
- store.line = binding->location.start.line;
- output->bytecode << store;
+ store.assignBinding.line = binding->location.start.line;
+ output->addInstruction(store);
return;
}
QDeclarativeInstruction store;
if (!prop->isAlias)
- store.type = QDeclarativeInstruction::StoreBinding;
+ store.setType(QDeclarativeInstruction::StoreBinding);
else
- store.type = QDeclarativeInstruction::StoreBindingOnAlias;
+ store.setType(QDeclarativeInstruction::StoreBindingOnAlias);
store.assignBinding.value = output->indexForByteArray(ref.compiledData);
store.assignBinding.context = ref.bindingContext.stack;
store.assignBinding.owner = ref.bindingContext.owner;
- store.line = binding->location.start.line;
+ store.assignBinding.line = binding->location.start.line;
Q_ASSERT(ref.bindingContext.owner == 0 ||
(ref.bindingContext.owner != 0 && valueTypeProperty));
@@ -2843,7 +2869,7 @@ void QDeclarativeCompiler::genBindingAssignment(QDeclarativeParser::Value *bindi
store.assignBinding.property = genPropertyData(prop);
}
- output->bytecode << store;
+ output->addInstruction(store);
}
int QDeclarativeCompiler::genContextCache()
@@ -2888,25 +2914,26 @@ bool QDeclarativeCompiler::completeComponentBuild()
COMPILE_CHECK(buildDynamicMeta(aliasObject, ResolveAliases));
}
- QDeclarativeBindingCompiler::Expression expr;
+ QDeclarativeV4Compiler::Expression expr;
expr.component = compileState.root;
expr.ids = compileState.ids;
+ expr.importCache = output->importCache;
+ expr.imports = unit->imports();
- QDeclarativeBindingCompiler bindingCompiler;
+ QDeclarativeV4Compiler bindingCompiler;
for (QHash<QDeclarativeParser::Value*,BindingReference>::Iterator iter = compileState.bindings.begin();
iter != compileState.bindings.end(); ++iter) {
BindingReference &binding = *iter;
- expr.context = binding.bindingContext.object;
- expr.property = binding.property;
- expr.expression = binding.expression;
- expr.imports = unit->imports();
-
// ### 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::Experimental;
@@ -2947,11 +2974,8 @@ bool QDeclarativeCompiler::completeComponentBuild()
componentStat.scriptBindings.append(iter.key()->location);
}
- if (bindingCompiler.isValid()) {
+ if (bindingCompiler.isValid())
compileState.compiledBindingData = bindingCompiler.program();
- if (bindingsDump())
- QDeclarativeBindingCompiler::dump(compileState.compiledBindingData);
- }
saveComponentState();
diff --git a/src/declarative/qml/qdeclarativecompiler_p.h b/src/declarative/qml/qdeclarativecompiler_p.h
index bcc0b298a8..e4b9240a93 100644
--- a/src/declarative/qml/qdeclarativecompiler_p.h
+++ b/src/declarative/qml/qdeclarativecompiler_p.h
@@ -102,31 +102,26 @@ public:
QDeclarativePropertyCache *createPropertyCache(QDeclarativeEngine *);
};
QList<TypeReference> types;
- struct CustomTypeData
- {
- int index;
- int type;
- };
const QMetaObject *root;
QAbstractDynamicMetaObject rootData;
QDeclarativePropertyCache *rootPropertyCache;
QList<QString> primitives;
- QList<float> floatData;
- QList<int> intData;
- QList<CustomTypeData> customTypeData;
QList<QByteArray> datas;
- QList<QDeclarativeParser::Location> locations;
- QList<QDeclarativeInstruction> bytecode;
+ QByteArray bytecode;
QList<QScriptProgram *> cachedPrograms;
QList<QScriptValue *> cachedClosures;
QList<QDeclarativePropertyCache *> propertyCaches;
QList<QDeclarativeIntegerCache *> contextCaches;
- QList<QDeclarativeParser::Object::ScriptBlock> scripts;
+ QList<QDeclarativeScriptData *> scripts;
QList<QUrl> urls;
void dumpInstructions();
+ int addInstruction(const QDeclarativeInstruction &instr);
+ int nextInstructionIndex();
+ QDeclarativeInstruction *instruction(int index);
+
protected:
virtual void clear(); // From QDeclarativeCleanup
@@ -140,10 +135,6 @@ private:
int indexForString(const QString &);
int indexForByteArray(const QByteArray &);
- int indexForFloat(float *, int);
- int indexForInt(int *, int);
- int indexForLocation(const QDeclarativeParser::Location &);
- int indexForLocation(const QDeclarativeParser::LocationSpan &);
int indexForUrl(const QUrl &);
};
@@ -305,11 +296,12 @@ private:
struct ComponentCompileState
{
ComponentCompileState()
- : parserStatusCount(0), pushedProperties(0), root(0) {}
+ : parserStatusCount(0), pushedProperties(0), nested(false), root(0) {}
QHash<QString, QDeclarativeParser::Object *> ids;
QHash<int, QDeclarativeParser::Object *> idIndexes;
int parserStatusCount;
int pushedProperties;
+ bool nested;
QByteArray compiledBindingData;
diff --git a/src/declarative/qml/qdeclarativecomponent.cpp b/src/declarative/qml/qdeclarativecomponent.cpp
index d9f291ba64..01e2434f76 100644
--- a/src/declarative/qml/qdeclarativecomponent.cpp
+++ b/src/declarative/qml/qdeclarativecomponent.cpp
@@ -455,7 +455,7 @@ QDeclarativeComponent::QDeclarativeComponent(QDeclarativeEngine *engine, const Q
/*!
\internal
*/
-QDeclarativeComponent::QDeclarativeComponent(QDeclarativeEngine *engine, QDeclarativeCompiledData *cc, int start, int count, QObject *parent)
+QDeclarativeComponent::QDeclarativeComponent(QDeclarativeEngine *engine, QDeclarativeCompiledData *cc, int start, QObject *parent)
: QObject(*(new QDeclarativeComponentPrivate), parent)
{
Q_D(QDeclarativeComponent);
@@ -463,7 +463,6 @@ QDeclarativeComponent::QDeclarativeComponent(QDeclarativeEngine *engine, QDeclar
d->cc = cc;
cc->addref();
d->start = start;
- d->count = count;
d->url = cc->url;
d->progress = 1.0;
}
@@ -833,12 +832,40 @@ QDeclarativeComponentPrivate::beginCreate(QDeclarativeContextData *context, cons
return 0;
}
- return begin(context, creationContext, cc, start, count, &state, 0, bindings);
+ return begin(context, creationContext, cc, start, &state, 0, bindings);
+}
+
+/*
+ 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('*'));
+ QDeclarativeType *type = QDeclarativeMetaType::qmlType(metaObject);
+ QString typeName = type ? QLatin1String(type->qmlTypeName()) : QLatin1String(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 = QDeclarativeMetaType::qmlType(QMetaType::type(className.toLatin1()));
+ if (type)
+ typeName = QLatin1String(type->qmlTypeName());
+ }
+ }
+ }
+ return typeName;
}
QObject * QDeclarativeComponentPrivate::begin(QDeclarativeContextData *parentContext,
QDeclarativeContextData *componentCreationContext,
- QDeclarativeCompiledData *component, int start, int count,
+ QDeclarativeCompiledData *component, int start,
ConstructionState *state, QList<QDeclarativeError> *errors,
const QBitField &bindings)
{
@@ -848,10 +875,8 @@ QObject * QDeclarativeComponentPrivate::begin(QDeclarativeContextData *parentCon
Q_ASSERT(!isRoot || state); // Either this isn't a root component, or a state data must be provided
Q_ASSERT((state != 0) ^ (errors != 0)); // One of state or errors (but not both) must be provided
- if (isRoot) {
+ if (isRoot)
QDeclarativeDebugTrace::startRange(QDeclarativeDebugTrace::Creating);
- QDeclarativeDebugTrace::rangeData(QDeclarativeDebugTrace::Creating, component->url);
- }
QDeclarativeContextData *ctxt = new QDeclarativeContextData;
ctxt->isInternal = true;
@@ -868,7 +893,9 @@ QObject * QDeclarativeComponentPrivate::begin(QDeclarativeContextData *parentCon
enginePriv->inBeginCreate = true;
QDeclarativeVME vme;
- QObject *rv = vme.run(ctxt, component, start, count, bindings);
+ enginePriv->referenceScarceResources(); // "hold" scarce resources in memory during evaluation.
+ QObject *rv = vme.run(ctxt, component, start, bindings);
+ enginePriv->dereferenceScarceResources(); // "release" scarce resources if top-level expression evaluation is complete.
if (vme.isError()) {
if(errors) *errors = vme.errors();
@@ -897,6 +924,11 @@ QObject * QDeclarativeComponentPrivate::begin(QDeclarativeContextData *parentCon
if (!parentContext->isInternal)
parentContext->asQDeclarativeContextPrivate()->instances.append(rv);
QDeclarativeEngineDebugServer::instance()->objectCreated(parentContext->engine, rv);
+ if (isRoot) {
+ QDeclarativeDebugTrace::rangeData(QDeclarativeDebugTrace::Creating, buildTypeNameForDebug(rv->metaObject()));
+ QDeclarativeData *data = QDeclarativeData::get(rv);
+ QDeclarativeDebugTrace::rangeLocation(QDeclarativeDebugTrace::Creating, component->url, data ? data->lineNumber : -1);
+ }
}
return rv;
diff --git a/src/declarative/qml/qdeclarativecomponent.h b/src/declarative/qml/qdeclarativecomponent.h
index ab007e8bd8..15004a6cb1 100644
--- a/src/declarative/qml/qdeclarativecomponent.h
+++ b/src/declarative/qml/qdeclarativecomponent.h
@@ -96,13 +96,14 @@ public:
virtual QObject *beginCreate(QDeclarativeContext *);
virtual void completeCreate();
- void loadUrl(const QUrl &url);
- void setData(const QByteArray &, const QUrl &baseUrl);
-
QDeclarativeContext *creationContext() const;
static QDeclarativeComponentAttached *qmlAttachedProperties(QObject *);
+public Q_SLOTS:
+ void loadUrl(const QUrl &url);
+ void setData(const QByteArray &, const QUrl &baseUrl);
+
Q_SIGNALS:
void statusChanged(QDeclarativeComponent::Status);
void progressChanged(qreal);
@@ -113,11 +114,10 @@ protected:
Q_INVOKABLE Q_REVISION(1) QScriptValue createObject(QObject* parent, const QScriptValue& valuemap); //XXX Versioning
private:
- QDeclarativeComponent(QDeclarativeEngine *, QDeclarativeCompiledData *, int, int, QObject *parent);
+ QDeclarativeComponent(QDeclarativeEngine *, QDeclarativeCompiledData *, int, QObject *parent);
Q_DISABLE_COPY(QDeclarativeComponent)
friend class QDeclarativeVME;
- friend class QDeclarativeCompositeTypeData;
friend class QDeclarativeTypeData;
};
diff --git a/src/declarative/qml/qdeclarativecomponent_p.h b/src/declarative/qml/qdeclarativecomponent_p.h
index f30691b536..ef04a5e137 100644
--- a/src/declarative/qml/qdeclarativecomponent_p.h
+++ b/src/declarative/qml/qdeclarativecomponent_p.h
@@ -79,7 +79,7 @@ class Q_AUTOTEST_EXPORT QDeclarativeComponentPrivate : public QObjectPrivate, pu
Q_DECLARE_PUBLIC(QDeclarativeComponent)
public:
- QDeclarativeComponentPrivate() : typeData(0), progress(0.), start(-1), count(-1), cc(0), engine(0), creationContext(0) {}
+ QDeclarativeComponentPrivate() : typeData(0), progress(0.), start(-1), cc(0), engine(0), creationContext(0) {}
QObject *beginCreate(QDeclarativeContextData *, const QBitField &);
void completeCreate();
@@ -94,7 +94,6 @@ public:
qreal progress;
int start;
- int count;
QDeclarativeCompiledData *cc;
struct ConstructionState {
@@ -109,7 +108,7 @@ public:
ConstructionState state;
static QObject *begin(QDeclarativeContextData *parentContext, QDeclarativeContextData *componentCreationContext,
- QDeclarativeCompiledData *component, int start, int count,
+ QDeclarativeCompiledData *component, int start,
ConstructionState *state, QList<QDeclarativeError> *errors,
const QBitField &bindings = QBitField());
static void beginDeferred(QDeclarativeEnginePrivate *enginePriv, QObject *object,
diff --git a/src/declarative/qml/qdeclarativecontext.cpp b/src/declarative/qml/qdeclarativecontext.cpp
index d57bc08d0f..c48f2ed3d4 100644
--- a/src/declarative/qml/qdeclarativecontext.cpp
+++ b/src/declarative/qml/qdeclarativecontext.cpp
@@ -46,9 +46,9 @@
#include "private/qdeclarativeexpression_p.h"
#include "private/qdeclarativeengine_p.h"
#include "qdeclarativeengine.h"
-#include "private/qdeclarativecompiledbindings_p.h"
#include "qdeclarativeinfo.h"
#include "private/qdeclarativeglobalscriptclass_p.h"
+#include "private/qdeclarativev4bindings_p.h"
#include <qscriptengine.h>
#include <QtCore/qvarlengtharray.h>
@@ -498,7 +498,7 @@ QObject *QDeclarativeContextPrivate::context_at(QDeclarativeListProperty<QObject
QDeclarativeContextData::QDeclarativeContextData()
-: parent(0), engine(0), isInternal(false), publicContext(0), propertyNames(0), contextObject(0),
+: parent(0), engine(0), isInternal(false), ownedByParent(false), publicContext(0), propertyNames(0), contextObject(0),
imports(0), childContexts(0), nextChild(0), prevChild(0), expressions(0), contextObjects(0),
contextGuards(0), idValues(0), idValueCount(0), optimizedBindings(0), linkedContext(0),
componentAttached(0)
@@ -506,7 +506,7 @@ QDeclarativeContextData::QDeclarativeContextData()
}
QDeclarativeContextData::QDeclarativeContextData(QDeclarativeContext *ctxt)
-: parent(0), engine(0), isInternal(false), publicContext(ctxt), propertyNames(0), contextObject(0),
+: parent(0), engine(0), isInternal(false), ownedByParent(false), publicContext(ctxt), propertyNames(0), contextObject(0),
imports(0), childContexts(0), nextChild(0), prevChild(0), expressions(0), contextObjects(0),
contextGuards(0), idValues(0), idValueCount(0), optimizedBindings(0), linkedContext(0),
componentAttached(0)
@@ -515,8 +515,13 @@ QDeclarativeContextData::QDeclarativeContextData(QDeclarativeContext *ctxt)
void QDeclarativeContextData::invalidate()
{
- while (childContexts)
- childContexts->invalidate();
+ while (childContexts) {
+ if (childContexts->ownedByParent) {
+ childContexts->destroy();
+ } else {
+ childContexts->invalidate();
+ }
+ }
while (componentAttached) {
QDeclarativeComponentAttached *a = componentAttached;
@@ -614,7 +619,7 @@ void QDeclarativeContextData::destroy()
delete this;
}
-void QDeclarativeContextData::setParent(QDeclarativeContextData *p)
+void QDeclarativeContextData::setParent(QDeclarativeContextData *p, bool parentTakesOwnership)
{
if (p) {
parent = p;
@@ -623,6 +628,7 @@ void QDeclarativeContextData::setParent(QDeclarativeContextData *p)
if (nextChild) nextChild->prevChild = &nextChild;
prevChild = &p->childContexts;
p->childContexts = this;
+ ownedByParent = parentTakesOwnership;
}
}
@@ -662,72 +668,6 @@ void QDeclarativeContextData::addObject(QObject *o)
contextObjects = data;
}
-void QDeclarativeContextData::addImportedScript(const QDeclarativeParser::Object::ScriptBlock &script)
-{
- if (!engine)
- return;
-
- QDeclarativeEnginePrivate *enginePriv = QDeclarativeEnginePrivate::get(engine);
- QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine);
-
- const QString &code = script.code;
- const QString &url = script.file;
- const QDeclarativeParser::Object::ScriptBlock::Pragmas &pragmas = script.pragmas;
-
- Q_ASSERT(!url.isEmpty());
-
- if (pragmas & QDeclarativeParser::Object::ScriptBlock::Shared) {
-
- QHash<QString, QScriptValue>::Iterator iter = enginePriv->m_sharedScriptImports.find(url);
- if (iter == enginePriv->m_sharedScriptImports.end()) {
- QScriptContext *scriptContext = QScriptDeclarativeClass::pushCleanContext(scriptEngine);
-
- scriptContext->pushScope(enginePriv->contextClass->newUrlContext(url));
- scriptContext->pushScope(enginePriv->globalClass->staticGlobalObject());
-
- QScriptValue scope = QScriptDeclarativeClass::newStaticScopeObject(scriptEngine);
- scriptContext->pushScope(scope);
-
- scriptEngine->evaluate(code, url, 1);
-
- if (scriptEngine->hasUncaughtException()) {
- QDeclarativeError error;
- QDeclarativeExpressionPrivate::exceptionToError(scriptEngine, error);
- enginePriv->warning(error);
- }
-
- scriptEngine->popContext();
-
- iter = enginePriv->m_sharedScriptImports.insert(url, scope);
- }
-
- importedScripts.append(*iter);
-
- } else {
-
- QScriptContext *scriptContext = QScriptDeclarativeClass::pushCleanContext(scriptEngine);
-
- scriptContext->pushScope(enginePriv->contextClass->newUrlContext(this, 0, url));
- scriptContext->pushScope(enginePriv->globalClass->staticGlobalObject());
-
- QScriptValue scope = QScriptDeclarativeClass::newStaticScopeObject(scriptEngine);
- scriptContext->pushScope(scope);
-
- scriptEngine->evaluate(code, url, 1);
-
- if (scriptEngine->hasUncaughtException()) {
- QDeclarativeError error;
- QDeclarativeExpressionPrivate::exceptionToError(scriptEngine, error);
- enginePriv->warning(error);
- }
-
- scriptEngine->popContext();
-
- importedScripts.append(scope);
-
- }
-}
-
void QDeclarativeContextData::setIdProperty(int idx, QObject *obj)
{
idValues[idx] = obj;
diff --git a/src/declarative/qml/qdeclarativecontext_p.h b/src/declarative/qml/qdeclarativecontext_p.h
index aa5f17c4f6..d7486b9653 100644
--- a/src/declarative/qml/qdeclarativecontext_p.h
+++ b/src/declarative/qml/qdeclarativecontext_p.h
@@ -77,7 +77,7 @@ class QDeclarativeEngine;
class QDeclarativeExpression;
class QDeclarativeExpressionPrivate;
class QDeclarativeAbstractExpression;
-class QDeclarativeCompiledBindings;
+class QDeclarativeV4Bindings;
class QDeclarativeContextData;
class QDeclarativeContextPrivate : public QObjectPrivate
@@ -124,7 +124,7 @@ public:
QDeclarativeContextData *parent;
QDeclarativeEngine *engine;
- void setParent(QDeclarativeContextData *);
+ void setParent(QDeclarativeContextData *, bool parentTakesOwnership = false);
void refreshExpressions();
void addObject(QObject *);
@@ -135,7 +135,9 @@ public:
// If internal is false publicContext owns this.
QDeclarativeContext *asQDeclarativeContext();
QDeclarativeContextPrivate *asQDeclarativeContextPrivate();
- bool isInternal;
+ quint32 isInternal:1;
+ quint32 ownedByParent:1; // unrelated to isInternal; parent context deletes children if true.
+ quint32 dummy:30;
QDeclarativeContext *publicContext;
// Property name cache
@@ -146,7 +148,6 @@ public:
// Any script blocks that exist on this context
QList<QScriptValue> importedScripts;
- void addImportedScript(const QDeclarativeParser::Object::ScriptBlock &script);
// Context base url
QUrl url;
@@ -188,7 +189,7 @@ public:
void setIdPropertyData(QDeclarativeIntegerCache *);
// Optimized binding pointer
- QDeclarativeCompiledBindings *optimizedBindings;
+ QDeclarativeV4Bindings *optimizedBindings;
// Linked contexts. this owns linkedContext.
QDeclarativeContextData *linkedContext;
diff --git a/src/declarative/qml/qdeclarativedirparser.cpp b/src/declarative/qml/qdeclarativedirparser.cpp
index 0a7a749c43..ba7aca038d 100644
--- a/src/declarative/qml/qdeclarativedirparser.cpp
+++ b/src/declarative/qml/qdeclarativedirparser.cpp
@@ -142,7 +142,7 @@ bool QDeclarativeDirParser::parse()
} else if (sections[0] == QLatin1String("plugin")) {
if (sectionCount < 2) {
reportError(lineNumber, -1,
- QString::fromUtf8("plugin directive requires 2 arguments, but %1 were provided").arg(sectionCount + 1));
+ QString::fromUtf8("plugin directive requires one or two arguments, but %1 were provided").arg(sectionCount - 1));
continue;
}
@@ -154,12 +154,22 @@ bool QDeclarativeDirParser::parse()
} 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));
+ 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)
@@ -189,7 +199,7 @@ bool QDeclarativeDirParser::parse()
}
} else {
reportError(lineNumber, -1,
- QString::fromUtf8("a component declaration requires 3 arguments, but %1 were provided").arg(sectionCount + 1));
+ QString::fromUtf8("a component declaration requires two or three arguments, but %1 were provided").arg(sectionCount));
}
}
@@ -229,4 +239,11 @@ QList<QDeclarativeDirParser::Component> QDeclarativeDirParser::components() cons
return _components;
}
+#ifdef QT_CREATOR
+QList<QDeclarativeDirParser::TypeInfo> QDeclarativeDirParser::typeInfos() const
+{
+ return _typeInfos;
+}
+#endif
+
QT_END_NAMESPACE
diff --git a/src/declarative/qml/qdeclarativedirparser_p.h b/src/declarative/qml/qdeclarativedirparser_p.h
index 7db7d8cd46..d40833ac45 100644
--- a/src/declarative/qml/qdeclarativedirparser_p.h
+++ b/src/declarative/qml/qdeclarativedirparser_p.h
@@ -109,6 +109,19 @@ public:
QList<Component> components() 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);
@@ -118,6 +131,9 @@ private:
QString _source;
QList<Component> _components;
QList<Plugin> _plugins;
+#ifdef QT_CREATOR
+ QList<TypeInfo> _typeInfos;
+#endif
unsigned _isParsed: 1;
};
diff --git a/src/declarative/qml/qdeclarativedom.cpp b/src/declarative/qml/qdeclarativedom.cpp
deleted file mode 100644
index ac59123f67..0000000000
--- a/src/declarative/qml/qdeclarativedom.cpp
+++ /dev/null
@@ -1,1835 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
-** All rights reserved.
-** Contact: Nokia Corporation (qt-info@nokia.com)
-**
-** This file is part of the QtDeclarative 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/qdeclarativedom_p.h"
-#include "private/qdeclarativedom_p_p.h"
-
-#include "private/qdeclarativecompiler_p.h"
-#include "private/qdeclarativeengine_p.h"
-#include "private/qdeclarativescriptparser_p.h"
-#include "private/qdeclarativeglobal_p.h"
-
-#include <QtCore/QByteArray>
-#include <QtCore/QDebug>
-#include <QtCore/QString>
-
-QT_BEGIN_NAMESPACE
-
-QDeclarativeDomDocumentPrivate::QDeclarativeDomDocumentPrivate()
-: root(0)
-{
-}
-
-QDeclarativeDomDocumentPrivate::~QDeclarativeDomDocumentPrivate()
-{
- if (root) root->release();
-}
-
-/*!
- \class QDeclarativeDomDocument
- \internal
- \brief The QDeclarativeDomDocument class represents the root of a QML document
-
- A QML document is a self-contained snippet of QML, usually contained in a
- single file. Each document has a root object, accessible through
- QDeclarativeDomDocument::rootObject().
-
- The QDeclarativeDomDocument class allows the programmer to inspect a QML document by
- calling QDeclarativeDomDocument::load().
-
- The following example loads a QML file from disk, and prints out its root
- object type and the properties assigned in the root object.
- \code
- QFile file(inputFileName);
- file.open(QIODevice::ReadOnly);
- QByteArray xmlData = file.readAll();
-
- QDeclarativeDomDocument document;
- document.load(qmlengine, xmlData);
-
- QDeclarativeDomObject rootObject = document.rootObject();
- qDebug() << rootObject.objectType();
- foreach(QDeclarativeDomProperty property, rootObject.properties())
- qDebug() << property.propertyName();
- \endcode
-*/
-
-/*!
- Construct an empty QDeclarativeDomDocument.
-*/
-QDeclarativeDomDocument::QDeclarativeDomDocument()
-: d(new QDeclarativeDomDocumentPrivate)
-{
-}
-
-/*!
- Create a copy of \a other QDeclarativeDomDocument.
-*/
-QDeclarativeDomDocument::QDeclarativeDomDocument(const QDeclarativeDomDocument &other)
-: d(other.d)
-{
-}
-
-/*!
- Destroy the QDeclarativeDomDocument
-*/
-QDeclarativeDomDocument::~QDeclarativeDomDocument()
-{
-}
-
-/*!
- Assign \a other to this QDeclarativeDomDocument.
-*/
-QDeclarativeDomDocument &QDeclarativeDomDocument::operator=(const QDeclarativeDomDocument &other)
-{
- d = other.d;
- return *this;
-}
-
-/*!
- Returns all import statements in qml.
-*/
-QList<QDeclarativeDomImport> QDeclarativeDomDocument::imports() const
-{
- return d->imports;
-}
-
-/*!
- Loads a QDeclarativeDomDocument from \a data. \a data should be valid QML
- data. On success, true is returned. If the \a data is malformed, false
- is returned and QDeclarativeDomDocument::errors() contains an error description.
-
- \sa QDeclarativeDomDocument::loadError()
-*/
-bool QDeclarativeDomDocument::load(QDeclarativeEngine *engine, const QByteArray &data, const QUrl &url)
-{
- d->errors.clear();
- d->imports.clear();
-
- QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
- QDeclarativeTypeData *td = ep->typeLoader.get(data, url, QDeclarativeTypeLoader::PreserveParser);
-
- if(td->isError()) {
- d->errors = td->errors();
- td->release();
- return false;
- } else if(!td->isCompleteOrError()) {
- QDeclarativeError error;
- error.setDescription(QLatin1String("QDeclarativeDomDocument supports local types only"));
- d->errors << error;
- td->release();
- return false;
- }
-
- for (int i = 0; i < td->parser().imports().size(); ++i) {
- QDeclarativeScriptParser::Import parserImport = td->parser().imports().at(i);
- QDeclarativeDomImport domImport;
- domImport.d->type = static_cast<QDeclarativeDomImportPrivate::Type>(parserImport.type);
- domImport.d->uri = parserImport.uri;
- domImport.d->qualifier = parserImport.qualifier;
- domImport.d->version = parserImport.version;
- d->imports += domImport;
- }
-
- if (td->parser().tree()) {
- d->root = td->parser().tree();
- d->root->addref();
- }
-
- td->release();
- return true;
-}
-
-/*!
- Returns the last load errors. The load errors will be reset after a
- successful call to load().
-
- \sa load()
-*/
-QList<QDeclarativeError> QDeclarativeDomDocument::errors() const
-{
- return d->errors;
-}
-
-/*!
- Returns the document's root object, or an invalid QDeclarativeDomObject if the
- document has no root.
-
- In the sample QML below, the root object will be the QDeclarativeItem type.
- \qml
-Item {
- Text {
- text: "Hello World"
- }
-}
- \endqml
-*/
-QDeclarativeDomObject QDeclarativeDomDocument::rootObject() const
-{
- QDeclarativeDomObject rv;
- rv.d->object = d->root;
- if (rv.d->object) rv.d->object->addref();
- return rv;
-}
-
-QDeclarativeDomPropertyPrivate::QDeclarativeDomPropertyPrivate()
-: property(0)
-{
-}
-
-QDeclarativeDomPropertyPrivate::~QDeclarativeDomPropertyPrivate()
-{
- if (property) property->release();
-}
-
-QDeclarativeDomDynamicPropertyPrivate::QDeclarativeDomDynamicPropertyPrivate():
- valid(false)
-{
-}
-
-QDeclarativeDomDynamicPropertyPrivate::~QDeclarativeDomDynamicPropertyPrivate()
-{
- if (valid && property.defaultValue) property.defaultValue->release();
-}
-
-/*!
- \class QDeclarativeDomProperty
- \internal
- \brief The QDeclarativeDomProperty class represents one property assignment in the
- QML DOM tree
-
- Properties in QML can be assigned QML \l {QDeclarativeDomValue}{values}.
-
- \sa QDeclarativeDomObject
-*/
-
-/*!
- Construct an invalid QDeclarativeDomProperty.
-*/
-QDeclarativeDomProperty::QDeclarativeDomProperty()
-: d(new QDeclarativeDomPropertyPrivate)
-{
-}
-
-/*!
- Create a copy of \a other QDeclarativeDomProperty.
-*/
-QDeclarativeDomProperty::QDeclarativeDomProperty(const QDeclarativeDomProperty &other)
-: d(other.d)
-{
-}
-
-/*!
- Destroy the QDeclarativeDomProperty.
-*/
-QDeclarativeDomProperty::~QDeclarativeDomProperty()
-{
-}
-
-/*!
- Assign \a other to this QDeclarativeDomProperty.
-*/
-QDeclarativeDomProperty &QDeclarativeDomProperty::operator=(const QDeclarativeDomProperty &other)
-{
- d = other.d;
- return *this;
-}
-
-/*!
- Returns true if this is a valid QDeclarativeDomProperty, false otherwise.
-*/
-bool QDeclarativeDomProperty::isValid() const
-{
- return d->property != 0;
-}
-
-
-/*!
- Return the name of this property.
-
- \qml
-Text {
- x: 10
- y: 10
- font.bold: true
-}
- \endqml
-
- As illustrated above, a property name can be a simple string, such as "x" or
- "y", or a more complex "dot property", such as "font.bold". In both cases
- the full name is returned ("x", "y" and "font.bold") by this method.
-
- For dot properties, a split version of the name can be accessed by calling
- QDeclarativeDomProperty::propertyNameParts().
-
- \sa QDeclarativeDomProperty::propertyNameParts()
-*/
-QByteArray QDeclarativeDomProperty::propertyName() const
-{
- return d->propertyName;
-}
-
-/*!
- Return the name of this property, split into multiple parts in the case
- of dot properties.
-
- \qml
-Text {
- x: 10
- y: 10
- font.bold: true
-}
- \endqml
-
- For each of the properties shown above, this method would return ("x"),
- ("y") and ("font", "bold").
-
- \sa QDeclarativeDomProperty::propertyName()
-*/
-QList<QByteArray> QDeclarativeDomProperty::propertyNameParts() const
-{
- if (d->propertyName.isEmpty()) return QList<QByteArray>();
- else return d->propertyName.split('.');
-}
-
-/*!
- Return true if this property is used as a default property in the QML
- document.
-
- \code
-<Text text="hello"/>
-<Text>hello</Text>
- \endcode
-
- The above two examples return the same DOM tree, except that the second has
- the default property flag set on the text property. Observe that whether
- or not a property has isDefaultProperty set is determined by how the
- property is used, and not only by whether the property is the types default
- property.
-*/
-bool QDeclarativeDomProperty::isDefaultProperty() const
-{
- return d->property && d->property->isDefault;
-}
-
-/*!
- Returns the QDeclarativeDomValue that is assigned to this property, or an invalid
- QDeclarativeDomValue if no value is assigned.
-*/
-QDeclarativeDomValue QDeclarativeDomProperty::value() const
-{
- QDeclarativeDomValue rv;
- if (d->property) {
- rv.d->property = d->property;
- if (d->property->values.count())
- rv.d->value = d->property->values.at(0);
- else
- rv.d->value = d->property->onValues.at(0);
- rv.d->property->addref();
- rv.d->value->addref();
- }
- return rv;
-}
-
-/*!
- Returns the position in the input data where the property ID startd, or -1 if
- the property is invalid.
-*/
-int QDeclarativeDomProperty::position() const
-{
- if (d && d->property) {
- return d->property->location.range.offset;
- } else
- return -1;
-}
-
-/*!
- Returns the length in the input data from where the property ID started upto
- the end of it, or -1 if the property is invalid.
-*/
-int QDeclarativeDomProperty::length() const
-{
- if (d && d->property)
- return d->property->location.range.length;
- else
- return -1;
-}
-
-/*!
- Construct an invalid QDeclarativeDomDynamicProperty.
-*/
-QDeclarativeDomDynamicProperty::QDeclarativeDomDynamicProperty():
- d(new QDeclarativeDomDynamicPropertyPrivate)
-{
-}
-
-/*!
- Create a copy of \a other QDeclarativeDomDynamicProperty.
-*/
-QDeclarativeDomDynamicProperty::QDeclarativeDomDynamicProperty(const QDeclarativeDomDynamicProperty &other):
- d(other.d)
-{
-}
-
-/*!
- Destroy the QDeclarativeDomDynamicProperty.
-*/
-QDeclarativeDomDynamicProperty::~QDeclarativeDomDynamicProperty()
-{
-}
-
-/*!
- Assign \a other to this QDeclarativeDomDynamicProperty.
-*/
-QDeclarativeDomDynamicProperty &QDeclarativeDomDynamicProperty::operator=(const QDeclarativeDomDynamicProperty &other)
-{
- d = other.d;
- return *this;
-}
-
-bool QDeclarativeDomDynamicProperty::isValid() const
-{
- return d && d->valid;
-}
-
-/*!
- Return the name of this dynamic property.
-
- \qml
-Item {
- property int count: 10;
-}
- \endqml
-
- As illustrated above, a dynamic property name can have a name and a
- default value ("10").
-*/
-QByteArray QDeclarativeDomDynamicProperty::propertyName() const
-{
- if (isValid())
- return d->property.name;
- else
- return QByteArray();
-}
-
-/*!
- Returns the type of the dynamic property. Note that when the property is an
- alias property, this will return -1. Use QDeclarativeDomProperty::isAlias() to check
- if the property is an alias.
-*/
-int QDeclarativeDomDynamicProperty::propertyType() const
-{
- if (isValid()) {
- switch (d->property.type) {
- case QDeclarativeParser::Object::DynamicProperty::Bool:
- return QMetaType::type("bool");
-
- case QDeclarativeParser::Object::DynamicProperty::Color:
- return QMetaType::type("QColor");
-
- case QDeclarativeParser::Object::DynamicProperty::Time:
- return QMetaType::type("QTime");
-
- case QDeclarativeParser::Object::DynamicProperty::Date:
- return QMetaType::type("QDate");
-
- case QDeclarativeParser::Object::DynamicProperty::DateTime:
- return QMetaType::type("QDateTime");
-
- case QDeclarativeParser::Object::DynamicProperty::Int:
- return QMetaType::type("int");
-
- case QDeclarativeParser::Object::DynamicProperty::Real:
- return sizeof(qreal) == sizeof(double) ? QMetaType::type("double") : QMetaType::type("float");
-
- case QDeclarativeParser::Object::DynamicProperty::String:
- return QMetaType::type("QString");
-
- case QDeclarativeParser::Object::DynamicProperty::Url:
- return QMetaType::type("QUrl");
-
- case QDeclarativeParser::Object::DynamicProperty::Variant:
- return QMetaType::type("QVariant");
-
- default:
- break;
- }
- }
-
- return -1;
-}
-
-QByteArray QDeclarativeDomDynamicProperty::propertyTypeName() const
-{
- if (isValid())
- return d->property.customType;
-
- return QByteArray();
-}
-
-/*!
- Return true if this property is used as a default property in the QML
- document.
-
- \code
-<Text text="hello"/>
-<Text>hello</Text>
- \endcode
-
- The above two examples return the same DOM tree, except that the second has
- the default property flag set on the text property. Observe that whether
- or not a property has isDefaultProperty set is determined by how the
- property is used, and not only by whether the property is the types default
- property.
-*/
-bool QDeclarativeDomDynamicProperty::isDefaultProperty() const
-{
- if (isValid())
- return d->property.isDefaultProperty;
- else
- return false;
-}
-
-/*!
- Returns the default value as a QDeclarativeDomProperty.
-*/
-QDeclarativeDomProperty QDeclarativeDomDynamicProperty::defaultValue() const
-{
- QDeclarativeDomProperty rp;
-
- if (isValid() && d->property.defaultValue) {
- rp.d->property = d->property.defaultValue;
- rp.d->propertyName = propertyName();
- rp.d->property->addref();
- }
-
- return rp;
-}
-
-/*!
- Returns true if this dynamic property is an alias for another property,
- false otherwise.
-*/
-bool QDeclarativeDomDynamicProperty::isAlias() const
-{
- if (isValid())
- return d->property.type == QDeclarativeParser::Object::DynamicProperty::Alias;
- else
- return false;
-}
-
-/*!
- Returns the position in the input data where the property ID startd, or 0 if
- the property is invalid.
-*/
-int QDeclarativeDomDynamicProperty::position() const
-{
- if (isValid()) {
- return d->property.location.range.offset;
- } else
- return -1;
-}
-
-/*!
- Returns the length in the input data from where the property ID started upto
- the end of it, or 0 if the property is invalid.
-*/
-int QDeclarativeDomDynamicProperty::length() const
-{
- if (isValid())
- return d->property.location.range.length;
- else
- return -1;
-}
-
-QDeclarativeDomObjectPrivate::QDeclarativeDomObjectPrivate()
-: object(0)
-{
-}
-
-QDeclarativeDomObjectPrivate::~QDeclarativeDomObjectPrivate()
-{
- if (object) object->release();
-}
-
-QDeclarativeDomObjectPrivate::Properties
-QDeclarativeDomObjectPrivate::properties() const
-{
- Properties rv;
-
- for (QHash<QByteArray, QDeclarativeParser::Property *>::ConstIterator iter =
- object->properties.begin();
- iter != object->properties.end();
- ++iter) {
-
- rv << properties(*iter);
-
- }
- return rv;
-}
-
-QDeclarativeDomObjectPrivate::Properties
-QDeclarativeDomObjectPrivate::properties(QDeclarativeParser::Property *property) const
-{
- Properties rv;
-
- if (property->value) {
-
- for (QHash<QByteArray, QDeclarativeParser::Property *>::ConstIterator iter =
- property->value->properties.begin();
- iter != property->value->properties.end();
- ++iter) {
-
- rv << properties(*iter);
-
- }
-
- QByteArray name(property->name + '.');
- for (Properties::Iterator iter = rv.begin(); iter != rv.end(); ++iter)
- iter->second.prepend(name);
-
- } else {
- rv << qMakePair(property, property->name);
- }
-
- return rv;
-}
-
-/*!
- \class QDeclarativeDomObject
- \internal
- \brief The QDeclarativeDomObject class represents an object instantiation.
-
- Each object instantiated in a QML file has a corresponding QDeclarativeDomObject
- node in the QML DOM.
-
- In addition to the type information that determines the object to
- instantiate, QDeclarativeDomObject's also have a set of associated QDeclarativeDomProperty's.
- Each QDeclarativeDomProperty represents a QML property assignment on the instantiated
- object. For example,
-
- \qml
-QGraphicsWidget {
- opacity: 0.5
- size: "100x100"
-}
- \endqml
-
- describes a single QDeclarativeDomObject - "QGraphicsWidget" - with two properties,
- "opacity" and "size". Obviously QGraphicsWidget has many more properties than just
- these two, but the QML DOM representation only contains those assigned
- values (or bindings) in the QML file.
-*/
-
-/*!
- Construct an invalid QDeclarativeDomObject.
-*/
-QDeclarativeDomObject::QDeclarativeDomObject()
-: d(new QDeclarativeDomObjectPrivate)
-{
-}
-
-/*!
- Create a copy of \a other QDeclarativeDomObject.
-*/
-QDeclarativeDomObject::QDeclarativeDomObject(const QDeclarativeDomObject &other)
-: d(other.d)
-{
-}
-
-/*!
- Destroy the QDeclarativeDomObject.
-*/
-QDeclarativeDomObject::~QDeclarativeDomObject()
-{
-}
-
-/*!
- Assign \a other to this QDeclarativeDomObject.
-*/
-QDeclarativeDomObject &QDeclarativeDomObject::operator=(const QDeclarativeDomObject &other)
-{
- d = other.d;
- return *this;
-}
-
-/*!
- Returns true if this is a valid QDeclarativeDomObject, false otherwise.
-*/
-bool QDeclarativeDomObject::isValid() const
-{
- return d->object != 0;
-}
-
-/*!
- Returns the fully-qualified type name of this object.
-
- For example, the type of this object would be "Qt/4.6/Rectangle".
- \qml
-Rectangle { }
- \endqml
-*/
-QByteArray QDeclarativeDomObject::objectType() const
-{
- if (d->object) return d->object->typeName;
- else return QByteArray();
-}
-
-/*!
- Returns the type name as referenced in the qml file.
-
- For example, the type of this object would be "Rectangle".
- \qml
-Rectangle { }
- \endqml
-*/
-QByteArray QDeclarativeDomObject::objectClassName() const
-{
- if (d->object)
- return d->object->className;
- else
- return QByteArray();
-}
-
-int QDeclarativeDomObject::objectTypeMajorVersion() const
-{
- if (d->object)
- return d->object->majorVersion;
- else
- return -1;
-}
-
-int QDeclarativeDomObject::objectTypeMinorVersion() const
-{
- if (d->object)
- return d->object->minorVersion;
- else
- return -1;
-}
-
-/*!
- Returns the QML id assigned to this object, or an empty QByteArray if no id
- has been assigned.
-
- For example, the object id of this object would be "MyText".
- \qml
-Text { id: myText }
- \endqml
-*/
-QString QDeclarativeDomObject::objectId() const
-{
- if (d->object) {
- return d->object->id;
- } else {
- return QString();
- }
-}
-
-/*!
- Returns the list of assigned properties on this object.
-
- In the following example, "text" and "x" properties would be returned.
- \qml
-Text {
- text: "Hello world!"
- x: 100
-}
- \endqml
-*/
-QList<QDeclarativeDomProperty> QDeclarativeDomObject::properties() const
-{
- QList<QDeclarativeDomProperty> rv;
-
- if (!d->object || isComponent())
- return rv;
-
- QDeclarativeDomObjectPrivate::Properties properties = d->properties();
- for (int ii = 0; ii < properties.count(); ++ii) {
-
- QDeclarativeDomProperty domProperty;
- domProperty.d->property = properties.at(ii).first;
- domProperty.d->property->addref();
- domProperty.d->propertyName = properties.at(ii).second;
- rv << domProperty;
-
- }
-
- if (d->object->defaultProperty) {
- QDeclarativeDomProperty domProperty;
- domProperty.d->property = d->object->defaultProperty;
- domProperty.d->property->addref();
- domProperty.d->propertyName = d->object->defaultProperty->name;
- rv << domProperty;
- }
-
- return rv;
-}
-
-/*!
- Returns the object's \a name property if a value has been assigned to
- it, or an invalid QDeclarativeDomProperty otherwise.
-
- In the example below, \c {object.property("source")} would return a valid
- QDeclarativeDomProperty, and \c {object.property("tile")} an invalid QDeclarativeDomProperty.
-
- \qml
-Image { source: "sample.jpg" }
- \endqml
-*/
-QDeclarativeDomProperty QDeclarativeDomObject::property(const QByteArray &name) const
-{
- QList<QDeclarativeDomProperty> props = properties();
- for (int ii = 0; ii < props.count(); ++ii)
- if (props.at(ii).propertyName() == name)
- return props.at(ii);
- return QDeclarativeDomProperty();
-}
-
-QList<QDeclarativeDomDynamicProperty> QDeclarativeDomObject::dynamicProperties() const
-{
- QList<QDeclarativeDomDynamicProperty> properties;
-
- for (int i = 0; i < d->object->dynamicProperties.size(); ++i) {
- QDeclarativeDomDynamicProperty p;
- p.d = new QDeclarativeDomDynamicPropertyPrivate;
- p.d->property = d->object->dynamicProperties.at(i);
- p.d->valid = true;
-
- if (p.d->property.defaultValue)
- p.d->property.defaultValue->addref();
-
- properties.append(p);
- }
-
- return properties;
-}
-
-QDeclarativeDomDynamicProperty QDeclarativeDomObject::dynamicProperty(const QByteArray &name) const
-{
- QDeclarativeDomDynamicProperty p;
-
- if (!isValid())
- return p;
-
- for (int i = 0; i < d->object->dynamicProperties.size(); ++i) {
- if (d->object->dynamicProperties.at(i).name == name) {
- p.d = new QDeclarativeDomDynamicPropertyPrivate;
- p.d->property = d->object->dynamicProperties.at(i);
- if (p.d->property.defaultValue) p.d->property.defaultValue->addref();
- p.d->valid = true;
- }
- }
-
- return p;
-}
-
-/*!
- Returns true if this object is a custom type. Custom types are special
- types that allow embeddeding non-QML data, such as SVG or HTML data,
- directly into QML files.
-
- \note Currently this method will always return false, and is a placekeeper
- for future functionality.
-
- \sa QDeclarativeDomObject::customTypeData()
-*/
-bool QDeclarativeDomObject::isCustomType() const
-{
- return false;
-}
-
-/*!
- If this object represents a custom type, returns the data associated with
- the custom type, otherwise returns an empty QByteArray().
- QDeclarativeDomObject::isCustomType() can be used to check if this object represents
- a custom type.
-*/
-QByteArray QDeclarativeDomObject::customTypeData() const
-{
- return QByteArray();
-}
-
-/*!
- Returns true if this object is a sub-component object. Sub-component
- objects can be converted into QDeclarativeDomComponent instances by calling
- QDeclarativeDomObject::toComponent().
-
- \sa QDeclarativeDomObject::toComponent()
-*/
-bool QDeclarativeDomObject::isComponent() const
-{
- return (d->object && (d->object->typeName == "Qt/Component" || d->object->typeName == "QtQuick/Component"));
-}
-
-/*!
- Returns a QDeclarativeDomComponent for this object if it is a sub-component, or
- an invalid QDeclarativeDomComponent if not. QDeclarativeDomObject::isComponent() can be used
- to check if this object represents a sub-component.
-
- \sa QDeclarativeDomObject::isComponent()
-*/
-QDeclarativeDomComponent QDeclarativeDomObject::toComponent() const
-{
- QDeclarativeDomComponent rv;
- if (isComponent())
- rv.d = d;
- return rv;
-}
-
-/*!
- Returns the position in the input data where the property assignment started
-, or -1 if the property is invalid.
-*/
-int QDeclarativeDomObject::position() const
-{
- if (d && d->object)
- return d->object->location.range.offset;
- else
- return -1;
-}
-
-/*!
- Returns the length in the input data from where the property assignment star
-ted upto the end of it, or -1 if the property is invalid.
-*/
-int QDeclarativeDomObject::length() const
-{
- if (d && d->object)
- return d->object->location.range.length;
- else
- return -1;
-}
-
-// Returns the URL of the type, if it is an external type, or an empty URL if
-// not
-QUrl QDeclarativeDomObject::url() const
-{
- if (d && d->object)
- return d->object->url;
- else
- return QUrl();
-}
-
-QDeclarativeDomBasicValuePrivate::QDeclarativeDomBasicValuePrivate()
-: value(0)
-{
-}
-
-QDeclarativeDomBasicValuePrivate::~QDeclarativeDomBasicValuePrivate()
-{
- if (value) value->release();
-}
-
-/*!
- \class QDeclarativeDomValueLiteral
- \internal
- \brief The QDeclarativeDomValueLiteral class represents a literal value.
-
- A literal value is a simple value, written inline with the QML. In the
- example below, the "x", "y" and "color" properties are being assigned
- literal values.
-
- \qml
-Rectangle {
- x: 10
- y: 10
- color: "red"
-}
- \endqml
-*/
-
-/*!
- Construct an empty QDeclarativeDomValueLiteral.
-*/
-QDeclarativeDomValueLiteral::QDeclarativeDomValueLiteral():
- d(new QDeclarativeDomBasicValuePrivate)
-{
-}
-
-/*!
- Create a copy of \a other QDeclarativeDomValueLiteral.
-*/
-QDeclarativeDomValueLiteral::QDeclarativeDomValueLiteral(const QDeclarativeDomValueLiteral &other)
-: d(other.d)
-{
-}
-
-/*!
- Destroy the QDeclarativeDomValueLiteral.
-*/
-QDeclarativeDomValueLiteral::~QDeclarativeDomValueLiteral()
-{
-}
-
-/*!
- Assign \a other to this QDeclarativeDomValueLiteral.
-*/
-QDeclarativeDomValueLiteral &QDeclarativeDomValueLiteral::operator=(const QDeclarativeDomValueLiteral &other)
-{
- d = other.d;
- return *this;
-}
-
-/*!
- Return the literal value.
-
- In the example below, the literal value will be the string "10".
- \qml
-Rectangle { x: 10 }
- \endqml
-*/
-QString QDeclarativeDomValueLiteral::literal() const
-{
- if (d->value) return d->value->primitive();
- else return QString();
-}
-
-/*!
- \class QDeclarativeDomValueBinding
- \internal
- \brief The QDeclarativeDomValueBinding class represents a property binding.
-
- A property binding is an ECMAScript expression assigned to a property. In
- the example below, the "x" property is being assigned a property binding.
-
- \qml
-Rectangle { x: Other.x }
- \endqml
-*/
-
-/*!
- Construct an empty QDeclarativeDomValueBinding.
-*/
-QDeclarativeDomValueBinding::QDeclarativeDomValueBinding():
- d(new QDeclarativeDomBasicValuePrivate)
-{
-}
-
-/*!
- Create a copy of \a other QDeclarativeDomValueBinding.
-*/
-QDeclarativeDomValueBinding::QDeclarativeDomValueBinding(const QDeclarativeDomValueBinding &other)
-: d(other.d)
-{
-}
-
-/*!
- Destroy the QDeclarativeDomValueBinding.
-*/
-QDeclarativeDomValueBinding::~QDeclarativeDomValueBinding()
-{
-}
-
-/*!
- Assign \a other to this QDeclarativeDomValueBinding.
-*/
-QDeclarativeDomValueBinding &QDeclarativeDomValueBinding::operator=(const QDeclarativeDomValueBinding &other)
-{
- d = other.d;
- return *this;
-}
-
-/*!
- Return the binding expression.
-
- In the example below, the string "Other.x" will be returned.
- \qml
-Rectangle { x: Other.x }
- \endqml
-*/
-QString QDeclarativeDomValueBinding::binding() const
-{
- if (d->value)
- return d->value->value.asScript();
- else
- return QString();
-}
-
-/*!
- \class QDeclarativeDomValueValueSource
- \internal
- \brief The QDeclarativeDomValueValueSource class represents a value source assignment value.
-
- In QML, value sources are special value generating types that may be
- assigned to properties. Value sources inherit the QDeclarativePropertyValueSource
- class. In the example below, the "x" property is being assigned the
- NumberAnimation value source.
-
- \qml
-Rectangle {
- x: NumberAnimation {
- from: 0
- to: 100
- loops: Animation.Infinite
- }
-}
- \endqml
-*/
-
-/*!
- Construct an empty QDeclarativeDomValueValueSource.
-*/
-QDeclarativeDomValueValueSource::QDeclarativeDomValueValueSource():
- d(new QDeclarativeDomBasicValuePrivate)
-{
-}
-
-/*!
- Create a copy of \a other QDeclarativeDomValueValueSource.
-*/
-QDeclarativeDomValueValueSource::QDeclarativeDomValueValueSource(const QDeclarativeDomValueValueSource &other)
-: d(other.d)
-{
-}
-
-/*!
- Destroy the QDeclarativeDomValueValueSource.
-*/
-QDeclarativeDomValueValueSource::~QDeclarativeDomValueValueSource()
-{
-}
-
-/*!
- Assign \a other to this QDeclarativeDomValueValueSource.
-*/
-QDeclarativeDomValueValueSource &QDeclarativeDomValueValueSource::operator=(const QDeclarativeDomValueValueSource &other)
-{
- d = other.d;
- return *this;
-}
-
-/*!
- Return the value source object.
-
- In the example below, an object representing the NumberAnimation will be
- returned.
- \qml
-Rectangle {
- x: NumberAnimation {
- from: 0
- to: 100
- loops: Animation.Infinite
- }
-}
- \endqml
-*/
-QDeclarativeDomObject QDeclarativeDomValueValueSource::object() const
-{
- QDeclarativeDomObject rv;
- if (d->value) {
- rv.d->object = d->value->object;
- rv.d->object->addref();
- }
- return rv;
-}
-
-/*!
- \class QDeclarativeDomValueValueInterceptor
- \internal
- \brief The QDeclarativeDomValueValueInterceptor class represents a value interceptor assignment value.
-
- In QML, value interceptor are special write-intercepting types that may be
- assigned to properties. Value interceptor inherit the QDeclarativePropertyValueInterceptor
- class. In the example below, the "x" property is being assigned the
- Behavior value interceptor.
-
- \qml
-Rectangle {
- Behavior on x { NumberAnimation { duration: 500 } }
-}
- \endqml
-*/
-
-/*!
- Construct an empty QDeclarativeDomValueValueInterceptor.
-*/
-QDeclarativeDomValueValueInterceptor::QDeclarativeDomValueValueInterceptor():
- d(new QDeclarativeDomBasicValuePrivate)
-{
-}
-
-/*!
- Create a copy of \a other QDeclarativeDomValueValueInterceptor.
-*/
-QDeclarativeDomValueValueInterceptor::QDeclarativeDomValueValueInterceptor(const QDeclarativeDomValueValueInterceptor &other)
-: d(other.d)
-{
-}
-
-/*!
- Destroy the QDeclarativeDomValueValueInterceptor.
-*/
-QDeclarativeDomValueValueInterceptor::~QDeclarativeDomValueValueInterceptor()
-{
-}
-
-/*!
- Assign \a other to this QDeclarativeDomValueValueInterceptor.
-*/
-QDeclarativeDomValueValueInterceptor &QDeclarativeDomValueValueInterceptor::operator=(const QDeclarativeDomValueValueInterceptor &other)
-{
- d = other.d;
- return *this;
-}
-
-/*!
- Return the value interceptor object.
-
- In the example below, an object representing the Behavior will be
- returned.
- \qml
-Rectangle {
- Behavior on x { NumberAnimation { duration: 500 } }
-}
- \endqml
-*/
-QDeclarativeDomObject QDeclarativeDomValueValueInterceptor::object() const
-{
- QDeclarativeDomObject rv;
- if (d->value) {
- rv.d->object = d->value->object;
- rv.d->object->addref();
- }
- return rv;
-}
-
-QDeclarativeDomValuePrivate::QDeclarativeDomValuePrivate()
-: property(0), value(0)
-{
-}
-
-QDeclarativeDomValuePrivate::~QDeclarativeDomValuePrivate()
-{
- if (property) property->release();
- if (value) value->release();
-}
-
-/*!
- \class QDeclarativeDomValue
- \internal
- \brief The QDeclarativeDomValue class represents a generic Qml value.
-
- QDeclarativeDomValue's can be assigned to QML \l {QDeclarativeDomProperty}{properties}. In
- QML, properties can be assigned various different values, including basic
- literals, property bindings, property value sources, objects and lists of
- values. The QDeclarativeDomValue class allows a programmer to determine the specific
- value type being assigned and access more detailed information through a
- corresponding value type class.
-
- For example, in the following example,
-
- \qml
-Text {
- text: "Hello World!"
- y: Other.y
-}
- \endqml
-
- The text property is being assigned a literal, and the y property a property
- binding. To output the values assigned to the text and y properties in the
- above example from C++,
-
- \code
- QDeclarativeDomDocument document;
- QDeclarativeDomObject root = document.rootObject();
-
- QDeclarativeDomProperty text = root.property("text");
- if (text.value().isLiteral()) {
- QDeclarativeDomValueLiteral literal = text.value().toLiteral();
- qDebug() << literal.literal();
- }
-
- QDeclarativeDomProperty y = root.property("y");
- if (y.value().isBinding()) {
- QDeclarativeDomValueBinding binding = y.value().toBinding();
- qDebug() << binding.binding();
- }
- \endcode
-*/
-
-/*!
- Construct an invalid QDeclarativeDomValue.
-*/
-QDeclarativeDomValue::QDeclarativeDomValue()
-: d(new QDeclarativeDomValuePrivate)
-{
-}
-
-/*!
- Create a copy of \a other QDeclarativeDomValue.
-*/
-QDeclarativeDomValue::QDeclarativeDomValue(const QDeclarativeDomValue &other)
-: d(other.d)
-{
-}
-
-/*!
- Destroy the QDeclarativeDomValue
-*/
-QDeclarativeDomValue::~QDeclarativeDomValue()
-{
-}
-
-/*!
- Assign \a other to this QDeclarativeDomValue.
-*/
-QDeclarativeDomValue &QDeclarativeDomValue::operator=(const QDeclarativeDomValue &other)
-{
- d = other.d;
- return *this;
-}
-
-/*!
- \enum QDeclarativeDomValue::Type
-
- The type of the QDeclarativeDomValue node.
-
- \value Invalid The QDeclarativeDomValue is invalid.
- \value Literal The QDeclarativeDomValue is a literal value assignment. Use QDeclarativeDomValue::toLiteral() to access the type instance.
- \value PropertyBinding The QDeclarativeDomValue is a property binding. Use QDeclarativeDomValue::toBinding() to access the type instance.
- \value ValueSource The QDeclarativeDomValue is a property value source. Use QDeclarativeDomValue::toValueSource() to access the type instance.
- \value ValueInterceptor The QDeclarativeDomValue is a property value interceptor. Use QDeclarativeDomValue::toValueInterceptor() to access the type instance.
- \value Object The QDeclarativeDomValue is an object assignment. Use QDeclarativeDomValue::toObject() to access the type instnace.
- \value List The QDeclarativeDomValue is a list of other values. Use QDeclarativeDomValue::toList() to access the type instance.
-*/
-
-/*!
- Returns the type of this QDeclarativeDomValue.
-*/
-QDeclarativeDomValue::Type QDeclarativeDomValue::type() const
-{
- if (d->property)
- if (QDeclarativeMetaType::isList(d->property->type) ||
- (d->property && (d->property->values.count() + d->property->onValues.count()) > 1))
- return List;
-
- QDeclarativeParser::Value *value = d->value;
- if (!value && !d->property)
- return Invalid;
-
- switch(value->type) {
- case QDeclarativeParser::Value::Unknown:
- return Invalid;
- case QDeclarativeParser::Value::Literal:
- return Literal;
- case QDeclarativeParser::Value::PropertyBinding:
- return PropertyBinding;
- case QDeclarativeParser::Value::ValueSource:
- return ValueSource;
- case QDeclarativeParser::Value::ValueInterceptor:
- return ValueInterceptor;
- case QDeclarativeParser::Value::CreatedObject:
- return Object;
- case QDeclarativeParser::Value::SignalObject:
- return Invalid;
- case QDeclarativeParser::Value::SignalExpression:
- return Literal;
- case QDeclarativeParser::Value::Id:
- return Literal;
- }
- return Invalid;
-}
-
-/*!
- Returns true if this is an invalid value, otherwise false.
-*/
-bool QDeclarativeDomValue::isInvalid() const
-{
- return type() == Invalid;
-}
-
-/*!
- Returns true if this is a literal value, otherwise false.
-*/
-bool QDeclarativeDomValue::isLiteral() const
-{
- return type() == Literal;
-}
-
-/*!
- Returns true if this is a property binding value, otherwise false.
-*/
-bool QDeclarativeDomValue::isBinding() const
-{
- return type() == PropertyBinding;
-}
-
-/*!
- Returns true if this is a value source value, otherwise false.
-*/
-bool QDeclarativeDomValue::isValueSource() const
-{
- return type() == ValueSource;
-}
-
-/*!
- Returns true if this is a value interceptor value, otherwise false.
-*/
-bool QDeclarativeDomValue::isValueInterceptor() const
-{
- return type() == ValueInterceptor;
-}
-
-/*!
- Returns true if this is an object value, otherwise false.
-*/
-bool QDeclarativeDomValue::isObject() const
-{
- return type() == Object;
-}
-
-/*!
- Returns true if this is a list value, otherwise false.
-*/
-bool QDeclarativeDomValue::isList() const
-{
- return type() == List;
-}
-
-/*!
- Returns a QDeclarativeDomValueLiteral if this value is a literal type, otherwise
- returns an invalid QDeclarativeDomValueLiteral.
-
- \sa QDeclarativeDomValue::type()
-*/
-QDeclarativeDomValueLiteral QDeclarativeDomValue::toLiteral() const
-{
- QDeclarativeDomValueLiteral rv;
- if (type() == Literal) {
- rv.d->value = d->value;
- rv.d->value->addref();
- }
- return rv;
-}
-
-/*!
- Returns a QDeclarativeDomValueBinding if this value is a property binding type,
- otherwise returns an invalid QDeclarativeDomValueBinding.
-
- \sa QDeclarativeDomValue::type()
-*/
-QDeclarativeDomValueBinding QDeclarativeDomValue::toBinding() const
-{
- QDeclarativeDomValueBinding rv;
- if (type() == PropertyBinding) {
- rv.d->value = d->value;
- rv.d->value->addref();
- }
- return rv;
-}
-
-/*!
- Returns a QDeclarativeDomValueValueSource if this value is a property value source
- type, otherwise returns an invalid QDeclarativeDomValueValueSource.
-
- \sa QDeclarativeDomValue::type()
-*/
-QDeclarativeDomValueValueSource QDeclarativeDomValue::toValueSource() const
-{
- QDeclarativeDomValueValueSource rv;
- if (type() == ValueSource) {
- rv.d->value = d->value;
- rv.d->value->addref();
- }
- return rv;
-}
-
-/*!
- Returns a QDeclarativeDomValueValueInterceptor if this value is a property value interceptor
- type, otherwise returns an invalid QDeclarativeDomValueValueInterceptor.
-
- \sa QDeclarativeDomValue::type()
-*/
-QDeclarativeDomValueValueInterceptor QDeclarativeDomValue::toValueInterceptor() const
-{
- QDeclarativeDomValueValueInterceptor rv;
- if (type() == ValueInterceptor) {
- rv.d->value = d->value;
- rv.d->value->addref();
- }
- return rv;
-}
-
-/*!
- Returns a QDeclarativeDomObject if this value is an object assignment type, otherwise
- returns an invalid QDeclarativeDomObject.
-
- \sa QDeclarativeDomValue::type()
-*/
-QDeclarativeDomObject QDeclarativeDomValue::toObject() const
-{
- QDeclarativeDomObject rv;
- if (type() == Object) {
- rv.d->object = d->value->object;
- rv.d->object->addref();
- }
- return rv;
-}
-
-/*!
- Returns a QDeclarativeDomList if this value is a list type, otherwise returns an
- invalid QDeclarativeDomList.
-
- \sa QDeclarativeDomValue::type()
-*/
-QDeclarativeDomList QDeclarativeDomValue::toList() const
-{
- QDeclarativeDomList rv;
- if (type() == List) {
- rv.d = d;
- }
- return rv;
-}
-
-/*!
- Returns the position in the input data where the property value startd, or -1
- if the value is invalid.
-*/
-int QDeclarativeDomValue::position() const
-{
- if (type() == Invalid)
- return -1;
- else
- return d->value->location.range.offset;
-}
-
-/*!
- Returns the length in the input data from where the property value started u
-pto the end of it, or -1 if the value is invalid.
-*/
-int QDeclarativeDomValue::length() const
-{
- if (type() == Invalid)
- return -1;
- else
- return d->value->location.range.length;
-}
-
-/*!
- \class QDeclarativeDomList
- \internal
- \brief The QDeclarativeDomList class represents a list of values assigned to a QML property.
-
- Lists of values can be assigned to properties. For example, the following
- example assigns multiple objects to Item's "children" property
- \qml
-Item {
- children: [
- Text { },
- Rectangle { }
- ]
-}
- \endqml
-
- Lists can also be implicitly created by assigning multiple
- \l {QDeclarativeDomValueValueSource}{value sources} or constants to a property.
- \qml
-Item {
- x: 10
- x: NumberAnimation {
- running: false
- from: 0
- to: 100
- }
-}
- \endqml
-*/
-
-/*!
- Construct an empty QDeclarativeDomList.
-*/
-QDeclarativeDomList::QDeclarativeDomList()
-{
-}
-
-/*!
- Create a copy of \a other QDeclarativeDomList.
-*/
-QDeclarativeDomList::QDeclarativeDomList(const QDeclarativeDomList &other)
-: d(other.d)
-{
-}
-
-/*!
- Destroy the QDeclarativeDomList.
-*/
-QDeclarativeDomList::~QDeclarativeDomList()
-{
-}
-
-/*!
- Assign \a other to this QDeclarativeDomList.
-*/
-QDeclarativeDomList &QDeclarativeDomList::operator=(const QDeclarativeDomList &other)
-{
- d = other.d;
- return *this;
-}
-
-/*!
- Returns the list of QDeclarativeDomValue's.
-*/
-QList<QDeclarativeDomValue> QDeclarativeDomList::values() const
-{
- QList<QDeclarativeDomValue> rv;
- if (!d->property)
- return rv;
-
- for (int ii = 0; ii < d->property->values.count(); ++ii) {
- QDeclarativeDomValue v;
- v.d->value = d->property->values.at(ii);
- v.d->value->addref();
- rv << v;
- }
-
- for (int ii = 0; ii < d->property->onValues.count(); ++ii) {
- QDeclarativeDomValue v;
- v.d->value = d->property->onValues.at(ii);
- v.d->value->addref();
- rv << v;
- }
-
- return rv;
-}
-
-/*!
- Returns the position in the input data where the list started, or -1 if
- the property is invalid.
-*/
-int QDeclarativeDomList::position() const
-{
- if (d && d->property) {
- return d->property->listValueRange.offset;
- } else
- return -1;
-}
-
-/*!
- Returns the length in the input data from where the list started upto
- the end of it, or 0 if the property is invalid.
-*/
-int QDeclarativeDomList::length() const
-{
- if (d && d->property)
- return d->property->listValueRange.length;
- else
- return -1;
-}
-
-/*!
- Returns a list of positions of the commas in the QML file.
-*/
-QList<int> QDeclarativeDomList:: commaPositions() const
-{
- if (d && d->property)
- return d->property->listCommaPositions;
- else
- return QList<int>();
-}
-
-/*!
- \class QDeclarativeDomComponent
- \internal
- \brief The QDeclarativeDomComponent class represents sub-component within a QML document.
-
- Sub-components are QDeclarativeComponents defined within a QML document. The
- following example shows the definition of a sub-component with the id
- "listDelegate".
-
- \qml
-Item {
- Component {
- id: listDelegate
- Text {
- text: modelData.text
- }
- }
-}
- \endqml
-
- Like QDeclarativeDomDocument's, components contain a single root object.
-*/
-
-/*!
- Construct an empty QDeclarativeDomComponent.
-*/
-QDeclarativeDomComponent::QDeclarativeDomComponent()
-{
-}
-
-/*!
- Create a copy of \a other QDeclarativeDomComponent.
-*/
-QDeclarativeDomComponent::QDeclarativeDomComponent(const QDeclarativeDomComponent &other)
-: QDeclarativeDomObject(other)
-{
-}
-
-/*!
- Destroy the QDeclarativeDomComponent.
-*/
-QDeclarativeDomComponent::~QDeclarativeDomComponent()
-{
-}
-
-/*!
- Assign \a other to this QDeclarativeDomComponent.
-*/
-QDeclarativeDomComponent &QDeclarativeDomComponent::operator=(const QDeclarativeDomComponent &other)
-{
- static_cast<QDeclarativeDomObject &>(*this) = other;
- return *this;
-}
-
-/*!
- Returns the component's root object.
-
- In the example below, the root object is the "Text" object.
- \qml
-Item {
- Component {
- id: listDelegate
- Text {
- text: modelData.text
- }
- }
-}
- \endqml
-*/
-QDeclarativeDomObject QDeclarativeDomComponent::componentRoot() const
-{
- QDeclarativeDomObject rv;
- if (d->object) {
- QDeclarativeParser::Object *obj = 0;
- if (d->object->defaultProperty &&
- d->object->defaultProperty->values.count() == 1 &&
- d->object->defaultProperty->values.at(0)->object)
- obj = d->object->defaultProperty->values.at(0)->object;
-
- if (obj) {
- rv.d->object = obj;
- rv.d->object->addref();
- }
- }
-
- return rv;
-}
-
-QDeclarativeDomImportPrivate::QDeclarativeDomImportPrivate()
-: type(File)
-{
-}
-
-QDeclarativeDomImportPrivate::~QDeclarativeDomImportPrivate()
-{
-}
-
-/*!
- \class QDeclarativeDomImport
- \internal
- \brief The QDeclarativeDomImport class represents an import statement.
-*/
-
-/*!
- Construct an empty QDeclarativeDomImport.
-*/
-QDeclarativeDomImport::QDeclarativeDomImport()
-: d(new QDeclarativeDomImportPrivate)
-{
-}
-
-/*!
- Create a copy of \a other QDeclarativeDomImport.
-*/
-QDeclarativeDomImport::QDeclarativeDomImport(const QDeclarativeDomImport &other)
-: d(other.d)
-{
-}
-
-/*!
- Destroy the QDeclarativeDomImport.
-*/
-QDeclarativeDomImport::~QDeclarativeDomImport()
-{
-}
-
-/*!
- Assign \a other to this QDeclarativeDomImport.
-*/
-QDeclarativeDomImport &QDeclarativeDomImport::operator=(const QDeclarativeDomImport &other)
-{
- d = other.d;
- return *this;
-}
-
-/*!
- Returns the type of the import.
- */
-QDeclarativeDomImport::Type QDeclarativeDomImport::type() const
-{
- return static_cast<QDeclarativeDomImport::Type>(d->type);
-}
-
-/*!
- Returns the URI of the import (e.g. 'subdir' or 'com.nokia.Qt')
- */
-QString QDeclarativeDomImport::uri() const
-{
- return d->uri;
-}
-
-/*!
- Returns the version specified by the import. An empty string if no version was specified.
- */
-QString QDeclarativeDomImport::version() const
-{
- return d->version;
-}
-
-/*!
- Returns the (optional) qualifier string (the token following the 'as' keyword) of the import.
- */
-QString QDeclarativeDomImport::qualifier() const
-{
- return d->qualifier;
-}
-
-QT_END_NAMESPACE
diff --git a/src/declarative/qml/qdeclarativedom_p.h b/src/declarative/qml/qdeclarativedom_p.h
deleted file mode 100644
index 9f255004e8..0000000000
--- a/src/declarative/qml/qdeclarativedom_p.h
+++ /dev/null
@@ -1,362 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
-** All rights reserved.
-** Contact: Nokia Corporation (qt-info@nokia.com)
-**
-** This file is part of the QtDeclarative 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 QDECLARATIVEDOM_P_H
-#define QDECLARATIVEDOM_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 "qdeclarativeerror.h"
-
-#include <QtCore/qlist.h>
-#include <QtCore/qshareddata.h>
-
-#include <private/qdeclarativeglobal_p.h>
-
-QT_BEGIN_HEADER
-
-QT_BEGIN_NAMESPACE
-
-QT_MODULE(Declarative)
-
-class QString;
-class QByteArray;
-class QDeclarativeDomObject;
-class QDeclarativeDomList;
-class QDeclarativeDomValue;
-class QDeclarativeEngine;
-class QDeclarativeDomComponent;
-class QDeclarativeDomImport;
-class QIODevice;
-
-class QDeclarativeDomDocumentPrivate;
-
-class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeDomDocument
-{
-public:
- QDeclarativeDomDocument();
- QDeclarativeDomDocument(const QDeclarativeDomDocument &);
- ~QDeclarativeDomDocument();
- QDeclarativeDomDocument &operator=(const QDeclarativeDomDocument &);
-
- QList<QDeclarativeDomImport> imports() const;
-
- QList<QDeclarativeError> errors() const;
- bool load(QDeclarativeEngine *, const QByteArray &, const QUrl & = QUrl());
-
- QDeclarativeDomObject rootObject() const;
-
-private:
- QSharedDataPointer<QDeclarativeDomDocumentPrivate> d;
-};
-
-class QDeclarativeDomPropertyPrivate;
-class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeDomProperty
-{
-public:
- QDeclarativeDomProperty();
- QDeclarativeDomProperty(const QDeclarativeDomProperty &);
- ~QDeclarativeDomProperty();
- QDeclarativeDomProperty &operator=(const QDeclarativeDomProperty &);
-
- bool isValid() const;
-
- QByteArray propertyName() const;
- QList<QByteArray> propertyNameParts() const;
-
- bool isDefaultProperty() const;
-
- QDeclarativeDomValue value() const;
-
- int position() const;
- int length() const;
-
-private:
- friend class QDeclarativeDomObject;
- friend class QDeclarativeDomDynamicProperty;
- QSharedDataPointer<QDeclarativeDomPropertyPrivate> d;
-};
-
-class QDeclarativeDomDynamicPropertyPrivate;
-class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeDomDynamicProperty
-{
-public:
- QDeclarativeDomDynamicProperty();
- QDeclarativeDomDynamicProperty(const QDeclarativeDomDynamicProperty &);
- ~QDeclarativeDomDynamicProperty();
- QDeclarativeDomDynamicProperty &operator=(const QDeclarativeDomDynamicProperty &);
-
- bool isValid() const;
-
- QByteArray propertyName() const;
- int propertyType() const;
- QByteArray propertyTypeName() const;
-
- bool isDefaultProperty() const;
- QDeclarativeDomProperty defaultValue() const;
-
- bool isAlias() const;
-
- int position() const;
- int length() const;
-
-private:
- friend class QDeclarativeDomObject;
- QSharedDataPointer<QDeclarativeDomDynamicPropertyPrivate> d;
-};
-
-class QDeclarativeDomObjectPrivate;
-class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeDomObject
-{
-public:
- QDeclarativeDomObject();
- QDeclarativeDomObject(const QDeclarativeDomObject &);
- ~QDeclarativeDomObject();
- QDeclarativeDomObject &operator=(const QDeclarativeDomObject &);
-
- bool isValid() const;
-
- QByteArray objectType() const;
- QByteArray objectClassName() const;
-
- int objectTypeMajorVersion() const;
- int objectTypeMinorVersion() const;
-
- QString objectId() const;
-
- QList<QDeclarativeDomProperty> properties() const;
- QDeclarativeDomProperty property(const QByteArray &) const;
-
- QList<QDeclarativeDomDynamicProperty> dynamicProperties() const;
- QDeclarativeDomDynamicProperty dynamicProperty(const QByteArray &) const;
-
- bool isCustomType() const;
- QByteArray customTypeData() const;
-
- bool isComponent() const;
- QDeclarativeDomComponent toComponent() const;
-
- int position() const;
- int length() const;
-
- QUrl url() const;
-private:
- friend class QDeclarativeDomDocument;
- friend class QDeclarativeDomComponent;
- friend class QDeclarativeDomValue;
- friend class QDeclarativeDomValueValueSource;
- friend class QDeclarativeDomValueValueInterceptor;
- QSharedDataPointer<QDeclarativeDomObjectPrivate> d;
-};
-
-class QDeclarativeDomValuePrivate;
-class QDeclarativeDomBasicValuePrivate;
-class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeDomValueLiteral
-{
-public:
- QDeclarativeDomValueLiteral();
- QDeclarativeDomValueLiteral(const QDeclarativeDomValueLiteral &);
- ~QDeclarativeDomValueLiteral();
- QDeclarativeDomValueLiteral &operator=(const QDeclarativeDomValueLiteral &);
-
- QString literal() const;
-
-private:
- friend class QDeclarativeDomValue;
- QSharedDataPointer<QDeclarativeDomBasicValuePrivate> d;
-};
-
-class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeDomValueBinding
-{
-public:
- QDeclarativeDomValueBinding();
- QDeclarativeDomValueBinding(const QDeclarativeDomValueBinding &);
- ~QDeclarativeDomValueBinding();
- QDeclarativeDomValueBinding &operator=(const QDeclarativeDomValueBinding &);
-
- QString binding() const;
-
-private:
- friend class QDeclarativeDomValue;
- QSharedDataPointer<QDeclarativeDomBasicValuePrivate> d;
-};
-
-class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeDomValueValueSource
-{
-public:
- QDeclarativeDomValueValueSource();
- QDeclarativeDomValueValueSource(const QDeclarativeDomValueValueSource &);
- ~QDeclarativeDomValueValueSource();
- QDeclarativeDomValueValueSource &operator=(const QDeclarativeDomValueValueSource &);
-
- QDeclarativeDomObject object() const;
-
-private:
- friend class QDeclarativeDomValue;
- QSharedDataPointer<QDeclarativeDomBasicValuePrivate> d;
-};
-
-class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeDomValueValueInterceptor
-{
-public:
- QDeclarativeDomValueValueInterceptor();
- QDeclarativeDomValueValueInterceptor(const QDeclarativeDomValueValueInterceptor &);
- ~QDeclarativeDomValueValueInterceptor();
- QDeclarativeDomValueValueInterceptor &operator=(const QDeclarativeDomValueValueInterceptor &);
-
- QDeclarativeDomObject object() const;
-
-private:
- friend class QDeclarativeDomValue;
- QSharedDataPointer<QDeclarativeDomBasicValuePrivate> d;
-};
-
-
-class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeDomComponent : public QDeclarativeDomObject
-{
-public:
- QDeclarativeDomComponent();
- QDeclarativeDomComponent(const QDeclarativeDomComponent &);
- ~QDeclarativeDomComponent();
- QDeclarativeDomComponent &operator=(const QDeclarativeDomComponent &);
-
- QDeclarativeDomObject componentRoot() const;
-};
-
-class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeDomValue
-{
-public:
- enum Type {
- Invalid,
- Literal,
- PropertyBinding,
- ValueSource,
- ValueInterceptor,
- Object,
- List
- };
-
- QDeclarativeDomValue();
- QDeclarativeDomValue(const QDeclarativeDomValue &);
- ~QDeclarativeDomValue();
- QDeclarativeDomValue &operator=(const QDeclarativeDomValue &);
-
- Type type() const;
-
- bool isInvalid() const;
- bool isLiteral() const;
- bool isBinding() const;
- bool isValueSource() const;
- bool isValueInterceptor() const;
- bool isObject() const;
- bool isList() const;
-
- QDeclarativeDomValueLiteral toLiteral() const;
- QDeclarativeDomValueBinding toBinding() const;
- QDeclarativeDomValueValueSource toValueSource() const;
- QDeclarativeDomValueValueInterceptor toValueInterceptor() const;
- QDeclarativeDomObject toObject() const;
- QDeclarativeDomList toList() const;
-
- int position() const;
- int length() const;
-
-private:
- friend class QDeclarativeDomProperty;
- friend class QDeclarativeDomList;
- QSharedDataPointer<QDeclarativeDomValuePrivate> d;
-};
-
-class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeDomList
-{
-public:
- QDeclarativeDomList();
- QDeclarativeDomList(const QDeclarativeDomList &);
- ~QDeclarativeDomList();
- QDeclarativeDomList &operator=(const QDeclarativeDomList &);
-
- QList<QDeclarativeDomValue> values() const;
-
- int position() const;
- int length() const;
-
- QList<int> commaPositions() const;
-
-private:
- friend class QDeclarativeDomValue;
- QSharedDataPointer<QDeclarativeDomValuePrivate> d;
-};
-
-class QDeclarativeDomImportPrivate;
-class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeDomImport
-{
-public:
- enum Type { Library, File };
-
- QDeclarativeDomImport();
- QDeclarativeDomImport(const QDeclarativeDomImport &);
- ~QDeclarativeDomImport();
- QDeclarativeDomImport &operator=(const QDeclarativeDomImport &);
-
- Type type() const;
- QString uri() const;
- QString version() const;
- QString qualifier() const;
-
-private:
- friend class QDeclarativeDomDocument;
- QSharedDataPointer<QDeclarativeDomImportPrivate> d;
-};
-
-QT_END_NAMESPACE
-
-QT_END_HEADER
-
-#endif // QDECLARATIVEDOM_P_H
diff --git a/src/declarative/qml/qdeclarativedom_p_p.h b/src/declarative/qml/qdeclarativedom_p_p.h
deleted file mode 100644
index bcff6236ec..0000000000
--- a/src/declarative/qml/qdeclarativedom_p_p.h
+++ /dev/null
@@ -1,157 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
-** All rights reserved.
-** Contact: Nokia Corporation (qt-info@nokia.com)
-**
-** This file is part of the QtDeclarative 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 QDECLARATIVEDOM_P_P_H
-#define QDECLARATIVEDOM_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/qdeclarativeparser_p.h"
-
-#include <QtCore/QtGlobal>
-
-QT_BEGIN_NAMESPACE
-
-class QDeclarativeDomDocumentPrivate : public QSharedData
-{
-public:
- QDeclarativeDomDocumentPrivate();
- QDeclarativeDomDocumentPrivate(const QDeclarativeDomDocumentPrivate &o)
- : QSharedData(o) { qFatal("Not impl"); }
- ~QDeclarativeDomDocumentPrivate();
-
- QList<QDeclarativeError> errors;
- QList<QDeclarativeDomImport> imports;
- QDeclarativeParser::Object *root;
- QList<int> automaticSemicolonOffsets;
-};
-
-class QDeclarativeDomObjectPrivate : public QSharedData
-{
-public:
- QDeclarativeDomObjectPrivate();
- QDeclarativeDomObjectPrivate(const QDeclarativeDomObjectPrivate &o)
- : QSharedData(o) { qFatal("Not impl"); }
- ~QDeclarativeDomObjectPrivate();
-
- typedef QList<QPair<QDeclarativeParser::Property *, QByteArray> > Properties;
- Properties properties() const;
- Properties properties(QDeclarativeParser::Property *) const;
-
- QDeclarativeParser::Object *object;
-};
-
-class QDeclarativeDomPropertyPrivate : public QSharedData
-{
-public:
- QDeclarativeDomPropertyPrivate();
- QDeclarativeDomPropertyPrivate(const QDeclarativeDomPropertyPrivate &o)
- : QSharedData(o) { qFatal("Not impl"); }
- ~QDeclarativeDomPropertyPrivate();
-
- QByteArray propertyName;
- QDeclarativeParser::Property *property;
-};
-
-class QDeclarativeDomDynamicPropertyPrivate : public QSharedData
-{
-public:
- QDeclarativeDomDynamicPropertyPrivate();
- QDeclarativeDomDynamicPropertyPrivate(const QDeclarativeDomDynamicPropertyPrivate &o)
- : QSharedData(o) { qFatal("Not impl"); }
- ~QDeclarativeDomDynamicPropertyPrivate();
-
- bool valid;
- QDeclarativeParser::Object::DynamicProperty property;
-};
-
-class QDeclarativeDomValuePrivate : public QSharedData
-{
-public:
- QDeclarativeDomValuePrivate();
- QDeclarativeDomValuePrivate(const QDeclarativeDomValuePrivate &o)
- : QSharedData(o) { qFatal("Not impl"); }
- ~QDeclarativeDomValuePrivate();
-
- QDeclarativeParser::Property *property;
- QDeclarativeParser::Value *value;
-};
-
-class QDeclarativeDomBasicValuePrivate : public QSharedData
-{
-public:
- QDeclarativeDomBasicValuePrivate();
- QDeclarativeDomBasicValuePrivate(const QDeclarativeDomBasicValuePrivate &o)
- : QSharedData(o) { qFatal("Not impl"); }
- ~QDeclarativeDomBasicValuePrivate();
-
- QDeclarativeParser::Value *value;
-};
-
-class QDeclarativeDomImportPrivate : public QSharedData
-{
-public:
- QDeclarativeDomImportPrivate();
- QDeclarativeDomImportPrivate(const QDeclarativeDomImportPrivate &o)
- : QSharedData(o) { qFatal("Not impl"); }
- ~QDeclarativeDomImportPrivate();
-
- enum Type { Library, File };
-
- Type type;
- QString uri;
- QString version;
- QString qualifier;
-};
-
-QT_END_NAMESPACE
-
-#endif // QDECLARATIVEDOM_P_P_H
-
diff --git a/src/declarative/qml/qdeclarativeengine.cpp b/src/declarative/qml/qdeclarativeengine.cpp
index 9e0e299c86..ecd6a2bd7a 100644
--- a/src/declarative/qml/qdeclarativeengine.cpp
+++ b/src/declarative/qml/qdeclarativeengine.cpp
@@ -55,6 +55,7 @@
#include "private/qdeclarativestringconverters_p.h"
#include "private/qdeclarativexmlhttprequest_p.h"
#include "private/qdeclarativesqldatabase_p.h"
+#include "private/qdeclarativescarceresourcescriptclass_p.h"
#include "private/qdeclarativetypenamescriptclass_p.h"
#include "private/qdeclarativelistscriptclass_p.h"
#include "qdeclarativescriptstring.h"
@@ -104,6 +105,8 @@
#include <private/qdeclarativeitemsmodule_p.h>
#include <private/qdeclarativeutilmodule_p.h>
+#include <private/qsgitemsmodule_p.h>
+#include <qsgtexture.h>
#ifdef Q_OS_WIN // for %APPDATA%
#include <qt_windows.h>
@@ -350,13 +353,15 @@ QDeclarativeEnginePrivate::QDeclarativeEnginePrivate(QDeclarativeEngine *e)
objectClass(0), valueTypeClass(0), globalClass(0), cleanup(0), erroredBindings(0),
inProgressCreations(0), scriptEngine(this), workerScriptEngine(0), componentAttached(0),
inBeginCreate(false), networkAccessManager(0), networkAccessManagerFactory(0),
- typeLoader(e), importDatabase(e), uniqueId(1)
+ scarceResources(0), scarceResourcesRefCount(0), typeLoader(e), importDatabase(e), uniqueId(1),
+ sgContext(0)
{
if (!qt_QmlQtModule_registered) {
qt_QmlQtModule_registered = true;
QDeclarativeItemModule::defineModule();
QDeclarativeUtilModule::defineModule();
QDeclarativeEnginePrivate::defineModule();
+ QSGItemsModule::defineModule();
QDeclarativeValueTypeFactory::registerValueTypes();
}
globalClass = new QDeclarativeGlobalScriptClass(&scriptEngine);
@@ -500,6 +505,8 @@ QDeclarativeEnginePrivate::~QDeclarativeEnginePrivate()
contextClass = 0;
delete objectClass;
objectClass = 0;
+ delete scarceResourceClass;
+ scarceResourceClass = 0;
delete valueTypeClass;
valueTypeClass = 0;
delete typeNameClass;
@@ -515,7 +522,10 @@ QDeclarativeEnginePrivate::~QDeclarativeEnginePrivate()
(*iter)->release();
for(QHash<QPair<QDeclarativeType *, int>, QDeclarativePropertyCache *>::Iterator iter = typePropertyCache.begin(); iter != typePropertyCache.end(); ++iter)
(*iter)->release();
-
+ for(QHash<QDeclarativeMetaType::ModuleApi, QDeclarativeMetaType::ModuleApiInstance *>::Iterator iter = moduleApiInstances.begin(); iter != moduleApiInstances.end(); ++iter) {
+ delete (*iter)->qobjectApi;
+ delete *iter;
+ }
}
void QDeclarativeEnginePrivate::clear(SimpleList<QDeclarativeAbstractBinding> &bvs)
@@ -572,6 +582,7 @@ void QDeclarativeEnginePrivate::init()
contextClass = new QDeclarativeContextScriptClass(q);
objectClass = new QDeclarativeObjectScriptClass(q);
+ scarceResourceClass = new QDeclarativeScarceResourceScriptClass(q);
valueTypeClass = new QDeclarativeValueTypeScriptClass(q);
typeNameClass = new QDeclarativeTypeNameScriptClass(q);
listClass = new QDeclarativeListScriptClass(q);
@@ -647,9 +658,23 @@ QDeclarativeEngine::QDeclarativeEngine(QObject *parent)
QDeclarativeEngine::~QDeclarativeEngine()
{
Q_D(QDeclarativeEngine);
- if (d->isDebugging) {
+ if (d->isDebugging)
QDeclarativeEngineDebugServer::instance()->remEngine(this);
- QJSDebugService::instance()->removeEngine(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<QDeclarativeMetaType::ModuleApi> keys = d->moduleApiInstances.keys();
+ QObject *currQObjectApi = 0;
+ QDeclarativeMetaType::ModuleApiInstance *currInstance = 0;
+ foreach (const QDeclarativeMetaType::ModuleApi &key, keys) {
+ currInstance = d->moduleApiInstances.value(key);
+ currQObjectApi = currInstance->qobjectApi;
+ if (this->children().contains(currQObjectApi)) {
+ delete currQObjectApi;
+ delete currInstance;
+ d->moduleApiInstances.remove(key);
+ }
}
}
@@ -814,7 +839,19 @@ QDeclarativeImageProvider::ImageType QDeclarativeEnginePrivate::getImageProvider
locker.unlock();
if (provider)
return provider->imageType();
- return static_cast<QDeclarativeImageProvider::ImageType>(-1);
+ return QDeclarativeImageProvider::Invalid;
+}
+
+QSGTexture *QDeclarativeEnginePrivate::getTextureFromProvider(const QUrl &url, QSize *size, const QSize& req_size)
+{
+ QMutexLocker locker(&mutex);
+ QSharedPointer<QDeclarativeImageProvider> 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 QDeclarativeEnginePrivate::getImageFromProvider(const QUrl &url, QSize *size, const QSize& req_size)
@@ -1315,6 +1352,8 @@ Example (where \c parentItem is the id of an existing QML item):
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).
@@ -1361,7 +1400,7 @@ QScriptValue QDeclarativeEnginePrivate::createQmlObject(QScriptContext *ctxt, QS
QScriptValue arr = ctxt->engine()->newArray(errors.length());
int i = 0;
foreach (const QDeclarativeError &error, errors){
- errstr += QLatin1String(" ") + error.toString() + QLatin1String("\n");
+ errstr += QLatin1String("\n ") + error.toString();
QScriptValue qmlErrObject = ctxt->engine()->newObject();
qmlErrObject.setProperty(QLatin1String("lineNumber"), QScriptValue(error.line()));
qmlErrObject.setProperty(QLatin1String("columnNumber"), QScriptValue(error.column()));
@@ -1388,7 +1427,7 @@ QScriptValue QDeclarativeEnginePrivate::createQmlObject(QScriptContext *ctxt, QS
QScriptValue arr = ctxt->engine()->newArray(errors.length());
int i = 0;
foreach (const QDeclarativeError &error, errors){
- errstr += QLatin1String(" ") + error.toString() + QLatin1String("\n");
+ errstr += QLatin1String("\n ") + error.toString();
QScriptValue qmlErrObject = ctxt->engine()->newObject();
qmlErrObject.setProperty(QLatin1String("lineNumber"), QScriptValue(error.line()));
qmlErrObject.setProperty(QLatin1String("columnNumber"), QScriptValue(error.column()));
@@ -1703,9 +1742,6 @@ QScriptValue QDeclarativeEnginePrivate::rect(QScriptContext *ctxt, QScriptEngine
qsreal w = ctxt->argument(2).toNumber();
qsreal h = ctxt->argument(3).toNumber();
- if (w < 0 || h < 0)
- return engine->nullValue();
-
return QDeclarativeEnginePrivate::get(engine)->scriptValueFromVariant(QVariant::fromValue(QRectF(x, y, w, h)));
}
@@ -2060,7 +2096,9 @@ QScriptValue QDeclarativeEnginePrivate::tint(QScriptContext *ctxt, QScriptEngine
QScriptValue QDeclarativeEnginePrivate::scriptValueFromVariant(const QVariant &val)
{
- if (val.userType() == qMetaTypeId<QDeclarativeListReference>()) {
+ if (variantIsScarceResource(val)) {
+ return scarceResourceClass->newScarceResource(val);
+ } else if (val.userType() == qMetaTypeId<QDeclarativeListReference>()) {
QDeclarativeListReferencePrivate *p =
QDeclarativeListReferencePrivate::get((QDeclarativeListReference*)val.constData());
if (p->object) {
@@ -2089,11 +2127,69 @@ QScriptValue QDeclarativeEnginePrivate::scriptValueFromVariant(const QVariant &v
}
}
+/*
+ If the variant is a scarce resource (consumes a large amount of memory, or
+ only a limited number of them can be held in memory at any given time without
+ exhausting supply for future use) we need to release the scarce resource
+ after evaluation of the javascript binding is complete.
+ */
+bool QDeclarativeEnginePrivate::variantIsScarceResource(const QVariant& val)
+{
+ if (val.type() == QVariant::Pixmap) {
+ return true;
+ } else if (val.type() == QVariant::Image) {
+ return true;
+ }
+
+ return false;
+}
+
+/*
+ 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 QDeclarativeEnginePrivate::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 QDeclarativeEnginePrivate::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.
+ ScarceResourceData *srd = 0;
+ while (scarceResources) {
+ srd = scarceResources; // srd points to the "old" (current) head of the list
+ scarceResources = srd->next; // srd->next is the "new" head of the list
+ if (srd->next) srd->next->prev = &scarceResources; // newHead->prev = listptr.
+ srd->next = 0;
+ srd->prev = 0;
+ srd->releaseResource(); // release the old head node.
+ }
+ }
+}
+
QVariant QDeclarativeEnginePrivate::scriptValueToVariant(const QScriptValue &val, int hint)
{
QScriptDeclarativeClass *dc = QScriptDeclarativeClass::scriptClass(val);
if (dc == objectClass)
return QVariant::fromValue(objectClass->toQObject(val));
+ else if (dc == scarceResourceClass)
+ return scarceResourceClass->toVariant(val);
else if (dc == valueTypeClass)
return valueTypeClass->toVariant(val);
else if (dc == contextClass)
@@ -2222,6 +2318,20 @@ void QDeclarativeEngine::setPluginPathList(const QStringList &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 QDeclarativeExtensionPlugin interface.
+*/
+bool QDeclarativeEngine::importPlugin(const QString &filePath, const QString &uri, QList<QDeclarativeError> *errors)
+{
+ Q_D(QDeclarativeEngine);
+ 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 QDeclarativeExtensionPlugin interface.
@@ -2229,7 +2339,18 @@ void QDeclarativeEngine::setPluginPathList(const QStringList &paths)
bool QDeclarativeEngine::importPlugin(const QString &filePath, const QString &uri, QString *errorString)
{
Q_D(QDeclarativeEngine);
- return d->importDatabase.importPlugin(filePath, uri, errorString);
+ QList<QDeclarativeError> 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;
}
/*!
diff --git a/src/declarative/qml/qdeclarativeengine.h b/src/declarative/qml/qdeclarativeengine.h
index 61ab2b2c63..476ff60ec9 100644
--- a/src/declarative/qml/qdeclarativeengine.h
+++ b/src/declarative/qml/qdeclarativeengine.h
@@ -86,7 +86,8 @@ public:
void setPluginPathList(const QStringList &paths);
void addPluginPath(const QString& dir);
- bool importPlugin(const QString &filePath, const QString &uri, QString *errorString);
+ 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<QDeclarativeError> *errors);
void setNetworkAccessManagerFactory(QDeclarativeNetworkAccessManagerFactory *);
QDeclarativeNetworkAccessManagerFactory *networkAccessManagerFactory() const;
diff --git a/src/declarative/qml/qdeclarativeengine_p.h b/src/declarative/qml/qdeclarativeengine_p.h
index 0a3fe5d130..c690ac7bff 100644
--- a/src/declarative/qml/qdeclarativeengine_p.h
+++ b/src/declarative/qml/qdeclarativeengine_p.h
@@ -67,6 +67,7 @@
#include "private/qdeclarativeproperty_p.h"
#include "private/qdeclarativepropertycache_p.h"
#include "private/qdeclarativeobjectscriptclass_p.h"
+#include "private/qdeclarativescarceresourcescriptclass_p.h"
#include "private/qdeclarativecontextscriptclass_p.h"
#include "private/qdeclarativevaluetypescriptclass_p.h"
#include "private/qdeclarativemetatype_p.h"
@@ -93,6 +94,8 @@ class QDeclarativeExpression;
class QDeclarativeContextScriptClass;
class QDeclarativeImportDatabase;
class QDeclarativeObjectScriptClass;
+class QDeclarativeScarceResourceScriptClass;
+class ScarceResourceData;
class QDeclarativeTypeNameScriptClass;
class QDeclarativeValueTypeScriptClass;
class QNetworkReply;
@@ -109,6 +112,8 @@ class QDeclarativeDelayedError;
class QDeclarativeWorkerScriptEngine;
class QDeclarativeGlobalScriptClass;
class QDir;
+class QSGTexture;
+class QSGContext;
class QDeclarativeScriptEngine : public QScriptEngine
{
@@ -168,6 +173,7 @@ public:
QDeclarativeContextData *sharedContext;
QObject *sharedScope;
QDeclarativeObjectScriptClass *objectClass;
+ QDeclarativeScarceResourceScriptClass *scarceResourceClass;
QDeclarativeValueTypeScriptClass *valueTypeClass;
QDeclarativeTypeNameScriptClass *typeNameClass;
QDeclarativeListScriptClass *listClass;
@@ -232,9 +238,22 @@ public:
QHash<QString,QSharedPointer<QDeclarativeImageProvider> > imageProviders;
QDeclarativeImageProvider::ImageType getImageProviderType(const QUrl &url);
+ QSGTexture *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);
+ /*
+ A scarce resource (like a large pixmap or texture) will be cached in a
+ JavaScript wrapper object when accessed in a binding or other js expression.
+ We need some way to automatically release that scarce resource prior to normal
+ garbage collection (unless the user explicitly preserves the resource).
+ */
+ ScarceResourceData* scarceResources;
+ int scarceResourcesRefCount;
+ static bool variantIsScarceResource(const QVariant& val);
+ void referenceScarceResources();
+ void dereferenceScarceResources();
+
mutable QMutex mutex;
QDeclarativeTypeLoader typeLoader;
@@ -249,6 +268,8 @@ public:
QDeclarativeValueTypeFactory valueTypes;
+ QHash<QDeclarativeMetaType::ModuleApi, QDeclarativeMetaType::ModuleApiInstance *> moduleApiInstances;
+
QHash<const QMetaObject *, QDeclarativePropertyCache *> propertyCache;
QHash<QPair<QDeclarativeType *, int>, QDeclarativePropertyCache *> typePropertyCache;
inline QDeclarativePropertyCache *cache(QObject *obj);
@@ -269,8 +290,6 @@ public:
QHash<int, int> m_qmlLists;
QHash<int, QDeclarativeCompiledData *> m_compositeTypes;
- QHash<QString, QScriptValue> m_sharedScriptImports;
-
QScriptValue scriptValueFromVariant(const QVariant &);
QVariant scriptValueToVariant(const QScriptValue &, int hint = QVariant::Invalid);
@@ -326,6 +345,8 @@ public:
static void defineModule();
static bool qml_debugging_enabled;
+
+ QSGContext *sgContext;
};
/*!
diff --git a/src/declarative/qml/qdeclarativeexpression.cpp b/src/declarative/qml/qdeclarativeexpression.cpp
index e56f819faf..247bde9a6c 100644
--- a/src/declarative/qml/qdeclarativeexpression.cpp
+++ b/src/declarative/qml/qdeclarativeexpression.cpp
@@ -630,7 +630,6 @@ QScriptValue QDeclarativeExpressionPrivate::scriptValue(QObject *secondaryScope,
if (!expressionFunctionValid) {
QDeclarativeEngine *engine = context()->engine;
QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
-
QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine);
QScriptContext *scriptContext = QScriptDeclarativeClass::pushCleanContext(scriptEngine);
@@ -663,8 +662,10 @@ QVariant QDeclarativeExpressionPrivate::value(QObject *secondaryScope, bool *isU
}
QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(q->engine());
-
- return ep->scriptValueToVariant(scriptValue(secondaryScope, isUndefined), qMetaTypeId<QList<QObject*> >());
+ ep->referenceScarceResources(); // "hold" scarce resources in memory during evaluation.
+ QVariant retn(ep->scriptValueToVariant(scriptValue(secondaryScope, isUndefined), qMetaTypeId<QList<QObject*> >()));
+ ep->dereferenceScarceResources(); // "release" scarce resources if top-level expression evaluation is complete.
+ return retn;
}
/*!
diff --git a/src/declarative/qml/qdeclarativeimageprovider.cpp b/src/declarative/qml/qdeclarativeimageprovider.cpp
index 559adf410e..50a3aad733 100644
--- a/src/declarative/qml/qdeclarativeimageprovider.cpp
+++ b/src/declarative/qml/qdeclarativeimageprovider.cpp
@@ -159,6 +159,8 @@ public:
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
*/
/*!
@@ -243,5 +245,36 @@ QPixmap QDeclarativeImageProvider::requestPixmap(const QString &id, QSize *size,
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.
+*/
+
+QSGTexture *QDeclarativeImageProvider::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/declarative/qml/qdeclarativeimageprovider.h b/src/declarative/qml/qdeclarativeimageprovider.h
index ff11afb1e8..8d35d14ccf 100644
--- a/src/declarative/qml/qdeclarativeimageprovider.h
+++ b/src/declarative/qml/qdeclarativeimageprovider.h
@@ -52,13 +52,16 @@ QT_BEGIN_NAMESPACE
QT_MODULE(Declarative)
class QDeclarativeImageProviderPrivate;
+class QSGTexture;
class Q_DECLARATIVE_EXPORT QDeclarativeImageProvider
{
public:
enum ImageType {
Image,
- Pixmap
+ Pixmap,
+ Texture,
+ Invalid
};
QDeclarativeImageProvider(ImageType type);
@@ -68,6 +71,7 @@ public:
virtual QImage requestImage(const QString &id, QSize *size, const QSize& requestedSize);
virtual QPixmap requestPixmap(const QString &id, QSize *size, const QSize& requestedSize);
+ virtual QSGTexture *requestTexture(const QString &id, QSize *size, const QSize &requestedSize);
private:
QDeclarativeImageProviderPrivate *d;
diff --git a/src/declarative/qml/qdeclarativeimport.cpp b/src/declarative/qml/qdeclarativeimport.cpp
index bf261ef242..16b2fa2886 100644
--- a/src/declarative/qml/qdeclarativeimport.cpp
+++ b/src/declarative/qml/qdeclarativeimport.cpp
@@ -83,7 +83,7 @@ public:
QDeclarativeType** type_return, QUrl* url_return,
QUrl *base = 0, bool *typeRecursionDetected = 0);
bool find(const QByteArray& type, int *vmajor, int *vminor, QDeclarativeType** type_return,
- QUrl* url_return, QUrl *base = 0, QString *errorString = 0);
+ QUrl* url_return, QUrl *base = 0, QList<QDeclarativeError> *errors = 0);
};
class QDeclarativeImportsPrivate {
@@ -93,15 +93,15 @@ public:
bool importExtension(const QString &absoluteFilePath, const QString &uri,
QDeclarativeImportDatabase *database, QDeclarativeDirComponents* components,
- QString *errorString);
+ QList<QDeclarativeError> *errors);
QString resolvedUri(const QString &dir_arg, QDeclarativeImportDatabase *database);
bool add(const QDeclarativeDirComponents &qmldircomponentsnetwork,
const QString& uri_arg, const QString& prefix,
int vmaj, int vmin, QDeclarativeScriptParser::Import::Type importType,
- QDeclarativeImportDatabase *database, QString *errorString);
+ QDeclarativeImportDatabase *database, QList<QDeclarativeError> *errors);
bool find(const QByteArray& type, int *vmajor, int *vminor,
- QDeclarativeType** type_return, QUrl* url_return, QString *errorString);
+ QDeclarativeType** type_return, QUrl* url_return, QList<QDeclarativeError> *errors);
QDeclarativeImportedNamespace *findNamespace(const QString& type);
@@ -163,7 +163,7 @@ QUrl QDeclarativeImports::baseUrl() const
static QDeclarativeTypeNameCache *
cacheForNamespace(QDeclarativeEngine *engine, const QDeclarativeImportedNamespace &set,
- QDeclarativeTypeNameCache *cache)
+ QDeclarativeTypeNameCache *cache, bool importWasQualified)
{
if (!cache)
cache = new QDeclarativeTypeNameCache(engine);
@@ -171,10 +171,27 @@ cacheForNamespace(QDeclarativeEngine *engine, const QDeclarativeImportedNamespac
QList<QDeclarativeType *> types = QDeclarativeMetaType::qmlTypes();
for (int ii = 0; ii < set.uris.count(); ++ii) {
- QByteArray base = set.uris.at(ii).toUtf8() + '/';
+ QByteArray uri = set.uris.at(ii).toUtf8();
int major = set.majversions.at(ii);
int minor = set.minversions.at(ii);
+ if (importWasQualified) {
+ QDeclarativeMetaType::ModuleApi moduleApi = QDeclarativeMetaType::moduleApi(uri, major, minor);
+ if (moduleApi.script || moduleApi.qobject) {
+ QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
+ QDeclarativeMetaType::ModuleApiInstance *a = ep->moduleApiInstances.value(moduleApi);
+ if (!a) {
+ a = new QDeclarativeMetaType::ModuleApiInstance;
+ a->scriptCallback = moduleApi.script;
+ a->qobjectCallback = moduleApi.qobject;
+ ep->moduleApiInstances.insert(moduleApi, a);
+ }
+ cache->setModuleApi(a);
+ }
+ }
+
+ QByteArray base = uri + '/';
+
foreach (QDeclarativeType *type, types) {
if (type->qmlTypeName().startsWith(base) &&
type->qmlTypeName().lastIndexOf('/') == (base.length() - 1) &&
@@ -200,15 +217,15 @@ void QDeclarativeImports::populateCache(QDeclarativeTypeNameCache *cache, QDecla
QDeclarativeTypeNameCache::Data *d = cache->data(iter.key());
if (d) {
if (!d->typeNamespace)
- cacheForNamespace(engine, *(*iter), d->typeNamespace);
+ cacheForNamespace(engine, *(*iter), d->typeNamespace, true);
} else {
- QDeclarativeTypeNameCache *nc = cacheForNamespace(engine, *(*iter), 0);
+ QDeclarativeTypeNameCache *nc = cacheForNamespace(engine, *(*iter), 0, true);
cache->add(iter.key(), nc);
nc->release();
}
}
- cacheForNamespace(engine, set, cache);
+ cacheForNamespace(engine, set, cache, false);
}
/*!
@@ -227,7 +244,7 @@ void QDeclarativeImports::populateCache(QDeclarativeTypeNameCache *cache, QDecla
*/
bool QDeclarativeImports::resolveType(const QByteArray& type,
QDeclarativeType** type_return, QUrl* url_return, int *vmaj, int *vmin,
- QDeclarativeImportedNamespace** ns_return, QString *errorString) const
+ QDeclarativeImportedNamespace** ns_return, QList<QDeclarativeError> *errors) const
{
QDeclarativeImportedNamespace* ns = d->findNamespace(QString::fromUtf8(type));
if (ns) {
@@ -236,7 +253,7 @@ bool QDeclarativeImports::resolveType(const QByteArray& type,
return true;
}
if (type_return || url_return) {
- if (d->find(type,vmaj,vmin,type_return,url_return, errorString)) {
+ 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() << "QDeclarativeImports(" << qPrintable(baseUrl().toString()) << ")" << "::resolveType: "
@@ -351,13 +368,16 @@ QDeclarativeImportsPrivate::~QDeclarativeImportsPrivate()
bool QDeclarativeImportsPrivate::importExtension(const QString &absoluteFilePath, const QString &uri,
QDeclarativeImportDatabase *database,
- QDeclarativeDirComponents* components, QString *errorString)
+ QDeclarativeDirComponents* components, QList<QDeclarativeError> *errors)
{
QFile file(absoluteFilePath);
QString filecontent;
if (!QDeclarative_isFileCaseCorrect(absoluteFilePath)) {
- if (errorString)
- *errorString = QDeclarativeImportDatabase::tr("cannot load module \"%1\": File name case mismatch for \"%2\"").arg(uri).arg(absoluteFilePath);
+ if (errors) {
+ QDeclarativeError error;
+ error.setDescription(QDeclarativeImportDatabase::tr("cannot load module \"%1\": File name case mismatch for \"%2\"").arg(uri).arg(absoluteFilePath));
+ errors->prepend(error);
+ }
return false;
} else if (file.open(QFile::ReadOnly)) {
filecontent = QString::fromUtf8(file.readAll());
@@ -365,15 +385,29 @@ bool QDeclarativeImportsPrivate::importExtension(const QString &absoluteFilePath
qDebug().nospace() << "QDeclarativeImports(" << qPrintable(base.toString()) << "::importExtension: "
<< "loaded " << absoluteFilePath;
} else {
- if (errorString)
- *errorString = QDeclarativeImportDatabase::tr("module \"%1\" definition \"%2\" not readable").arg(uri).arg(absoluteFilePath);
+ if (errors) {
+ QDeclarativeError error;
+ error.setDescription(QDeclarativeImportDatabase::tr("module \"%1\" definition \"%2\" not readable").arg(uri).arg(absoluteFilePath));
+ errors->prepend(error);
+ }
return false;
}
QDir dir = QFileInfo(file).dir();
+ QUrl url = QUrl::fromLocalFile(absoluteFilePath);
QDeclarativeDirParser qmldirParser;
qmldirParser.setSource(filecontent);
- qmldirParser.parse();
+ qmldirParser.setUrl(url);
+
+ // propagate any errors reported by the parser back up to the typeloader.
+ if (qmldirParser.parse()) {
+ if (errors) {
+ for (int i = 0; i < qmldirParser.errors().size(); ++i) {
+ errors->prepend(qmldirParser.errors().at(i));
+ }
+ }
+ return false;
+ }
if (! qmlDirFilesForWhichPluginsHaveBeenLoaded.contains(absoluteFilePath)) {
qmlDirFilesForWhichPluginsHaveBeenLoaded.insert(absoluteFilePath);
@@ -390,14 +424,26 @@ bool QDeclarativeImportsPrivate::importExtension(const QString &absoluteFilePath
}
#endif
if (!resolvedFilePath.isEmpty()) {
- if (!database->importPlugin(resolvedFilePath, uri, errorString)) {
- if (errorString)
- *errorString = QDeclarativeImportDatabase::tr("plugin cannot be loaded for module \"%1\": %2").arg(uri).arg(*errorString);
+ 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.
+ QDeclarativeError poppedError = errors->takeFirst();
+ QDeclarativeError error;
+ error.setDescription(QDeclarativeImportDatabase::tr("plugin cannot be loaded for module \"%1\": %2").arg(uri).arg(poppedError.description()));
+ error.setUrl(url);
+ errors->prepend(error);
+ }
return false;
}
} else {
- if (errorString)
- *errorString = QDeclarativeImportDatabase::tr("module \"%1\" plugin \"%2\" not found").arg(uri).arg(plugin.name);
+ if (errors) {
+ QDeclarativeError error;
+ error.setDescription(QDeclarativeImportDatabase::tr("module \"%1\" plugin \"%2\" not found").arg(uri).arg(plugin.name));
+ error.setUrl(url);
+ errors->prepend(error);
+ }
return false;
}
}
@@ -443,7 +489,7 @@ QString QDeclarativeImportsPrivate::resolvedUri(const QString &dir_arg, QDeclara
bool QDeclarativeImportsPrivate::add(const QDeclarativeDirComponents &qmldircomponentsnetwork,
const QString& uri_arg, const QString& prefix, int vmaj, int vmin,
QDeclarativeScriptParser::Import::Type importType,
- QDeclarativeImportDatabase *database, QString *errorString)
+ QDeclarativeImportDatabase *database, QList<QDeclarativeError> *errors)
{
QDeclarativeDirComponents qmldircomponents = qmldircomponentsnetwork;
QString uri = uri_arg;
@@ -477,7 +523,7 @@ bool QDeclarativeImportsPrivate::add(const QDeclarativeDirComponents &qmldircomp
url = QUrl::fromLocalFile(fi.absolutePath()).toString();
uri = resolvedUri(dir, database);
- if (!importExtension(absoluteFilePath, uri, database, &qmldircomponents, errorString))
+ if (!importExtension(absoluteFilePath, uri, database, &qmldircomponents, errors))
return false;
break;
}
@@ -496,7 +542,7 @@ bool QDeclarativeImportsPrivate::add(const QDeclarativeDirComponents &qmldircomp
url = QUrl::fromLocalFile(fi.absolutePath()).toString();
uri = resolvedUri(dir, database);
- if (!importExtension(absoluteFilePath, uri, database, &qmldircomponents, errorString))
+ if (!importExtension(absoluteFilePath, uri, database, &qmldircomponents, errors))
return false;
break;
}
@@ -516,7 +562,7 @@ bool QDeclarativeImportsPrivate::add(const QDeclarativeDirComponents &qmldircomp
url = QUrl::fromLocalFile(fi.absolutePath()).toString();
uri = resolvedUri(dir, database);
- if (!importExtension(absoluteFilePath, uri, database, &qmldircomponents, errorString))
+ if (!importExtension(absoluteFilePath, uri, database, &qmldircomponents, errors))
return false;
break;
}
@@ -527,12 +573,14 @@ bool QDeclarativeImportsPrivate::add(const QDeclarativeDirComponents &qmldircomp
versionFound = true;
if (!versionFound && qmldircomponents.isEmpty()) {
- if (errorString) {
+ if (errors) {
bool anyversion = QDeclarativeMetaType::isModule(uri.toUtf8(), -1, -1);
+ QDeclarativeError error; // we don't set the url or line or column as these will be set by the loader.
if (anyversion)
- *errorString = QDeclarativeImportDatabase::tr("module \"%1\" version %2.%3 is not installed").arg(uri_arg).arg(vmaj).arg(vmin);
+ error.setDescription(QDeclarativeImportDatabase::tr("module \"%1\" version %2.%3 is not installed").arg(uri_arg).arg(vmaj).arg(vmin));
else
- *errorString = QDeclarativeImportDatabase::tr("module \"%1\" is not installed").arg(uri_arg);
+ error.setDescription(QDeclarativeImportDatabase::tr("module \"%1\" is not installed").arg(uri_arg));
+ errors->prepend(error);
}
return false;
}
@@ -545,15 +593,19 @@ bool QDeclarativeImportsPrivate::add(const QDeclarativeDirComponents &qmldircomp
QString dir = QDeclarativeEnginePrivate::urlToLocalFileOrQrc(base.resolved(QUrl(uri)));
QFileInfo dirinfo(dir);
if (dir.isEmpty() || !dirinfo.exists() || !dirinfo.isDir()) {
- if (errorString)
- *errorString = QDeclarativeImportDatabase::tr("\"%1\": no such directory").arg(uri_arg);
+ if (errors) {
+ QDeclarativeError error; // we don't set the line or column as these will be set by the loader.
+ error.setDescription(QDeclarativeImportDatabase::tr("\"%1\": no such directory").arg(uri_arg));
+ error.setUrl(importUrl);
+ errors->prepend(error);
+ }
return false; // local import dirs must exist
}
uri = resolvedUri(QDeclarativeEnginePrivate::urlToLocalFileOrQrc(base.resolved(QUrl(uri))), database);
if (uri.endsWith(QLatin1Char('/')))
uri.chop(1);
if (QFile::exists(localFileOrQrc)) {
- if (!importExtension(localFileOrQrc,uri,database,&qmldircomponents,errorString))
+ if (!importExtension(localFileOrQrc,uri,database,&qmldircomponents,errors))
return false;
}
} else {
@@ -562,11 +614,14 @@ bool QDeclarativeImportsPrivate::add(const QDeclarativeDirComponents &qmldircomp
QString localFileOrQrc = QDeclarativeEnginePrivate::urlToLocalFileOrQrc(base.resolved(QUrl(uri)));
QFileInfo dirinfo(localFileOrQrc);
if (localFileOrQrc.isEmpty() || !dirinfo.exists() || !dirinfo.isDir()) {
- if (errorString) {
+ if (errors) {
+ QDeclarativeError error; // we don't set the line or column as these will be set by the loader.
if (localFileOrQrc.isEmpty())
- *errorString = QDeclarativeImportDatabase::tr("import \"%1\" has no qmldir and no namespace").arg(uri);
+ error.setDescription(QDeclarativeImportDatabase::tr("import \"%1\" has no qmldir and no namespace").arg(uri));
else
- *errorString = QDeclarativeImportDatabase::tr("\"%1\": no such directory").arg(uri);
+ error.setDescription(QDeclarativeImportDatabase::tr("\"%1\": no such directory").arg(uri));
+ error.setUrl(importUrl);
+ errors->prepend(error);
}
return false;
}
@@ -598,7 +653,11 @@ bool QDeclarativeImportsPrivate::add(const QDeclarativeDirComponents &qmldircomp
if (lowest_maj > vmaj || (lowest_maj == vmaj && lowest_min > vmin)
|| highest_maj < vmaj || (highest_maj == vmaj && highest_min < vmin))
{
- *errorString = QDeclarativeImportDatabase::tr("module \"%1\" version %2.%3 is not installed").arg(uri_arg).arg(vmaj).arg(vmin);
+ if (errors) {
+ QDeclarativeError error; // we don't set the url or line or column information, as these will be set by the loader.
+ error.setDescription(QDeclarativeImportDatabase::tr("module \"%1\" version %2.%3 is not installed").arg(uri_arg).arg(vmaj).arg(vmin));
+ errors->prepend(error);
+ }
return false;
}
}
@@ -613,7 +672,7 @@ bool QDeclarativeImportsPrivate::add(const QDeclarativeDirComponents &qmldircomp
}
bool QDeclarativeImportsPrivate::find(const QByteArray& type, int *vmajor, int *vminor, QDeclarativeType** type_return,
- QUrl* url_return, QString *errorString)
+ QUrl* url_return, QList<QDeclarativeError> *errors)
{
QDeclarativeImportedNamespace *s = 0;
int slash = type.indexOf('/');
@@ -621,14 +680,20 @@ bool QDeclarativeImportsPrivate::find(const QByteArray& type, int *vmajor, int *
QString namespaceName = QString::fromUtf8(type.left(slash));
s = set.value(namespaceName);
if (!s) {
- if (errorString)
- *errorString = QDeclarativeImportDatabase::tr("- %1 is not a namespace").arg(namespaceName);
+ if (errors) {
+ QDeclarativeError error;
+ error.setDescription(QDeclarativeImportDatabase::tr("- %1 is not a namespace").arg(namespaceName));
+ errors->prepend(error);
+ }
return false;
}
int nslash = type.indexOf('/',slash+1);
if (nslash > 0) {
- if (errorString)
- *errorString = QDeclarativeImportDatabase::tr("- nested namespaces not allowed");
+ if (errors) {
+ QDeclarativeError error;
+ error.setDescription(QDeclarativeImportDatabase::tr("- nested namespaces not allowed"));
+ errors->prepend(error);
+ }
return false;
}
} else {
@@ -636,7 +701,7 @@ bool QDeclarativeImportsPrivate::find(const QByteArray& type, int *vmajor, int *
}
QByteArray unqualifiedtype = slash < 0 ? type : type.mid(slash+1); // common-case opt (QString::mid works fine, but slower)
if (s) {
- if (s->find(unqualifiedtype,vmajor,vminor,type_return,url_return, &base, errorString))
+ if (s->find(unqualifiedtype,vmajor,vminor,type_return,url_return, &base, errors))
return true;
if (s->urls.count() == 1 && !s->isLibrary[0] && url_return && s != &unqualifiedset) {
// qualified, and only 1 url
@@ -654,7 +719,7 @@ QDeclarativeImportedNamespace *QDeclarativeImportsPrivate::findNamespace(const Q
}
bool QDeclarativeImportedNamespace::find(const QByteArray& type, int *vmajor, int *vminor, QDeclarativeType** type_return,
- QUrl* url_return, QUrl *base, QString *errorString)
+ QUrl* url_return, QUrl *base, QList<QDeclarativeError> *errors)
{
bool typeRecursionDetected = false;
for (int i=0; i<urls.count(); ++i) {
@@ -663,7 +728,7 @@ bool QDeclarativeImportedNamespace::find(const QByteArray& type, int *vmajor, in
// check for type clashes
for (int j = i+1; j<urls.count(); ++j) {
if (find_helper(j, type, vmajor, vminor, 0, 0, base)) {
- if (errorString) {
+ if (errors) {
QString u1 = urls.at(i);
QString u2 = urls.at(j);
if (base) {
@@ -683,16 +748,16 @@ bool QDeclarativeImportedNamespace::find(const QByteArray& type, int *vmajor, in
}
}
- if (u1 != u2)
- *errorString
- = QDeclarativeImportDatabase::tr("is ambiguous. Found in %1 and in %2")
- .arg(u1).arg(u2);
- else
- *errorString
- = QDeclarativeImportDatabase::tr("is ambiguous. Found in %1 in version %2.%3 and %4.%5")
- .arg(u1)
- .arg(majversions.at(i)).arg(minversions.at(i))
- .arg(majversions.at(j)).arg(minversions.at(j));
+ QDeclarativeError error;
+ if (u1 != u2) {
+ error.setDescription(QDeclarativeImportDatabase::tr("is ambiguous. Found in %1 and in %2").arg(u1).arg(u2));
+ } else {
+ error.setDescription(QDeclarativeImportDatabase::tr("is ambiguous. Found in %1 in version %2.%3 and %4.%5")
+ .arg(u1)
+ .arg(majversions.at(i)).arg(minversions.at(i))
+ .arg(majversions.at(j)).arg(minversions.at(j)));
+ }
+ errors->prepend(error);
}
return false;
}
@@ -701,11 +766,13 @@ bool QDeclarativeImportedNamespace::find(const QByteArray& type, int *vmajor, in
return true;
}
}
- if (errorString) {
+ if (errors) {
+ QDeclarativeError error;
if (typeRecursionDetected)
- *errorString = QDeclarativeImportDatabase::tr("is instantiated recursively");
+ error.setDescription(QDeclarativeImportDatabase::tr("is instantiated recursively"));
else
- *errorString = QDeclarativeImportDatabase::tr("is not a type");
+ error.setDescription(QDeclarativeImportDatabase::tr("is not a type"));
+ errors->prepend(error);
}
return false;
}
@@ -790,7 +857,7 @@ bool QDeclarativeImports::addImport(QDeclarativeImportDatabase *importDb,
const QString& uri, const QString& prefix, int vmaj, int vmin,
QDeclarativeScriptParser::Import::Type importType,
const QDeclarativeDirComponents &qmldircomponentsnetwork,
- QString *errorString)
+ QList<QDeclarativeError> *errors)
{
if (qmlImportTrace())
qDebug().nospace() << "QDeclarativeImports(" << qPrintable(baseUrl().toString()) << ")" << "::addImport: "
@@ -798,7 +865,7 @@ bool QDeclarativeImports::addImport(QDeclarativeImportDatabase *importDb,
<< (importType==QDeclarativeScriptParser::Import::Library? "Library" : "File")
<< " as " << prefix;
- return d->add(qmldircomponentsnetwork, uri, prefix, vmaj, vmin, importType, importDb, errorString);
+ return d->add(qmldircomponentsnetwork, uri, prefix, vmaj, vmin, importType, importDb, errors);
}
/*!
@@ -1013,7 +1080,7 @@ void QDeclarativeImportDatabase::setImportPathList(const QStringList &paths)
/*!
\internal
*/
-bool QDeclarativeImportDatabase::importPlugin(const QString &filePath, const QString &uri, QString *errorString)
+bool QDeclarativeImportDatabase::importPlugin(const QString &filePath, const QString &uri, QList<QDeclarativeError> *errors)
{
if (qmlImportTrace())
qDebug().nospace() << "QDeclarativeImportDatabase::importPlugin: " << uri << " from " << filePath;
@@ -1033,15 +1100,21 @@ bool QDeclarativeImportDatabase::importPlugin(const QString &filePath, const QSt
if (!engineInitialized || !typesRegistered) {
if (!QDeclarative_isFileCaseCorrect(absoluteFilePath)) {
- if (errorString)
- *errorString = tr("File name case mismatch for \"%2\"").arg(absoluteFilePath);
+ if (errors) {
+ QDeclarativeError error;
+ error.setDescription(tr("File name case mismatch for \"%2\"").arg(absoluteFilePath));
+ errors->prepend(error);
+ }
return false;
}
QPluginLoader loader(absoluteFilePath);
if (!loader.load()) {
- if (errorString)
- *errorString = loader.errorString();
+ if (errors) {
+ QDeclarativeError error;
+ error.setDescription(loader.errorString());
+ errors->prepend(error);
+ }
return false;
}
@@ -1063,8 +1136,11 @@ bool QDeclarativeImportDatabase::importPlugin(const QString &filePath, const QSt
iface->initializeEngine(engine, moduleId);
}
} else {
- if (errorString)
- *errorString = loader.errorString();
+ if (errors) {
+ QDeclarativeError error;
+ error.setDescription(loader.errorString());
+ errors->prepend(error);
+ }
return false;
}
}
diff --git a/src/declarative/qml/qdeclarativeimport_p.h b/src/declarative/qml/qdeclarativeimport_p.h
index 319e76ce98..fe9404d9b2 100644
--- a/src/declarative/qml/qdeclarativeimport_p.h
+++ b/src/declarative/qml/qdeclarativeimport_p.h
@@ -84,7 +84,7 @@ public:
QDeclarativeType** type_return, QUrl* url_return,
int *version_major, int *version_minor,
QDeclarativeImportedNamespace** ns_return,
- QString *errorString = 0) const;
+ QList<QDeclarativeError> *errors = 0) const;
bool resolveType(QDeclarativeImportedNamespace*,
const QByteArray& type,
QDeclarativeType** type_return, QUrl* url_return,
@@ -94,7 +94,7 @@ public:
const QString& uri, const QString& prefix, int vmaj, int vmin,
QDeclarativeScriptParser::Import::Type importType,
const QDeclarativeDirComponents &qmldircomponentsnetwork,
- QString *errorString);
+ QList<QDeclarativeError> *errors);
void populateCache(QDeclarativeTypeNameCache *cache, QDeclarativeEngine *) const;
@@ -110,7 +110,7 @@ public:
QDeclarativeImportDatabase(QDeclarativeEngine *);
~QDeclarativeImportDatabase();
- bool importPlugin(const QString &filePath, const QString &uri, QString *errorString);
+ bool importPlugin(const QString &filePath, const QString &uri, QList<QDeclarativeError> *errors);
QStringList importPathList() const;
void setImportPathList(const QStringList &paths);
diff --git a/src/declarative/qml/qdeclarativeinfo.cpp b/src/declarative/qml/qdeclarativeinfo.cpp
index 2fd5347782..e2f728ad69 100644
--- a/src/declarative/qml/qdeclarativeinfo.cpp
+++ b/src/declarative/qml/qdeclarativeinfo.cpp
@@ -129,6 +129,18 @@ QDeclarativeInfo::~QDeclarativeInfo()
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) + "*";
+ type = QDeclarativeMetaType::qmlType(QMetaType::type(typeName.toLatin1()));
+ if (type) {
+ typeName = QLatin1String(type->qmlTypeName());
+ int lastSlash = typeName.lastIndexOf(QLatin1Char('/'));
+ if (lastSlash != -1)
+ typeName = typeName.mid(lastSlash+1);
+ }
+ }
}
d->buffer.prepend(QLatin1String("QML ") + typeName + QLatin1String(": "));
diff --git a/src/declarative/qml/qdeclarativeinstruction.cpp b/src/declarative/qml/qdeclarativeinstruction.cpp
index 446c9ab37c..fa0d8ea6f4 100644
--- a/src/declarative/qml/qdeclarativeinstruction.cpp
+++ b/src/declarative/qml/qdeclarativeinstruction.cpp
@@ -53,178 +53,184 @@ void QDeclarativeCompiledData::dump(QDeclarativeInstruction *instr, int idx)
Q_UNUSED(instr)
Q_UNUSED(idx)
#else
- QByteArray lineNumber = QByteArray::number(instr->line);
- if (instr->line == (unsigned short)-1)
- lineNumber = "NA";
- const char *line = lineNumber.constData();
-
- switch(instr->type) {
+ switch(instr->type()) {
case QDeclarativeInstruction::Init:
- qWarning().nospace() << idx << "\t\t" << line << "\t" << "INIT\t\t\t" << instr->init.bindingsSize << "\t" << instr->init.parserStatusSize << "\t" << instr->init.contextCache << "\t" << instr->init.compiledBinding;
+ 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 QDeclarativeInstruction::Done:
+ qWarning().nospace() << idx << "\t\t" << "DONE";
break;
case QDeclarativeInstruction::CreateObject:
- qWarning().nospace() << idx << "\t\t" << line << "\t" << "CREATE\t\t\t" << instr->create.type << "\t" << instr->create.bindingBits << "\t\t" << types.at(instr->create.type).className;
+ qWarning().nospace() << idx << "\t\t" << "CREATE\t\t\t" << instr->create.type << "\t" << instr->create.bindingBits << "\t\t" << types.at(instr->create.type).className;
break;
case QDeclarativeInstruction::CreateSimpleObject:
- qWarning().nospace() << idx << "\t\t" << line << "\t" << "CREATE_SIMPLE\t\t" << instr->createSimple.typeSize;
+ qWarning().nospace() << idx << "\t\t" << "CREATE_SIMPLE\t\t" << instr->createSimple.typeSize;
break;
case QDeclarativeInstruction::SetId:
- qWarning().nospace() << idx << "\t\t" << line << "\t" << "SETID\t\t\t" << instr->setId.value << "\t\t\t" << primitives.at(instr->setId.value);
+ qWarning().nospace() << idx << "\t\t" << "SETID\t\t\t" << instr->setId.value << "\t\t\t" << primitives.at(instr->setId.value);
break;
case QDeclarativeInstruction::SetDefault:
- qWarning().nospace() << idx << "\t\t" << line << "\t" << "SET_DEFAULT";
+ qWarning().nospace() << idx << "\t\t" << "SET_DEFAULT";
break;
case QDeclarativeInstruction::CreateComponent:
- qWarning().nospace() << idx << "\t\t" << line << "\t" << "CREATE_COMPONENT\t" << instr->createComponent.count;
+ qWarning().nospace() << idx << "\t\t" << "CREATE_COMPONENT\t" << instr->createComponent.count;
break;
case QDeclarativeInstruction::StoreMetaObject:
- qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_META\t\t" << instr->storeMeta.data;
+ qWarning().nospace() << idx << "\t\t" << "STORE_META\t\t" << instr->storeMeta.data;
break;
-
case QDeclarativeInstruction::StoreFloat:
- qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_FLOAT\t\t" << instr->storeFloat.propertyIndex << "\t" << instr->storeFloat.value;
+ qWarning().nospace() << idx << "\t\t" << "STORE_FLOAT\t\t" << instr->storeFloat.propertyIndex << "\t" << instr->storeFloat.value;
break;
case QDeclarativeInstruction::StoreDouble:
- qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_DOUBLE\t\t" << instr->storeDouble.propertyIndex << "\t" << instr->storeDouble.value;
+ qWarning().nospace() << idx << "\t\t" << "STORE_DOUBLE\t\t" << instr->storeDouble.propertyIndex << "\t" << instr->storeDouble.value;
break;
case QDeclarativeInstruction::StoreInteger:
- qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_INTEGER\t\t" << instr->storeInteger.propertyIndex << "\t" << instr->storeInteger.value;
+ qWarning().nospace() << idx << "\t\t" << "STORE_INTEGER\t\t" << instr->storeInteger.propertyIndex << "\t" << instr->storeInteger.value;
break;
case QDeclarativeInstruction::StoreBool:
- qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_BOOL\t\t" << instr->storeBool.propertyIndex << "\t" << instr->storeBool.value;
+ qWarning().nospace() << idx << "\t\t" << "STORE_BOOL\t\t" << instr->storeBool.propertyIndex << "\t" << instr->storeBool.value;
break;
case QDeclarativeInstruction::StoreString:
- qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_STRING\t\t" << instr->storeString.propertyIndex << "\t" << instr->storeString.value << "\t\t" << primitives.at(instr->storeString.value);
+ 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 QDeclarativeInstruction::StoreByteArray:
+ qWarning().nospace() << idx << "\t\t" << "STORE_BYTEARRAY" << instr->storeByteArray.propertyIndex << "\t" << instr->storeByteArray.value << "\t\t" << datas.at(instr->storeByteArray.value);
break;
case QDeclarativeInstruction::StoreUrl:
- qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_URL\t\t" << instr->storeUrl.propertyIndex << "\t" << instr->storeUrl.value << "\t\t" << urls.at(instr->storeUrl.value);
+ 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 QDeclarativeInstruction::StoreColor:
- qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_COLOR\t\t" << instr->storeColor.propertyIndex << "\t\t\t" << QString::number(instr->storeColor.value, 16);
+ qWarning().nospace() << idx << "\t\t" << "STORE_COLOR\t\t" << instr->storeColor.propertyIndex << "\t\t\t" << QString::number(instr->storeColor.value, 16);
break;
case QDeclarativeInstruction::StoreDate:
- qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_DATE\t\t" << instr->storeDate.propertyIndex << "\t" << instr->storeDate.value;
+ qWarning().nospace() << idx << "\t\t" << "STORE_DATE\t\t" << instr->storeDate.propertyIndex << "\t" << instr->storeDate.value;
break;
case QDeclarativeInstruction::StoreTime:
- qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_TIME\t\t" << instr->storeTime.propertyIndex << "\t" << instr->storeTime.valueIndex;
+ qWarning().nospace() << idx << "\t\t" << "STORE_TIME\t\t" << instr->storeTime.propertyIndex;
break;
case QDeclarativeInstruction::StoreDateTime:
- qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_DATETIME\t\t" << instr->storeDateTime.propertyIndex << "\t" << instr->storeDateTime.valueIndex;
+ qWarning().nospace() << idx << "\t\t" << "STORE_DATETIME\t\t" << instr->storeDateTime.propertyIndex;
break;
case QDeclarativeInstruction::StorePoint:
- qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_POINT\t\t" << instr->storeRealPair.propertyIndex << "\t" << instr->storeRealPair.valueIndex;
+ qWarning().nospace() << idx << "\t\t" << "STORE_POINT\t\t" << instr->storePoint.propertyIndex << "\t" << instr->storePoint.point.xp << "\t" << instr->storePoint.point.yp;
break;
case QDeclarativeInstruction::StorePointF:
- qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_POINTF\t\t" << instr->storeRealPair.propertyIndex << "\t" << instr->storeRealPair.valueIndex;
+ qWarning().nospace() << idx << "\t\t" << "STORE_POINTF\t\t" << instr->storePointF.propertyIndex << "\t" << instr->storePointF.point.xp << "\t" << instr->storePointF.point.yp;
break;
case QDeclarativeInstruction::StoreSize:
- qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_SIZE\t\t" << instr->storeRealPair.propertyIndex << "\t" << instr->storeRealPair.valueIndex;
+ qWarning().nospace() << idx << "\t\t" << "STORE_SIZE\t\t" << instr->storeSize.propertyIndex << "\t" << instr->storeSize.size.wd << "\t" << instr->storeSize.size.ht;
break;
case QDeclarativeInstruction::StoreSizeF:
- qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_SIZEF\t\t" << instr->storeRealPair.propertyIndex << "\t" << instr->storeRealPair.valueIndex;
+ qWarning().nospace() << idx << "\t\t" << "STORE_SIZEF\t\t" << instr->storeSizeF.propertyIndex << "\t" << instr->storeSizeF.size.wd << "\t" << instr->storeSizeF.size.ht;
break;
case QDeclarativeInstruction::StoreRect:
- qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_RECT\t\t" << instr->storeRect.propertyIndex << "\t" << instr->storeRect.valueIndex;
+ 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 QDeclarativeInstruction::StoreRectF:
- qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_RECTF\t\t" << instr->storeRect.propertyIndex << "\t" << instr->storeRect.valueIndex;
+ 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 QDeclarativeInstruction::StoreVector3D:
- qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_VECTOR3D\t\t" << instr->storeVector3D.propertyIndex << "\t" << instr->storeVector3D.valueIndex;
+ 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 QDeclarativeInstruction::StoreVariant:
- qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_VARIANT\t\t" << instr->storeString.propertyIndex << "\t" << instr->storeString.value << "\t\t" << primitives.at(instr->storeString.value);
+ 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 QDeclarativeInstruction::StoreVariantInteger:
- qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_VARIANT_INTEGER\t\t" << instr->storeInteger.propertyIndex << "\t" << instr->storeInteger.value;
+ qWarning().nospace() << idx << "\t\t" << "STORE_VARIANT_INTEGER\t\t" << instr->storeInteger.propertyIndex << "\t" << instr->storeInteger.value;
break;
case QDeclarativeInstruction::StoreVariantDouble:
- qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_VARIANT_DOUBLE\t\t" << instr->storeDouble.propertyIndex << "\t" << instr->storeDouble.value;
+ qWarning().nospace() << idx << "\t\t" << "STORE_VARIANT_DOUBLE\t\t" << instr->storeDouble.propertyIndex << "\t" << instr->storeDouble.value;
break;
case QDeclarativeInstruction::StoreVariantBool:
- qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_VARIANT_BOOL\t\t" << instr->storeBool.propertyIndex << "\t" << instr->storeBool.value;
+ qWarning().nospace() << idx << "\t\t" << "STORE_VARIANT_BOOL\t\t" << instr->storeBool.propertyIndex << "\t" << instr->storeBool.value;
break;
case QDeclarativeInstruction::StoreObject:
- qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_OBJECT\t\t" << instr->storeObject.propertyIndex;
+ qWarning().nospace() << idx << "\t\t" << "STORE_OBJECT\t\t" << instr->storeObject.propertyIndex;
break;
case QDeclarativeInstruction::StoreVariantObject:
- qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_VARIANT_OBJECT\t" << instr->storeObject.propertyIndex;
+ qWarning().nospace() << idx << "\t\t" << "STORE_VARIANT_OBJECT\t" << instr->storeObject.propertyIndex;
break;
case QDeclarativeInstruction::StoreInterface:
- qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_INTERFACE\t\t" << instr->storeObject.propertyIndex;
+ qWarning().nospace() << idx << "\t\t" << "STORE_INTERFACE\t\t" << instr->storeObject.propertyIndex;
break;
-
case QDeclarativeInstruction::StoreSignal:
- qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_SIGNAL\t\t" << instr->storeSignal.signalIndex << "\t" << instr->storeSignal.value << "\t\t" << primitives.at(instr->storeSignal.value);
+ 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 QDeclarativeInstruction::StoreImportedScript:
- qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_IMPORTED_SCRIPT\t" << instr->storeScript.value;
+ qWarning().nospace() << idx << "\t\t" << "STORE_IMPORTED_SCRIPT\t" << instr->storeScript.value;
break;
case QDeclarativeInstruction::StoreScriptString:
- qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_SCRIPT_STRING\t" << instr->storeScriptString.propertyIndex << "\t" << instr->storeScriptString.value << "\t" << instr->storeScriptString.scope;
+ qWarning().nospace() << idx << "\t\t" << "STORE_SCRIPT_STRING\t" << instr->storeScriptString.propertyIndex << "\t" << instr->storeScriptString.value << "\t" << instr->storeScriptString.scope;
break;
-
case QDeclarativeInstruction::AssignSignalObject:
- qWarning().nospace() << idx << "\t\t" << line << "\t" << "ASSIGN_SIGNAL_OBJECT\t" << instr->assignSignalObject.signal << "\t\t\t" << datas.at(instr->assignSignalObject.signal);
+ qWarning().nospace() << idx << "\t\t" << "ASSIGN_SIGNAL_OBJECT\t" << instr->assignSignalObject.signal << "\t\t\t" << datas.at(instr->assignSignalObject.signal);
break;
case QDeclarativeInstruction::AssignCustomType:
- qWarning().nospace() << idx << "\t\t" << line << "\t" << "ASSIGN_CUSTOMTYPE\t" << instr->assignCustomType.propertyIndex << "\t" << instr->assignCustomType.valueIndex;
+ qWarning().nospace() << idx << "\t\t" << "ASSIGN_CUSTOMTYPE\t" << instr->assignCustomType.propertyIndex << "\t" << instr->assignCustomType.primitive << "\t" << instr->assignCustomType.type;
break;
-
case QDeclarativeInstruction::StoreBinding:
- qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_BINDING\t" << instr->assignBinding.property << "\t" << instr->assignBinding.value << "\t" << instr->assignBinding.context;
+ qWarning().nospace() << idx << "\t\t" << "STORE_BINDING\t" << instr->assignBinding.property << "\t" << instr->assignBinding.value << "\t" << instr->assignBinding.context;
break;
case QDeclarativeInstruction::StoreBindingOnAlias:
- qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_BINDING_ALIAS\t" << instr->assignBinding.property << "\t" << instr->assignBinding.value << "\t" << instr->assignBinding.context;
+ qWarning().nospace() << idx << "\t\t" << "STORE_BINDING_ALIAS\t" << instr->assignBinding.property << "\t" << instr->assignBinding.value << "\t" << instr->assignBinding.context;
break;
case QDeclarativeInstruction::StoreCompiledBinding:
- qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_COMPILED_BINDING\t" << instr->assignBinding.property << "\t" << instr->assignBinding.value << "\t" << instr->assignBinding.context;
+ qWarning().nospace() << idx << "\t\t" << "STORE_COMPILED_BINDING\t" << instr->assignBinding.property << "\t" << instr->assignBinding.value << "\t" << instr->assignBinding.context;
break;
case QDeclarativeInstruction::StoreValueSource:
- qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_VALUE_SOURCE\t" << instr->assignValueSource.property << "\t" << instr->assignValueSource.castValue;
+ qWarning().nospace() << idx << "\t\t" << "STORE_VALUE_SOURCE\t" << instr->assignValueSource.property << "\t" << instr->assignValueSource.castValue;
break;
case QDeclarativeInstruction::StoreValueInterceptor:
- qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_VALUE_INTERCEPTOR\t" << instr->assignValueInterceptor.property << "\t" << instr->assignValueInterceptor.castValue;
+ qWarning().nospace() << idx << "\t\t" << "STORE_VALUE_INTERCEPTOR\t" << instr->assignValueInterceptor.property << "\t" << instr->assignValueInterceptor.castValue;
break;
-
case QDeclarativeInstruction::BeginObject:
- qWarning().nospace() << idx << "\t\t" << line << "\t" << "BEGIN\t\t\t" << instr->begin.castValue;
+ qWarning().nospace() << idx << "\t\t" << "BEGIN\t\t\t" << instr->begin.castValue;
break;
case QDeclarativeInstruction::StoreObjectQList:
- qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_OBJECT_QLIST";
+ qWarning().nospace() << idx << "\t\t" << "STORE_OBJECT_QLIST";
break;
case QDeclarativeInstruction::AssignObjectList:
- qWarning().nospace() << idx << "\t\t" << line << "\t" << "ASSIGN_OBJECT_LIST";
+ qWarning().nospace() << idx << "\t\t" << "ASSIGN_OBJECT_LIST";
break;
case QDeclarativeInstruction::FetchAttached:
- qWarning().nospace() << idx << "\t\t" << line << "\t" << "FETCH_ATTACHED\t\t" << instr->fetchAttached.id;
+ qWarning().nospace() << idx << "\t\t" << "FETCH_ATTACHED\t\t" << instr->fetchAttached.id;
break;
case QDeclarativeInstruction::FetchQList:
- qWarning().nospace() << idx << "\t\t" << line << "\t" << "FETCH_QLIST\t\t" << instr->fetch.property;
+ qWarning().nospace() << idx << "\t\t" << "FETCH_QLIST\t\t" << instr->fetch.property;
break;
case QDeclarativeInstruction::FetchObject:
- qWarning().nospace() << idx << "\t\t" << line << "\t" << "FETCH\t\t\t" << instr->fetch.property;
+ qWarning().nospace() << idx << "\t\t" << "FETCH\t\t\t" << instr->fetch.property;
break;
case QDeclarativeInstruction::FetchValueType:
- qWarning().nospace() << idx << "\t\t" << line << "\t" << "FETCH_VALUE\t\t" << instr->fetchValue.property << "\t" << instr->fetchValue.type << "\t" << instr->fetchValue.bindingSkipList;
+ qWarning().nospace() << idx << "\t\t" << "FETCH_VALUE\t\t" << instr->fetchValue.property << "\t" << instr->fetchValue.type << "\t" << instr->fetchValue.bindingSkipList;
break;
case QDeclarativeInstruction::PopFetchedObject:
- qWarning().nospace() << idx << "\t\t" << line << "\t" << "POP";
+ qWarning().nospace() << idx << "\t\t" << "POP";
break;
case QDeclarativeInstruction::PopQList:
- qWarning().nospace() << idx << "\t\t" << line << "\t" << "POP_QLIST";
+ qWarning().nospace() << idx << "\t\t" << "POP_QLIST";
break;
case QDeclarativeInstruction::PopValueType:
- qWarning().nospace() << idx << "\t\t" << line << "\t" << "POP_VALUE\t\t" << instr->fetchValue.property << "\t" << instr->fetchValue.type;
+ qWarning().nospace() << idx << "\t\t" << "POP_VALUE\t\t" << instr->fetchValue.property << "\t" << instr->fetchValue.type;
break;
case QDeclarativeInstruction::Defer:
- qWarning().nospace() << idx << "\t\t" << line << "\t" << "DEFER" << "\t\t\t" << instr->defer.deferCount;
+ qWarning().nospace() << idx << "\t\t" << "DEFER" << "\t\t\t" << instr->defer.deferCount;
break;
default:
- qWarning().nospace() << idx << "\t\t" << line << "\t" << "XXX UNKNOWN INSTRUCTION" << "\t" << instr->type;
+ qWarning().nospace() << idx << "\t\t" << "XXX UNKNOWN INSTRUCTION" << "\t" << instr->type();
break;
}
#endif // QT_NO_DEBUG_STREAM
}
+int QDeclarativeInstruction::size() const
+{
+#define QML_RETURN_INSTR_SIZE(I, FMT) case I: return QDeclarativeInstructionMeta<(int)I>::Size;
+ switch (common.instructionType) {
+ FOR_EACH_QML_INSTR(QML_RETURN_INSTR_SIZE)
+ default: return 0;
+ }
+#undef QML_RETURN_INSTR_SIZE
+}
+
QT_END_NAMESPACE
diff --git a/src/declarative/qml/qdeclarativeinstruction_p.h b/src/declarative/qml/qdeclarativeinstruction_p.h
index 74f8ab4063..d040967882 100644
--- a/src/declarative/qml/qdeclarativeinstruction_p.h
+++ b/src/declarative/qml/qdeclarativeinstruction_p.h
@@ -57,303 +57,408 @@
QT_BEGIN_NAMESPACE
-class QDeclarativeCompiledData;
-class Q_AUTOTEST_EXPORT QDeclarativeInstruction
-{
-public:
- enum Type {
- //
- // Object Creation
- //
- // CreateObject - Create a new object instance and push it on the
- // object stack
- // SetId - Set the id of the object on the top of the object stack
- // SetDefault - Sets the instance on the top of the object stack to
- // be the context's default object.
- // StoreMetaObject - Assign the dynamic metaobject to object on the
- // top of the stack.
- Init, /* init */
- CreateObject, /* create */
- CreateSimpleObject, /* createSimple */
- SetId, /* setId */
- SetDefault,
- CreateComponent, /* createComponent */
- StoreMetaObject, /* storeMeta */
-
- //
- // Precomputed single assignment
- //
- // StoreFloat - Store a float in a core property
- // StoreDouble - Store a double in a core property
- // StoreInteger - Store a int or uint in a core property
- // StoreBool - Store a bool in a core property
- // StoreString - Store a QString in a core property
- // StoreUrl - Store a QUrl in a core property
- // StoreColor - Store a QColor in a core property
- // StoreDate - Store a QDate in a core property
- // StoreTime - Store a QTime in a core property
- // StoreDateTime - Store a QDateTime in a core property
- // StoreVariant - Store a QVariant in a core property
- // StoreObject - Pop the object on the top of the object stack and
- // store it in a core property
- StoreFloat, /* storeFloat */
- StoreDouble, /* storeDouble */
- StoreInteger, /* storeInteger */
- StoreBool, /* storeBool */
- StoreString, /* storeString */
- StoreUrl, /* storeUrl */
- StoreColor, /* storeColor */
- StoreDate, /* storeDate */
- StoreTime, /* storeTime */
- StoreDateTime, /* storeDateTime */
- StorePoint, /* storeRealPair */
- StorePointF, /* storeRealPair */
- StoreSize, /* storeRealPair */
- StoreSizeF, /* storeRealPair */
- StoreRect, /* storeRect */
- StoreRectF, /* storeRect */
- StoreVector3D, /* storeVector3D */
- StoreVariant, /* storeString */
- StoreVariantInteger, /* storeInteger */
- StoreVariantDouble, /* storeDouble */
- StoreVariantBool, /* storeBool */
- StoreObject, /* storeObject */
- StoreVariantObject, /* storeObject */
- StoreInterface, /* storeObject */
-
- StoreSignal, /* storeSignal */
- StoreImportedScript, /* storeScript */
- StoreScriptString, /* storeScriptString */
+#define FOR_EACH_QML_INSTR(F) \
+ F(Init, init) \
+ F(Done, common) \
+ F(CreateObject, create) \
+ 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(StoreString, storeString) \
+ F(StoreByteArray, storeByteArray) \
+ F(StoreUrl, storeUrl) \
+ F(StoreFloat, storeFloat) \
+ F(StoreDouble, storeDouble) \
+ F(StoreBool, storeBool) \
+ F(StoreInteger, 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(StoreObject, storeObject) \
+ F(AssignCustomType, assignCustomType) \
+ F(AssignSignalObject, assignSignalObject) \
+ F(StoreSignal, storeSignal) \
+ F(StoreImportedScript, storeScript) \
+ F(StoreScriptString, storeScriptString) \
+ F(BeginObject, begin) \
+ F(StoreBinding, assignBinding) \
+ F(StoreBindingOnAlias, assignBinding) \
+ F(StoreCompiledBinding, assignBinding) \
+ F(StoreValueSource, assignValueSource) \
+ F(StoreValueInterceptor, assignValueInterceptor) \
+ F(StoreObjectQList, common) \
+ F(AssignObjectList, assignObjectList) \
+ F(StoreVariantObject, 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)
- //
- // Unresolved single assignment
- //
- AssignSignalObject, /* assignSignalObject */
- AssignCustomType, /* assignCustomType */
+#ifdef Q_ALIGNOF
+# define QML_INSTR_ALIGN_MASK (Q_ALIGNOF(QDeclarativeInstruction) - 1)
+#else
+# define QML_INSTR_ALIGN_MASK (sizeof(void *) - 1)
+#endif
- StoreBinding, /* assignBinding */
- StoreBindingOnAlias, /* assignBinding */
- StoreCompiledBinding, /* assignBinding */
- StoreValueSource, /* assignValueSource */
- StoreValueInterceptor, /* assignValueInterceptor */
+#define QML_INSTR_HEADER quint8 instructionType;
+#define QML_INSTR_ENUM(I, FMT) I,
+#define QML_INSTR_SIZE(I, FMT) ((sizeof(QDeclarativeInstruction::instr_##FMT) + QML_INSTR_ALIGN_MASK) & ~QML_INSTR_ALIGN_MASK)
- BeginObject, /* begin */
-
- StoreObjectQList, /* NA */
- AssignObjectList, /* NA */
-
- FetchAttached, /* fetchAttached */
- FetchQList, /* fetch */
- FetchObject, /* fetch */
- FetchValueType, /* fetchValue */
-
- //
- // Stack manipulation
- //
- // PopFetchedObject - Remove an object from the object stack
- // PopQList - Remove a list from the list stack
- PopFetchedObject,
- PopQList,
- PopValueType, /* fetchValue */
-
- //
- // Deferred creation
- //
- Defer /* defer */
+class QDeclarativeCompiledData;
+union QDeclarativeInstruction
+{
+ enum Type {
+ FOR_EACH_QML_INSTR(QML_INSTR_ENUM)
};
- QDeclarativeInstruction()
- : line(0) {}
- Type type;
- unsigned short line;
+ inline void setType(Type type) { common.instructionType = type; }
+ inline Type type() const { return (Type)common.instructionType; }
- struct InitInstruction {
+ struct instr_common {
+ QML_INSTR_HEADER
+ };
+ struct instr_init {
+ QML_INSTR_HEADER
int bindingsSize;
int parserStatusSize;
int contextCache;
int compiledBinding;
};
- struct CreateInstruction {
+ struct instr_create {
+ QML_INSTR_HEADER
int type;
int data;
int bindingBits;
ushort column;
+ ushort line;
};
- struct CreateSimpleInstruction {
+ struct instr_createSimple {
+ QML_INSTR_HEADER
void (*create)(void *);
int typeSize;
int type;
ushort column;
+ ushort line;
};
- struct StoreMetaInstruction {
+ struct instr_storeMeta {
+ QML_INSTR_HEADER
int data;
int aliasData;
int propertyCache;
};
- struct SetIdInstruction {
+ struct instr_setId {
+ QML_INSTR_HEADER
int value;
int index;
};
- struct AssignValueSourceInstruction {
+ struct instr_assignValueSource {
+ QML_INSTR_HEADER
int property;
int owner;
int castValue;
};
- struct AssignValueInterceptorInstruction {
+ struct instr_assignValueInterceptor {
+ QML_INSTR_HEADER
int property;
int owner;
int castValue;
};
- struct AssignBindingInstruction {
+ struct instr_assignBinding {
+ QML_INSTR_HEADER
unsigned int property;
int value;
short context;
short owner;
+ ushort line;
};
- struct FetchInstruction {
+ struct instr_fetch {
+ QML_INSTR_HEADER
int property;
+ ushort line;
};
- struct FetchValueInstruction {
+ struct instr_fetchValue {
+ QML_INSTR_HEADER
int property;
int type;
quint32 bindingSkipList;
};
- struct FetchQmlListInstruction {
+ struct instr_fetchQmlList {
+ QML_INSTR_HEADER
int property;
int type;
};
- struct BeginInstruction {
+ struct instr_begin {
+ QML_INSTR_HEADER
int castValue;
};
- struct StoreFloatInstruction {
+ struct instr_storeFloat {
+ QML_INSTR_HEADER
int propertyIndex;
float value;
};
- struct StoreDoubleInstruction {
+ struct instr_storeDouble {
+ QML_INSTR_HEADER
int propertyIndex;
double value;
};
- struct StoreIntegerInstruction {
+ struct instr_storeInteger {
+ QML_INSTR_HEADER
int propertyIndex;
int value;
};
- struct StoreBoolInstruction {
+ struct instr_storeBool {
+ QML_INSTR_HEADER
int propertyIndex;
bool value;
};
- struct StoreStringInstruction {
+ struct instr_storeString {
+ QML_INSTR_HEADER
+ int propertyIndex;
+ int value;
+ };
+ struct instr_storeByteArray {
+ QML_INSTR_HEADER
int propertyIndex;
int value;
};
- struct StoreScriptStringInstruction {
+ struct instr_storeScriptString {
+ QML_INSTR_HEADER
int propertyIndex;
int value;
int scope;
};
- struct StoreScriptInstruction {
+ struct instr_storeScript {
+ QML_INSTR_HEADER
int value;
};
- struct StoreUrlInstruction {
+ struct instr_storeUrl {
+ QML_INSTR_HEADER
int propertyIndex;
int value;
};
- struct StoreColorInstruction {
+ struct instr_storeColor {
+ QML_INSTR_HEADER
int propertyIndex;
unsigned int value;
};
- struct StoreDateInstruction {
+ struct instr_storeDate {
+ QML_INSTR_HEADER
int propertyIndex;
int value;
};
- struct StoreTimeInstruction {
+ struct instr_storeTime {
+ QML_INSTR_HEADER
int propertyIndex;
- int valueIndex;
- };
- struct StoreDateTimeInstruction {
+ struct QTime {
+ int mds;
+#if defined(Q_OS_WINCE)
+ int startTick;
+#endif
+ } time;
+ };
+ struct instr_storeDateTime {
+ QML_INSTR_HEADER
int propertyIndex;
- int valueIndex;
+ int date;
+ instr_storeTime::QTime time;
};
- struct StoreRealPairInstruction {
+ struct instr_storeRect {
+ QML_INSTR_HEADER
int propertyIndex;
- int valueIndex;
- };
- struct StoreRectInstruction {
+ struct QRect {
+#if defined(Q_OS_MAC)
+ int y1;
+ int x1;
+ int y2;
+ int x2;
+#else
+ int x1;
+ int y1;
+ int x2;
+ int y2;
+#endif
+ } rect;
+ };
+ struct instr_storeRectF {
+ QML_INSTR_HEADER
int propertyIndex;
- int valueIndex;
- };
- struct StoreVector3DInstruction {
+ struct QRectF {
+ qreal xp;
+ qreal yp;
+ qreal w;
+ qreal h;
+ } rect;
+ };
+ struct instr_storeObject {
+ QML_INSTR_HEADER
int propertyIndex;
- int valueIndex;
+ ushort line;
};
- struct StoreObjectInstruction {
+ struct instr_assignCustomType {
+ QML_INSTR_HEADER
int propertyIndex;
+ int primitive;
+ int type;
+ ushort line;
};
- struct AssignCustomTypeInstruction {
- int propertyIndex;
- int valueIndex;
- };
- struct StoreSignalInstruction {
+ struct instr_storeSignal {
+ QML_INSTR_HEADER
int signalIndex;
int value;
short context;
int name;
+ ushort line;
};
- struct AssignSignalObjectInstruction {
+ struct instr_assignSignalObject {
+ QML_INSTR_HEADER
int signal;
+ ushort line;
};
- struct CreateComponentInstruction {
+ struct instr_createComponent {
+ QML_INSTR_HEADER
int count;
- ushort column;
int endLine;
int metaObject;
+ ushort column;
+ ushort line;
};
- struct FetchAttachedInstruction {
+ struct instr_fetchAttached {
+ QML_INSTR_HEADER
int id;
+ ushort line;
};
- struct DeferInstruction {
+ struct instr_defer {
+ QML_INSTR_HEADER
int deferCount;
};
-
- union {
- InitInstruction init;
- CreateInstruction create;
- CreateSimpleInstruction createSimple;
- StoreMetaInstruction storeMeta;
- SetIdInstruction setId;
- AssignValueSourceInstruction assignValueSource;
- AssignValueInterceptorInstruction assignValueInterceptor;
- AssignBindingInstruction assignBinding;
- FetchInstruction fetch;
- FetchValueInstruction fetchValue;
- FetchQmlListInstruction fetchQmlList;
- BeginInstruction begin;
- StoreFloatInstruction storeFloat;
- StoreDoubleInstruction storeDouble;
- StoreIntegerInstruction storeInteger;
- StoreBoolInstruction storeBool;
- StoreStringInstruction storeString;
- StoreScriptStringInstruction storeScriptString;
- StoreScriptInstruction storeScript;
- StoreUrlInstruction storeUrl;
- StoreColorInstruction storeColor;
- StoreDateInstruction storeDate;
- StoreTimeInstruction storeTime;
- StoreDateTimeInstruction storeDateTime;
- StoreRealPairInstruction storeRealPair;
- StoreRectInstruction storeRect;
- StoreVector3DInstruction storeVector3D;
- StoreObjectInstruction storeObject;
- AssignCustomTypeInstruction assignCustomType;
- StoreSignalInstruction storeSignal;
- AssignSignalObjectInstruction assignSignalObject;
- CreateComponentInstruction createComponent;
- FetchAttachedInstruction fetchAttached;
- DeferInstruction defer;
+ struct instr_assignObjectList {
+ QML_INSTR_HEADER
+ ushort line;
+ };
+ struct instr_storePoint {
+ QML_INSTR_HEADER
+ int propertyIndex;
+ struct QPoint {
+#if defined(Q_OS_MAC)
+ int yp;
+ int xp;
+#else
+ int xp;
+ int yp;
+#endif
+ } 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;
+ };
+
+ instr_common common;
+ instr_init init;
+ instr_create create;
+ instr_createSimple createSimple;
+ instr_storeMeta storeMeta;
+ instr_setId setId;
+ instr_assignValueSource assignValueSource;
+ instr_assignValueInterceptor assignValueInterceptor;
+ 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_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_storeObject storeObject;
+ instr_assignCustomType assignCustomType;
+ instr_storeSignal storeSignal;
+ instr_assignSignalObject assignSignalObject;
+ instr_createComponent createComponent;
+ instr_fetchAttached fetchAttached;
+ instr_defer defer;
+ instr_assignObjectList assignObjectList;
- void dump(QDeclarativeCompiledData *);
+ int size() const;
};
+template<int N>
+struct QDeclarativeInstructionMeta {
+};
+
+#define QML_INSTR_META_TEMPLATE(I, FMT) \
+ template<> struct QDeclarativeInstructionMeta<(int)QDeclarativeInstruction::I> { \
+ enum { Size = QML_INSTR_SIZE(I, FMT) }; \
+ typedef QDeclarativeInstruction::instr_##FMT DataType; \
+ static const DataType &data(const QDeclarativeInstruction &instr) { return instr.FMT; } \
+ };
+FOR_EACH_QML_INSTR(QML_INSTR_META_TEMPLATE);
+#undef QML_INSTR_META_TEMPLATE
+
QT_END_NAMESPACE
#endif // QDECLARATIVEINSTRUCTION_P_H
diff --git a/src/declarative/qml/qdeclarativemetatype.cpp b/src/declarative/qml/qdeclarativemetatype.cpp
index 50c6907b70..73ed23ba9d 100644
--- a/src/declarative/qml/qdeclarativemetatype.cpp
+++ b/src/declarative/qml/qdeclarativemetatype.cpp
@@ -88,6 +88,7 @@ QT_BEGIN_NAMESPACE
struct QDeclarativeMetaTypeData
{
+ QDeclarativeMetaTypeData();
~QDeclarativeMetaTypeData();
QList<QDeclarativeType *> types;
typedef QHash<int, QDeclarativeType *> Ids;
@@ -98,6 +99,14 @@ struct QDeclarativeMetaTypeData
MetaObjects metaObjectToType;
typedef QHash<int, QDeclarativeMetaType::StringConverter> StringConverters;
StringConverters stringConverters;
+ struct ModuleApiList {
+ ModuleApiList() : sorted(true) {}
+ QList<QDeclarativeMetaType::ModuleApi> moduleApis;
+ bool sorted;
+ };
+ typedef QHash<QByteArray, ModuleApiList> ModuleApis;
+ ModuleApis moduleApis;
+ int moduleApiCount;
struct ModuleInfo {
ModuleInfo(int major, int minor)
@@ -119,6 +128,11 @@ struct QDeclarativeMetaTypeData
Q_GLOBAL_STATIC(QDeclarativeMetaTypeData, metaTypeData)
Q_GLOBAL_STATIC(QReadWriteLock, metaTypeDataLock)
+QDeclarativeMetaTypeData::QDeclarativeMetaTypeData()
+: moduleApiCount(0)
+{
+}
+
QDeclarativeMetaTypeData::~QDeclarativeMetaTypeData()
{
for (int i = 0; i < types.count(); ++i)
@@ -664,6 +678,34 @@ int registerType(const QDeclarativePrivate::RegisterType &type)
return index;
}
+int registerModuleApi(const QDeclarativePrivate::RegisterModuleApi &api)
+{
+ QWriteLocker lock(metaTypeDataLock());
+
+ QDeclarativeMetaTypeData *data = metaTypeData();
+ QByteArray uri(api.uri);
+ QDeclarativeMetaType::ModuleApi import;
+ import.major = api.versionMajor;
+ import.minor = api.versionMinor;
+ import.script = api.scriptApi;
+ import.qobject = api.qobjectApi;
+
+ int index = data->moduleApiCount++;
+
+ QDeclarativeMetaTypeData::ModuleApis::Iterator iter = data->moduleApis.find(uri);
+ if (iter == data->moduleApis.end()) {
+ QDeclarativeMetaTypeData::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.
@@ -676,13 +718,16 @@ int QDeclarativePrivate::qmlregister(RegistrationType type, void *data)
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;
}
/*
- Have any types been registered for \a module with at least versionMajor.versionMinor, and types
- for \a module with at most versionMajor.versionMinor.
+ 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.
@@ -691,13 +736,27 @@ int QDeclarativePrivate::qmlregister(RegistrationType type, void *data)
bool QDeclarativeMetaType::isModule(const QByteArray &module, int versionMajor, int versionMinor)
{
QDeclarativeMetaTypeData *data = metaTypeData();
+
+ // first, check Types
QDeclarativeMetaTypeData::ModuleInfoHash::Iterator it = data->modules.find(module);
- return it != data->modules.end()
+ if (it != data->modules.end()
&& ((versionMajor<0 && versionMinor<0) ||
(((*it).vmajor_max > versionMajor ||
((*it).vmajor_max == versionMajor && (*it).vminor_max >= versionMinor))
&& ((*it).vmajor_min < versionMajor ||
- ((*it).vmajor_min == versionMajor && (*it).vminor_min <= versionMinor))));
+ ((*it).vmajor_min == versionMajor && (*it).vminor_min <= versionMinor))))) {
+ return true;
+ }
+
+ // then, check ModuleApis
+ foreach (const QDeclarativeMetaType::ModuleApi &mApi, data->moduleApis.value(module).moduleApis) {
+ if ((versionMajor<0 && versionMinor<0)
+ || (mApi.major == versionMajor && mApi.minor == versionMinor)) {
+ return true;
+ }
+ }
+
+ return false;
}
QList<QDeclarativePrivate::AutoParentFunction> QDeclarativeMetaType::parentFunctions()
@@ -707,6 +766,35 @@ QList<QDeclarativePrivate::AutoParentFunction> QDeclarativeMetaType::parentFunct
return data->parentFunctions;
}
+static bool operator<(const QDeclarativeMetaType::ModuleApi &lhs, const QDeclarativeMetaType::ModuleApi &rhs)
+{
+ return lhs.major < rhs.major || (lhs.major == rhs.major && lhs.minor < rhs.minor);
+}
+
+QDeclarativeMetaType::ModuleApi
+QDeclarativeMetaType::moduleApi(const QByteArray &uri, int versionMajor, int versionMinor)
+{
+ QReadLocker lock(metaTypeDataLock());
+ QDeclarativeMetaTypeData *data = metaTypeData();
+
+ QDeclarativeMetaTypeData::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();
+}
+
QObject *QDeclarativeMetaType::toQObject(const QVariant &v, bool *ok)
{
if (!isQObject(v.userType())) {
diff --git a/src/declarative/qml/qdeclarativemetatype_p.h b/src/declarative/qml/qdeclarativemetatype_p.h
index a6a3e548c4..ba2d445826 100644
--- a/src/declarative/qml/qdeclarativemetatype_p.h
+++ b/src/declarative/qml/qdeclarativemetatype_p.h
@@ -59,6 +59,7 @@
#include <QtCore/qvariant.h>
#include <QtCore/qbitarray.h>
#include <private/qdeclarativeglobal_p.h>
+#include <QtScript/qscriptvalue.h>
QT_BEGIN_NAMESPACE
@@ -106,6 +107,25 @@ public:
static bool isModule(const QByteArray &module, int versionMajor, int versionMinor);
static QList<QDeclarativePrivate::AutoParentFunction> parentFunctions();
+
+ struct ModuleApiInstance {
+ ModuleApiInstance()
+ : scriptCallback(0), qobjectCallback(0), qobjectApi(0) {}
+
+ QScriptValue (*scriptCallback)(QDeclarativeEngine *, QScriptEngine *);
+ QObject *(*qobjectCallback)(QDeclarativeEngine *, QScriptEngine *);
+ QScriptValue scriptApi;
+ QObject *qobjectApi;
+ };
+ struct ModuleApi {
+ inline ModuleApi();
+ inline bool operator==(const ModuleApi &) const;
+ int major;
+ int minor;
+ QScriptValue (*script)(QDeclarativeEngine *, QScriptEngine *);
+ QObject *(*qobject)(QDeclarativeEngine *, QScriptEngine *);
+ };
+ static ModuleApi moduleApi(const QByteArray &, int, int);
};
class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeType
@@ -168,6 +188,25 @@ private:
QDeclarativeTypePrivate *d;
};
+QDeclarativeMetaType::ModuleApi::ModuleApi()
+// : major(0), minor(0), script(0), qobject(0)
+{
+ major = 0;
+ minor = 0;
+ script = 0;
+ qobject = 0;
+}
+
+bool QDeclarativeMetaType::ModuleApi::operator==(const ModuleApi &other) const
+{
+ return major == other.major && minor == other.minor && script == other.script && qobject == other.qobject;
+}
+
+inline uint qHash(const QDeclarativeMetaType::ModuleApi &import)
+{
+ return import.major ^ import.minor ^ quintptr(import.script) ^ quintptr(import.qobject);
+}
+
QT_END_NAMESPACE
#endif // QDECLARATIVEMETATYPE_P_H
diff --git a/src/declarative/qml/qdeclarativeobjectscriptclass.cpp b/src/declarative/qml/qdeclarativeobjectscriptclass.cpp
index 1ab97e70e7..53f702ce51 100644
--- a/src/declarative/qml/qdeclarativeobjectscriptclass.cpp
+++ b/src/declarative/qml/qdeclarativeobjectscriptclass.cpp
@@ -403,6 +403,33 @@ void QDeclarativeObjectScriptClass::setProperty(QObject *obj,
} else if (value.isFunction() && !value.isRegExp()) {
// this is handled by the binding creation above
} else {
+ //### expand optimization for other known types
+ if (lastData->propType == QMetaType::Int && value.isNumber()) {
+ int rawValue = qRound(value.toNumber());
+ int status = -1;
+ int flags = 0;
+ void *a[] = { (void *)&rawValue, 0, &status, &flags };
+ QMetaObject::metacall(obj, QMetaObject::WriteProperty,
+ lastData->coreIndex, a);
+ return;
+ } else if (lastData->propType == QMetaType::QReal && value.isNumber()) {
+ qreal rawValue = qreal(value.toNumber());
+ int status = -1;
+ int flags = 0;
+ void *a[] = { (void *)&rawValue, 0, &status, &flags };
+ QMetaObject::metacall(obj, QMetaObject::WriteProperty,
+ lastData->coreIndex, a);
+ return;
+ } else if (lastData->propType == QMetaType::QString && value.isString()) {
+ const QString &rawValue = value.toString();
+ int status = -1;
+ int flags = 0;
+ void *a[] = { (void *)&rawValue, 0, &status, &flags };
+ QMetaObject::metacall(obj, QMetaObject::WriteProperty,
+ lastData->coreIndex, a);
+ return;
+ }
+
QVariant v;
if (lastData->flags & QDeclarativePropertyCache::Data::IsQList)
v = enginePriv->scriptValueToVariant(value, qMetaTypeId<QList<QObject *> >());
diff --git a/src/declarative/qml/qdeclarativeprivate.h b/src/declarative/qml/qdeclarativeprivate.h
index 2cf2317293..9eacc1d1cb 100644
--- a/src/declarative/qml/qdeclarativeprivate.h
+++ b/src/declarative/qml/qdeclarativeprivate.h
@@ -74,6 +74,9 @@ public:
};
+class QScriptValue;
+class QScriptEngine;
+class QDeclarativeEngine;
class QDeclarativeCustomParser;
namespace QDeclarativePrivate
{
@@ -233,10 +236,22 @@ namespace QDeclarativePrivate
AutoParentFunction function;
};
+ struct RegisterModuleApi {
+ int version;
+
+ const char *uri;
+ int versionMajor;
+ int versionMinor;
+
+ QScriptValue (*scriptApi)(QDeclarativeEngine *, QScriptEngine *);
+ QObject *(*qobjectApi)(QDeclarativeEngine *, QScriptEngine *);
+ };
+
enum RegistrationType {
TypeRegistration = 0,
InterfaceRegistration = 1,
- AutoParentRegistration = 2
+ AutoParentRegistration = 2,
+ ModuleApiRegistration = 3,
};
int Q_DECLARATIVE_EXPORT qmlregister(RegistrationType, void *);
diff --git a/src/declarative/qml/qdeclarativeproperty.cpp b/src/declarative/qml/qdeclarativeproperty.cpp
index e806dbf779..ae28049eed 100644
--- a/src/declarative/qml/qdeclarativeproperty.cpp
+++ b/src/declarative/qml/qdeclarativeproperty.cpp
@@ -183,6 +183,9 @@ QDeclarativeProperty::QDeclarativeProperty(QObject *obj, const QString &name)
/*!
Creates a QDeclarativeProperty for the property \a name of \a obj
using the \l{QDeclarativeContext} {context} \a ctxt.
+
+ Creating a QDeclarativeProperty without a context will render some
+ properties - like attached properties - inaccessible.
*/
QDeclarativeProperty::QDeclarativeProperty(QObject *obj, const QString &name, QDeclarativeContext *ctxt)
: d(new QDeclarativePropertyPrivate)
diff --git a/src/declarative/qml/qdeclarativepropertycache.cpp b/src/declarative/qml/qdeclarativepropertycache.cpp
index 59e76afb3f..0fa4e24725 100644
--- a/src/declarative/qml/qdeclarativepropertycache.cpp
+++ b/src/declarative/qml/qdeclarativepropertycache.cpp
@@ -61,6 +61,8 @@ QDeclarativePropertyCache::Data::Flags QDeclarativePropertyCache::Data::flagsFor
flags |= Data::IsWritable;
if (p.isResettable())
flags |= Data::IsResettable;
+ if (p.isFinal())
+ flags |= Data::IsFinal;
if (propType == qMetaTypeId<QDeclarativeBinding *>()) {
flags |= Data::IsQmlBinding;
diff --git a/src/declarative/qml/qdeclarativepropertycache_p.h b/src/declarative/qml/qdeclarativepropertycache_p.h
index 581f5197f4..7e34748c6c 100644
--- a/src/declarative/qml/qdeclarativepropertycache_p.h
+++ b/src/declarative/qml/qdeclarativepropertycache_p.h
@@ -84,20 +84,21 @@ public:
IsWritable = 0x00000002,
IsResettable = 0x00000004,
IsAlias = 0x00000008,
+ IsFinal = 0x00000010,
// These are mutualy exclusive
- IsFunction = 0x00000010,
- IsQObjectDerived = 0x00000020,
- IsEnumType = 0x00000040,
- IsQList = 0x00000080,
- IsQmlBinding = 0x00000100,
- IsQScriptValue = 0x00000200,
+ IsFunction = 0x00000020,
+ IsQObjectDerived = 0x00000040,
+ IsEnumType = 0x00000080,
+ IsQList = 0x00000100,
+ IsQmlBinding = 0x00000200,
+ IsQScriptValue = 0x00000400,
// Apply only to IsFunctions
- IsVMEFunction = 0x00000400,
- HasArguments = 0x00000800,
- IsSignal = 0x00001000,
- IsVMESignal = 0x00002000
+ IsVMEFunction = 0x00000800,
+ HasArguments = 0x00001000,
+ IsSignal = 0x00002000,
+ IsVMESignal = 0x00004000
};
Q_DECLARE_FLAGS(Flags, Flag)
diff --git a/src/declarative/qml/qdeclarativescarceresourcescriptclass.cpp b/src/declarative/qml/qdeclarativescarceresourcescriptclass.cpp
new file mode 100644
index 0000000000..d94e2d9332
--- /dev/null
+++ b/src/declarative/qml/qdeclarativescarceresourcescriptclass.cpp
@@ -0,0 +1,219 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "private/qdeclarativescarceresourcescriptclass_p.h"
+
+#include "private/qdeclarativeengine_p.h"
+#include "private/qdeclarativecontext_p.h"
+#include "private/qdeclarativedata_p.h"
+#include "private/qdeclarativetypenamescriptclass_p.h"
+#include "private/qdeclarativelistscriptclass_p.h"
+#include "private/qdeclarativebinding_p.h"
+#include "private/qdeclarativeguard_p.h"
+#include "private/qdeclarativevmemetaobject_p.h"
+
+#include <QtCore/qtimer.h>
+#include <QtCore/qvarlengtharray.h>
+#include <QtScript/qscriptcontextinfo.h>
+
+Q_DECLARE_METATYPE(QScriptValue);
+
+QT_BEGIN_NAMESPACE
+
+QDeclarativeScarceResourceScriptClass::QDeclarativeScarceResourceScriptClass(QDeclarativeEngine *bindEngine)
+ : QScriptDeclarativeClass(QDeclarativeEnginePrivate::getScriptEngine(bindEngine)), engine(bindEngine)
+{
+ QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine);
+
+ // Properties of this type can be explicitly preserved by clients,
+ // which prevents the scarce resource from being automatically
+ // released after the binding has been evaluated.
+ m_preserve = scriptEngine->newFunction(preserve);
+ m_preserveId = createPersistentIdentifier(QLatin1String("preserve"));
+
+ // Similarly, they can be explicitly destroyed by clients,
+ // which releases the scarce resource.
+ m_destroy = scriptEngine->newFunction(destroy);
+ m_destroyId = createPersistentIdentifier(QLatin1String("destroy"));
+}
+
+QDeclarativeScarceResourceScriptClass::~QDeclarativeScarceResourceScriptClass()
+{
+}
+
+/*
+ Returns a JavaScript object whose instance data is a new scarce resource data.
+ The scarce resource is added to the doubly-linked-list of scarce resources in the engine
+ so that the scarce resource can be released after evaluation completes.
+ */
+QScriptValue QDeclarativeScarceResourceScriptClass::newScarceResource(const QVariant &v)
+{
+ // create the scarce resource
+ ScarceResourceData *srd = new ScarceResourceData(v);
+
+ // insert into the linked list
+ QDeclarativeEnginePrivate *enginePrivate = QDeclarativeEnginePrivate::get(engine);
+ srd->insertInto(&enginePrivate->scarceResources);
+ Q_ASSERT(enginePrivate->scarceResourcesRefCount > 0);
+
+ // return the javascript object with the scarce resource instance data
+ QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine);
+ return QScriptDeclarativeClass::newObject(scriptEngine, this, srd); // JSC takes ownership of srd.
+}
+
+QVariant QDeclarativeScarceResourceScriptClass::toVariant(Object *object, bool *ok)
+{
+ ScarceResourceData *obj = static_cast<ScarceResourceData*>(object);
+ if (ok) *ok = true;
+ return obj->resource;
+}
+
+QVariant QDeclarativeScarceResourceScriptClass::toVariant(const QScriptValue &value)
+{
+ Q_ASSERT(scriptClass(value) == this);
+
+ return toVariant(object(value), 0);
+}
+
+// The destroy() and preserve() function properties are readable.
+QScriptClass::QueryFlags
+QDeclarativeScarceResourceScriptClass::queryProperty(Object *object, const Identifier &name,
+ QScriptClass::QueryFlags flags)
+{
+ Q_UNUSED(object)
+ Q_UNUSED(flags)
+
+ if (name == m_destroyId.identifier || name == m_preserveId.identifier)
+ return (QScriptClass::HandlesReadAccess);
+ return 0;
+}
+
+// Return the (function) values which may be evaluated by clients.
+QDeclarativeScarceResourceScriptClass::Value
+QDeclarativeScarceResourceScriptClass::property(Object *object, const Identifier &name)
+{
+ Q_UNUSED(object)
+
+ QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine);
+
+ // functions
+ if (name == m_preserveId.identifier)
+ return Value(scriptEngine, m_preserve);
+ else if (name == m_destroyId.identifier)
+ return Value(scriptEngine, m_destroy);
+
+ return Value();
+}
+
+/*
+ This method is called when the user explicitly calls the "preserve" method of a scarce resource in JavaScript
+ within the specified evaluation context \a context of the script engine \a engine.
+ Calling this function signifies that the user explicitly wants to preserve the resource rather than let it
+ be automatically released once evaluation of the expression is complete.
+ This function removes the internal scarce resource from the declarative engine's linked list of scarce resources
+ to release after evaluation of the expression completes. This means that the resource will only be truly
+ released when the JavaScript engine's garbage collector is run.
+
+ Example:
+ \qml
+ function getIcon(model) {
+ var icon = model.avatar; // a pixmap property
+ icon.preserve(); // explicitly preserves the resource
+ return icon; // a valid variant will be returned
+ }
+ \endqml
+ */
+QScriptValue QDeclarativeScarceResourceScriptClass::preserve(QScriptContext *context, QScriptEngine *engine)
+{
+ QDeclarativeEnginePrivate *p = QDeclarativeEnginePrivate::get(engine);
+ QScriptValue that = context->thisObject();
+
+ if (scriptClass(that) != p->scarceResourceClass)
+ return engine->undefinedValue();
+
+ // The client wishes to preserve the resource in this SRD.
+ ScarceResourceData *data = static_cast<ScarceResourceData *>(p->scarceResourceClass->object(that));
+ if (!data)
+ return engine->undefinedValue();
+
+ // remove node from list, without releasing the resource.
+ data->removeNode();
+
+ return engine->undefinedValue();
+}
+
+/*
+ This method is called when the user explicitly calls the "destroy" method of a scarce resource in JavaScript
+ within the specified evaluation context \a context of the script engine \a engine.
+ Calling this function signifies that the user explicitly wants to release the resource.
+ This function sets the internal scarce resource variant to the invalid variant, in order to release the original resource,
+ and then removes the resource from the declarative engine's linked-list of scarce resources to
+ to release after evaluation of the expression completes, as it has already been released.
+
+ Example:
+ \qml
+ function getIcon(model) {
+ var icon = model.avatar; // a pixmap property
+ icon.destroy(); // explicitly releases the resource
+ return icon; // an invalid variant will be returned
+ }
+ \endqml
+ */
+QScriptValue QDeclarativeScarceResourceScriptClass::destroy(QScriptContext *context, QScriptEngine *engine)
+{
+ QDeclarativeEnginePrivate *p = QDeclarativeEnginePrivate::get(engine);
+ QScriptValue that = context->thisObject();
+
+ if (scriptClass(that) != p->scarceResourceClass)
+ return engine->undefinedValue();
+
+ // the client wishes to release the resource in this SRD.
+ ScarceResourceData *data = static_cast<ScarceResourceData *>(p->scarceResourceClass->object(that));
+ if (!data)
+ return engine->undefinedValue();
+
+ // release the resource and remove the node from the list.
+ data->releaseResource();
+
+ return engine->undefinedValue();
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/qml/qdeclarativescarceresourcescriptclass_p.h b/src/declarative/qml/qdeclarativescarceresourcescriptclass_p.h
new file mode 100644
index 0000000000..2a1390a230
--- /dev/null
+++ b/src/declarative/qml/qdeclarativescarceresourcescriptclass_p.h
@@ -0,0 +1,163 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVESCARCERESOURCESCRIPTCLASS_P_H
+#define QDECLARATIVESCARCERESOURCESCRIPTCLASS_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/qdeclarativepropertycache_p.h"
+#include "private/qdeclarativetypenamecache_p.h"
+
+#include <private/qscriptdeclarativeclass_p.h>
+#include <QtScript/qscriptengine.h>
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativeEngine;
+
+/*
+ Scarce resources (like pixmaps and textures) are managed manually
+ in that the variant will be set to the invalid variant once the
+ JavaScript engine has finished using the JavaScript object whose
+ instance data is the ScarceResourceData (but before the garbage
+ collector frees the JavaScript object itself).
+
+ The engine stores a doubly-linked-list of scarce resources which
+ will to be cleaned up after a binding is successfully evaluated
+ (unless the user explicitly preserves the scarce resource).
+
+ A ScarceResourceData pointer should not be deleted manually, as
+ all instances of a ScarceResourceData should be owned by the
+ JavaScript engine.
+ */
+struct ScarceResourceData : public QScriptDeclarativeClass::Object {
+ ScarceResourceData(const QVariant &v) : resource(v), prev(0), next(0)
+ {
+ }
+
+ virtual ~ScarceResourceData()
+ {
+ releaseResource();
+ }
+
+ // Insert this resource into the given list of resources.
+ void insertInto(ScarceResourceData **list)
+ {
+ // This node becomes the head of the list.
+ next = *list; // so our next = old list head
+ *list = this; // list now points to us (we're the head)
+ prev = list; // as we're the head, our prev ptr becomes the list ptr.
+
+ // and the next node's prev pointer must contain a ptr to our next ptr,
+ // since per definition, prev always contains a pointer to the previous node's "next" ptr,
+ // and the "this" node is the "this->next" node's "prev" node.
+ if (next) next->prev = &next;
+ }
+
+ // Remove this resource from the list of resources, without releasing the resource.
+ void removeNode()
+ {
+ // whatever previously pointed to this node (ie, as that node's "next" node)
+ // should now point to our next node (since we no longer exist in the list).
+ // and the next node's prev ptr should point to our prev node.
+ if (prev) *prev = next;
+ if (next) next->prev = prev;
+ prev = 0;
+ next = 0;
+ }
+
+ // Release this resource, and remove from the list.
+ void releaseResource()
+ {
+ resource = QVariant();
+ removeNode();
+ }
+
+ QVariant resource;
+
+ // prev always contains a pointer to the previous node's "next" ptr.
+ // :. for the head node, [*prev] will be engine->scarceResources
+ // :. for every other node, [*prev] will be the previous node's "next" ptr.
+ ScarceResourceData **prev;
+ ScarceResourceData *next;
+};
+
+class Q_AUTOTEST_EXPORT QDeclarativeScarceResourceScriptClass : public QScriptDeclarativeClass
+{
+public:
+ QDeclarativeScarceResourceScriptClass(QDeclarativeEngine *);
+ ~QDeclarativeScarceResourceScriptClass();
+
+ // Creates a new JavaScript object whose instance data is the scarce resource v
+ QScriptValue newScarceResource(const QVariant &v);
+
+ // inherited from QScriptDeclarativeClass
+ virtual QScriptClass::QueryFlags queryProperty(Object *, const Identifier &,
+ QScriptClass::QueryFlags flags);
+ virtual Value property(Object *, const Identifier &);
+ virtual QVariant toVariant(Object *, bool *ok = 0);
+ QVariant toVariant(const QScriptValue &value);
+
+private:
+ PersistentIdentifier m_preserveId;
+ PersistentIdentifier m_destroyId;
+ QScriptValue m_preserve;
+ QScriptValue m_destroy;
+
+ static QScriptValue preserve(QScriptContext *context, QScriptEngine *engine);
+ static QScriptValue destroy(QScriptContext *context, QScriptEngine *engine);
+
+ QDeclarativeEngine *engine;
+};
+
+QT_END_NAMESPACE
+
+#endif // QDECLARATIVESCARCERESOURCESCRIPTCLASS_P_H
diff --git a/src/declarative/qml/qdeclarativescriptparser.cpp b/src/declarative/qml/qdeclarativescriptparser.cpp
index d87f8da3dc..df1dec5efc 100644
--- a/src/declarative/qml/qdeclarativescriptparser.cpp
+++ b/src/declarative/qml/qdeclarativescriptparser.cpp
@@ -59,6 +59,22 @@ QT_BEGIN_NAMESPACE
using namespace QDeclarativeJS;
using namespace QDeclarativeParser;
+void QDeclarativeScriptParser::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
@@ -111,6 +127,7 @@ protected:
LocationSpan location,
AST::UiObjectInitializer *initializer = 0);
+ QDeclarativeParser::Variant getVariant(AST::Statement *stmt);
QDeclarativeParser::Variant getVariant(AST::ExpressionNode *expr);
LocationSpan location(AST::SourceLocation start, AST::SourceLocation end);
@@ -588,16 +605,16 @@ bool ProcessAST::visit(AST::UiPublicMember *node)
property.location = location(node->firstSourceLocation(),
node->lastSourceLocation());
- if (node->expression) { // default value
+ if (node->statement) { // default value
property.defaultValue = new Property;
property.defaultValue->parent = _stateStack.top().object;
property.defaultValue->location =
- location(node->expression->firstSourceLocation(),
- node->expression->lastSourceLocation());
+ location(node->statement->firstSourceLocation(),
+ node->statement->lastSourceLocation());
QDeclarativeParser::Value *value = new QDeclarativeParser::Value;
- value->location = location(node->expression->firstSourceLocation(),
- node->expression->lastSourceLocation());
- value->value = getVariant(node->expression);
+ value->location = location(node->statement->firstSourceLocation(),
+ node->statement->lastSourceLocation());
+ value->value = getVariant(node->statement);
property.defaultValue->values << value;
}
@@ -642,6 +659,18 @@ bool ProcessAST::visit(AST::UiObjectBinding *node)
return false;
}
+QDeclarativeParser::Variant ProcessAST::getVariant(AST::Statement *stmt)
+{
+ if (stmt) {
+ if (AST::ExpressionStatement *exprStmt = AST::cast<AST::ExpressionStatement *>(stmt))
+ return getVariant(exprStmt->expression);
+
+ return QDeclarativeParser::Variant(asString(stmt), stmt);
+ }
+
+ return QDeclarativeParser::Variant();
+}
+
QDeclarativeParser::Variant ProcessAST::getVariant(AST::ExpressionNode *expr)
{
if (AST::StringLiteral *lit = AST::cast<AST::StringLiteral *>(expr)) {
@@ -708,7 +737,7 @@ bool ProcessAST::visit(AST::UiScriptBinding *node)
while (propertyCount--)
_stateStack.pop();
- return true;
+ return false;
}
static QList<int> collectCommas(AST::UiArrayMemberList *members)
@@ -743,7 +772,7 @@ bool ProcessAST::visit(AST::UiArrayBinding *node)
error.setLine(this->location(propertyName).start.line);
error.setColumn(this->location(propertyName).start.column);
_parser->_errors << error;
- return 0;
+ return false;
}
accept(node->members);
@@ -896,6 +925,19 @@ static void replaceWithSpace(QString &str, int idx, int n)
*data++ = space;
}
+static QDeclarativeParser::LocationSpan
+locationFromLexer(const QDeclarativeJS::Lexer &lex, int startLine, int startColumn, int startOffset)
+{
+ QDeclarativeParser::LocationSpan l;
+
+ l.start.line = startLine; l.start.column = startColumn;
+ l.end.line = lex.endLineNo(); l.end.column = lex.endColumnNo();
+ 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:
@@ -1024,7 +1066,8 @@ QDeclarativeScriptParser::JavaScriptMetaData QDeclarativeScriptParser::extractMe
return rv;
int startOffset = l.tokenOffset();
- int startLine = l.currentLineNo();
+ int startLine = l.startLineNo();
+ int startColumn = l.startColumnNo();
token = l.lex();
@@ -1062,8 +1105,11 @@ QDeclarativeScriptParser::JavaScriptMetaData QDeclarativeScriptParser::extractMe
if (!importId.at(0).isUpper())
return rv;
+ QDeclarativeParser::LocationSpan location =
+ locationFromLexer(l, startLine, startColumn, startOffset);
+
token = l.lex();
- if (l.currentLineNo() == startLine)
+ if (l.startLineNo() == startLine)
return rv;
replaceWithSpace(script, startOffset, endOffset - startOffset);
@@ -1072,9 +1118,9 @@ QDeclarativeScriptParser::JavaScriptMetaData QDeclarativeScriptParser::extractMe
import.type = Import::Script;
import.uri = file;
import.qualifier = importId;
+ import.location = location;
rv.imports << import;
-
} else {
// URI
QString uri;
@@ -1117,8 +1163,11 @@ QDeclarativeScriptParser::JavaScriptMetaData QDeclarativeScriptParser::extractMe
if (!importId.at(0).isUpper())
return rv;
+ QDeclarativeParser::LocationSpan location =
+ locationFromLexer(l, startLine, startColumn, startOffset);
+
token = l.lex();
- if (l.currentLineNo() == startLine)
+ if (l.startLineNo() == startLine)
return rv;
replaceWithSpace(script, startOffset, endOffset - startOffset);
@@ -1128,6 +1177,7 @@ QDeclarativeScriptParser::JavaScriptMetaData QDeclarativeScriptParser::extractMe
import.uri = uri;
import.version = version;
import.qualifier = importId;
+ import.location = location;
rv.imports << import;
}
@@ -1143,7 +1193,7 @@ QDeclarativeScriptParser::JavaScriptMetaData QDeclarativeScriptParser::extractMe
QString pragmaValue = script.mid(l.tokenOffset(), l.tokenLength());
int endOffset = l.tokenLength() + l.tokenOffset();
- if (pragmaValue == QLatin1String("library")) {
+ if (pragmaValue == library) {
pragmas |= QDeclarativeParser::Object::ScriptBlock::Shared;
replaceWithSpace(script, startOffset, endOffset - startOffset);
} else {
diff --git a/src/declarative/qml/qdeclarativescriptparser_p.h b/src/declarative/qml/qdeclarativescriptparser_p.h
index 5a64153370..73e797635a 100644
--- a/src/declarative/qml/qdeclarativescriptparser_p.h
+++ b/src/declarative/qml/qdeclarativescriptparser_p.h
@@ -67,7 +67,7 @@ QT_MODULE(Declarative)
class QByteArray;
class QDeclarativeScriptParserJsASTData;
-class QDeclarativeScriptParser
+class Q_AUTOTEST_EXPORT QDeclarativeScriptParser
{
public:
class Import
@@ -82,6 +82,8 @@ public:
QString qualifier;
QString version;
+ void extractVersion(int *maj, int *min) const;
+
QDeclarativeParser::LocationSpan location;
};
diff --git a/src/declarative/qml/qdeclarativetypeloader.cpp b/src/declarative/qml/qdeclarativetypeloader.cpp
index 168c1512e2..a413305e28 100644
--- a/src/declarative/qml/qdeclarativetypeloader.cpp
+++ b/src/declarative/qml/qdeclarativetypeloader.cpp
@@ -609,7 +609,7 @@ void QDeclarativeDataLoader::setData(QDeclarativeDataBlob *blob, const QByteArra
if (!blob->isError() && !blob->isWaiting())
blob->allDependenciesDone();
- if (blob->status() != QDeclarativeDataBlob::Error)
+ if (blob->status() != QDeclarativeDataBlob::Error)
blob->m_status = QDeclarativeDataBlob::WaitingForDependencies;
blob->m_inCallback = false;
@@ -680,24 +680,23 @@ QDeclarativeTypeData *QDeclarativeTypeLoader::get(const QByteArray &data, const
}
/*!
-Returns a QDeclarativeScriptData for \a url. The QDeclarativeScriptData may be cached.
+Return a QDeclarativeScriptBlob for \a url. The QDeclarativeScriptData may be cached.
*/
-QDeclarativeScriptData *QDeclarativeTypeLoader::getScript(const QUrl &url)
+QDeclarativeScriptBlob *QDeclarativeTypeLoader::getScript(const QUrl &url)
{
Q_ASSERT(!url.isRelative() &&
(QDeclarativeEnginePrivate::urlToLocalFileOrQrc(url).isEmpty() ||
!QDir::isRelativePath(QDeclarativeEnginePrivate::urlToLocalFileOrQrc(url))));
- QDeclarativeScriptData *scriptData = m_scriptCache.value(url);
+ QDeclarativeScriptBlob *scriptBlob = m_scriptCache.value(url);
- if (!scriptData) {
- scriptData = new QDeclarativeScriptData(url);
- m_scriptCache.insert(url, scriptData);
- QDeclarativeDataLoader::load(scriptData);
+ if (!scriptBlob) {
+ scriptBlob = new QDeclarativeScriptBlob(url, this);
+ m_scriptCache.insert(url, scriptBlob);
+ QDeclarativeDataLoader::load(scriptBlob);
}
- scriptData->addref();
- return scriptData;
+ return scriptBlob;
}
/*!
@@ -878,13 +877,14 @@ void QDeclarativeTypeData::dataReceived(const QByteArray &data)
}
} else if (import.type == QDeclarativeScriptParser::Import::Script) {
QUrl scriptUrl = finalUrl().resolved(QUrl(import.uri));
- QDeclarativeScriptData *data = typeLoader()->getScript(scriptUrl);
- addDependency(data);
+ QDeclarativeScriptBlob *blob = typeLoader()->getScript(scriptUrl);
+ addDependency(blob);
ScriptReference ref;
ref.location = import.location.start;
ref.qualifier = import.qualifier;
- ref.script = data;
+ ref.script = blob;
+ blob->addref();
m_scripts << ref;
}
@@ -943,14 +943,31 @@ void QDeclarativeTypeData::resolveTypes()
// 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<QDeclarativeError> errors;
if (QDeclarativeQmldirData *qmldir = qmldirForUrl(finalUrl().resolved(QUrl(QLatin1String("./qmldir"))))) {
m_imports.addImport(importDatabase, QLatin1String("."),
QString(), -1, -1, QDeclarativeScriptParser::Import::File,
- qmldir->dirComponents(), 0);
+ qmldir->dirComponents(), &errors);
} else {
m_imports.addImport(importDatabase, QLatin1String("."),
QString(), -1, -1, QDeclarativeScriptParser::Import::File,
- QDeclarativeDirComponents(), 0);
+ QDeclarativeDirComponents(), &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<QDeclarativeError> realErrors;
+ for (int i = 0; i < errors.size(); ++i) {
+ if (errors.at(i).description() != QDeclarativeImportDatabase::tr("import \".\" has no qmldir and no namespace")
+ && errors.at(i).description() != QDeclarativeImportDatabase::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 QDeclarativeScriptParser::Import &import, scriptParser.imports()) {
@@ -960,34 +977,31 @@ void QDeclarativeTypeData::resolveTypes()
if (import.type == QDeclarativeScriptParser::Import::File && import.qualifier.isEmpty()) {
QUrl qmldirUrl = finalUrl().resolved(QUrl(import.uri + QLatin1String("/qmldir")));
- if (QDeclarativeQmldirData *qmldir = qmldirForUrl(qmldirUrl))
+ if (QDeclarativeQmldirData *qmldir = qmldirForUrl(qmldirUrl))
qmldircomponentsnetwork = qmldir->dirComponents();
}
int vmaj = -1;
int vmin = -1;
+ import.extractVersion(&vmaj, &vmin);
- if (!import.version.isEmpty()) {
- int dot = import.version.indexOf(QLatin1Char('.'));
- if (dot < 0) {
- vmaj = import.version.toInt();
- vmin = 0;
- } else {
- vmaj = import.version.left(dot).toInt();
- vmin = import.version.mid(dot+1).toInt();
- }
- }
-
- QString errorString;
+ QList<QDeclarativeError> errors;
if (!m_imports.addImport(importDatabase, import.uri, import.qualifier,
- vmaj, vmin, import.type, qmldircomponentsnetwork, &errorString)) {
+ vmaj, vmin, import.type, qmldircomponentsnetwork, &errors)) {
QDeclarativeError error;
+ if (errors.size()) {
+ error = errors.takeFirst();
+ } else {
+ // this should not be possible!
+ // Description should come from error provided by addImport() function.
+ error.setDescription(QDeclarativeTypeLoader::tr("Unreported error adding script import to import database"));
+ }
error.setUrl(m_imports.baseUrl());
- error.setDescription(errorString);
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(error);
+ setError(errors);
return;
}
}
@@ -1001,29 +1015,38 @@ void QDeclarativeTypeData::resolveTypes()
int majorVersion;
int minorVersion;
QDeclarativeImportedNamespace *typeNamespace = 0;
- QString errorString;
+ QList<QDeclarativeError> errors;
if (!m_imports.resolveType(typeName, &ref.type, &url, &majorVersion, &minorVersion,
- &typeNamespace, &errorString) || typeNamespace) {
+ &typeNamespace, &errors) || typeNamespace) {
// Known to not be a type:
// - known to be a namespace (Namespace {})
// - type with unknown namespace (UnknownNamespace.SomeType {})
QDeclarativeError error;
- error.setUrl(m_imports.baseUrl());
QString userTypeName = parserRef->name;
userTypeName.replace(QLatin1Char('/'),QLatin1Char('.'));
- if (typeNamespace)
+ if (typeNamespace) {
error.setDescription(QDeclarativeTypeLoader::tr("Namespace %1 cannot be used as a type").arg(userTypeName));
- else
- error.setDescription(QDeclarativeTypeLoader::tr("%1 %2").arg(userTypeName).arg(errorString));
+ } else {
+ if (errors.size()) {
+ error = errors.takeFirst();
+ } else {
+ // this should not be possible!
+ // Description should come from error provided by addImport() function.
+ error.setDescription(QDeclarativeTypeLoader::tr("Unreported error adding script import to import database"));
+ }
+ error.setUrl(m_imports.baseUrl());
+ error.setDescription(QDeclarativeTypeLoader::tr("%1 %2").arg(userTypeName).arg(error.description()));
+ }
if (!parserRef->refObjects.isEmpty()) {
QDeclarativeParser::Object *obj = parserRef->refObjects.first();
error.setLine(obj->location.start.line);
error.setColumn(obj->location.start.column);
}
-
- setError(error);
+
+ errors.prepend(error);
+ setError(errors);
return;
}
@@ -1056,25 +1079,156 @@ QDeclarativeQmldirData *QDeclarativeTypeData::qmldirForUrl(const QUrl &url)
return 0;
}
-QDeclarativeScriptData::QDeclarativeScriptData(const QUrl &url)
-: QDeclarativeDataBlob(url, JavaScriptFile), m_pragmas(QDeclarativeParser::Object::ScriptBlock::None)
+QDeclarativeScriptData::QDeclarativeScriptData(QDeclarativeEngine *engine)
+: QDeclarativeCleanup(engine), importCache(0), pragmas(QDeclarativeParser::Object::ScriptBlock::None),
+ m_loaded(false)
+{
+}
+
+QDeclarativeScriptData::~QDeclarativeScriptData()
{
+ clear();
}
-QDeclarativeParser::Object::ScriptBlock::Pragmas QDeclarativeScriptData::pragmas() const
+void QDeclarativeScriptData::clear()
+{
+ if (importCache) {
+ importCache->release();
+ importCache = 0;
+ }
+
+ for (int ii = 0; ii < scripts.count(); ++ii)
+ scripts.at(ii)->release();
+ scripts.clear();
+}
+
+QDeclarativeScriptBlob::QDeclarativeScriptBlob(const QUrl &url, QDeclarativeTypeLoader *loader)
+: QDeclarativeDataBlob(url, JavaScriptFile), m_pragmas(QDeclarativeParser::Object::ScriptBlock::None),
+ m_scriptData(0), m_typeLoader(loader)
+{
+}
+
+QDeclarativeScriptBlob::~QDeclarativeScriptBlob()
+{
+ if (m_scriptData) {
+ m_scriptData->release();
+ m_scriptData = 0;
+ }
+}
+
+QDeclarativeParser::Object::ScriptBlock::Pragmas QDeclarativeScriptBlob::pragmas() const
{
return m_pragmas;
}
-QString QDeclarativeScriptData::scriptSource() const
+QString QDeclarativeScriptBlob::scriptSource() const
{
return m_source;
}
-void QDeclarativeScriptData::dataReceived(const QByteArray &data)
+QDeclarativeTypeLoader *QDeclarativeScriptBlob::typeLoader() const
+{
+ return m_typeLoader;
+}
+
+const QDeclarativeImports &QDeclarativeScriptBlob::imports() const
+{
+ return m_imports;
+}
+
+QDeclarativeScriptData *QDeclarativeScriptBlob::scriptData() const
+{
+ return m_scriptData;
+}
+
+void QDeclarativeScriptBlob::dataReceived(const QByteArray &data)
{
+ QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(m_typeLoader->engine());
+ QDeclarativeImportDatabase *importDatabase = &ep->importDatabase;
+
m_source = QString::fromUtf8(data);
- m_pragmas = QDeclarativeScriptParser::extractPragmas(m_source);
+
+ QDeclarativeScriptParser::JavaScriptMetaData metadata =
+ QDeclarativeScriptParser::extractMetaData(m_source);
+
+ m_imports.setBaseUrl(finalUrl());
+
+ m_pragmas = metadata.pragmas;
+
+ foreach (const QDeclarativeScriptParser::Import &import, metadata.imports) {
+ Q_ASSERT(import.type != QDeclarativeScriptParser::Import::File);
+
+ if (import.type == QDeclarativeScriptParser::Import::Script) {
+ QUrl scriptUrl = finalUrl().resolved(QUrl(import.uri));
+ QDeclarativeScriptBlob *blob = typeLoader()->getScript(scriptUrl);
+ addDependency(blob);
+
+ ScriptReference ref;
+ ref.location = import.location.start;
+ ref.qualifier = import.qualifier;
+ ref.script = blob;
+ blob->addref();
+ m_scripts << ref;
+ } else {
+ Q_ASSERT(import.type == QDeclarativeScriptParser::Import::Library);
+ int vmaj = -1;
+ int vmin = -1;
+ import.extractVersion(&vmaj, &vmin);
+
+ QList<QDeclarativeError> errors;
+ if (!m_imports.addImport(importDatabase, import.uri, import.qualifier, vmaj, vmin,
+ import.type, QDeclarativeDirComponents(), &errors)) {
+ QDeclarativeError 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 QDeclarativeScriptBlob::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<QDeclarativeError> errors = script.script->errors();
+ QDeclarativeError 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;
+
+ QDeclarativeEngine *engine = typeLoader()->engine();
+ m_scriptData = new QDeclarativeScriptData(engine);
+ m_scriptData->url = finalUrl();
+ m_scriptData->importCache = new QDeclarativeTypeNameCache(engine);
+
+ 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_program = QScriptProgram(m_source, finalUrl().toString());
}
QDeclarativeQmldirData::QDeclarativeQmldirData(const QUrl &url)
diff --git a/src/declarative/qml/qdeclarativetypeloader_p.h b/src/declarative/qml/qdeclarativetypeloader_p.h
index 56b663689e..05873df4ca 100644
--- a/src/declarative/qml/qdeclarativetypeloader_p.h
+++ b/src/declarative/qml/qdeclarativetypeloader_p.h
@@ -55,8 +55,11 @@
#include <QtCore/qobject.h>
#include <QtNetwork/qnetworkreply.h>
+#include <QtScript/qscriptvalue.h>
+#include <QtScript/qscriptprogram.h>
#include <QtDeclarative/qdeclarativeerror.h>
#include <QtDeclarative/qdeclarativeengine.h>
+#include <private/qdeclarativecleanup_p.h>
#include <private/qdeclarativescriptparser_p.h>
#include <private/qdeclarativedirparser_p.h>
#include <private/qdeclarativeimport_p.h>
@@ -64,6 +67,7 @@
QT_BEGIN_NAMESPACE
class QDeclarativeScriptData;
+class QDeclarativeScriptBlob;
class QDeclarativeQmldirData;
class QDeclarativeTypeLoader;
class QDeclarativeCompiledData;
@@ -140,7 +144,7 @@ private:
QUrl m_finalUrl;
// List of QDeclarativeDataBlob's that are waiting for me to complete.
- QList<QDeclarativeDataBlob *> m_waitingOnMe;
+ QList<QDeclarativeDataBlob *> m_waitingOnMe;
// List of QDeclarativeDataBlob's that I am waiting for to complete.
QList<QDeclarativeDataBlob *> m_waitingFor;
@@ -178,7 +182,6 @@ private:
NetworkReplies m_networkReplies;
};
-
class Q_AUTOTEST_EXPORT QDeclarativeTypeLoader : public QDeclarativeDataLoader
{
Q_OBJECT
@@ -196,11 +199,11 @@ public:
QDeclarativeTypeData *get(const QByteArray &, const QUrl &url, Options = None);
void clearCache();
- QDeclarativeScriptData *getScript(const QUrl &);
+ QDeclarativeScriptBlob *getScript(const QUrl &);
QDeclarativeQmldirData *getQmldir(const QUrl &);
private:
typedef QHash<QUrl, QDeclarativeTypeData *> TypeCache;
- typedef QHash<QUrl, QDeclarativeScriptData *> ScriptCache;
+ typedef QHash<QUrl, QDeclarativeScriptBlob *> ScriptCache;
typedef QHash<QUrl, QDeclarativeQmldirData *> QmldirCache;
TypeCache m_typeCache;
@@ -230,7 +233,7 @@ public:
QDeclarativeParser::Location location;
QString qualifier;
- QDeclarativeScriptData *script;
+ QDeclarativeScriptBlob *script;
};
QDeclarativeTypeData(const QUrl &, QDeclarativeTypeLoader::Options, QDeclarativeTypeLoader *);
@@ -285,20 +288,65 @@ private:
QDeclarativeTypeLoader *m_typeLoader;
};
-class Q_AUTOTEST_EXPORT QDeclarativeScriptData : public QDeclarativeDataBlob
+class Q_AUTOTEST_EXPORT QDeclarativeScriptData : public QDeclarativeRefCount, public QDeclarativeCleanup
{
public:
- QDeclarativeScriptData(const QUrl &);
+ QDeclarativeScriptData(QDeclarativeEngine *);
+ ~QDeclarativeScriptData();
+
+ QUrl url;
+ QDeclarativeTypeNameCache *importCache;
+ QList<QDeclarativeScriptBlob *> scripts;
+ QDeclarativeParser::Object::ScriptBlock::Pragmas pragmas;
+
+protected:
+ virtual void clear(); // From QDeclarativeCleanup
+
+private:
+ friend class QDeclarativeVME;
+ friend class QDeclarativeScriptBlob;
+
+ bool m_loaded;
+ QScriptProgram m_program;
+ QScriptValue m_value;
+};
+
+class Q_AUTOTEST_EXPORT QDeclarativeScriptBlob : public QDeclarativeDataBlob
+{
+public:
+ QDeclarativeScriptBlob(const QUrl &, QDeclarativeTypeLoader *);
+ ~QDeclarativeScriptBlob();
+
+ struct ScriptReference
+ {
+ ScriptReference() : script(0) {}
+
+ QDeclarativeParser::Location location;
+ QString qualifier;
+ QDeclarativeScriptBlob *script;
+ };
QDeclarativeParser::Object::ScriptBlock::Pragmas pragmas() const;
QString scriptSource() const;
+ QDeclarativeTypeLoader *typeLoader() const;
+ const QDeclarativeImports &imports() const;
+
+ QDeclarativeScriptData *scriptData() const;
+
protected:
virtual void dataReceived(const QByteArray &);
+ virtual void done();
private:
QDeclarativeParser::Object::ScriptBlock::Pragmas m_pragmas;
QString m_source;
+
+ QDeclarativeImports m_imports;
+ QList<ScriptReference> m_scripts;
+ QDeclarativeScriptData *m_scriptData;
+
+ QDeclarativeTypeLoader *m_typeLoader;
};
class Q_AUTOTEST_EXPORT QDeclarativeQmldirData : public QDeclarativeDataBlob
diff --git a/src/declarative/qml/qdeclarativetypenamecache.cpp b/src/declarative/qml/qdeclarativetypenamecache.cpp
index b171dbab6c..8a1b4bff43 100644
--- a/src/declarative/qml/qdeclarativetypenamecache.cpp
+++ b/src/declarative/qml/qdeclarativetypenamecache.cpp
@@ -46,7 +46,7 @@
QT_BEGIN_NAMESPACE
QDeclarativeTypeNameCache::QDeclarativeTypeNameCache(QDeclarativeEngine *e)
-: QDeclarativeCleanup(e), engine(e)
+: QDeclarativeCleanup(e), engine(e), m_moduleApi(0)
{
}
@@ -60,6 +60,7 @@ void QDeclarativeTypeNameCache::clear()
qDeleteAll(stringCache);
stringCache.clear();
identifierCache.clear();
+ m_moduleApi = 0;
engine = 0;
}
@@ -114,5 +115,10 @@ QDeclarativeTypeNameCache::Data *QDeclarativeTypeNameCache::data(const QString &
return stringCache.value(id);
}
+void QDeclarativeTypeNameCache::setModuleApi(QDeclarativeMetaType::ModuleApiInstance *api)
+{
+ m_moduleApi = api;
+}
+
QT_END_NAMESPACE
diff --git a/src/declarative/qml/qdeclarativetypenamecache_p.h b/src/declarative/qml/qdeclarativetypenamecache_p.h
index e8a017428d..497633b993 100644
--- a/src/declarative/qml/qdeclarativetypenamecache_p.h
+++ b/src/declarative/qml/qdeclarativetypenamecache_p.h
@@ -55,6 +55,7 @@
#include "private/qdeclarativerefcount_p.h"
#include "private/qdeclarativecleanup_p.h"
+#include "private/qdeclarativemetatype_p.h"
#include <private/qscriptdeclarativeclass_p.h>
@@ -82,6 +83,10 @@ public:
Data *data(const QString &) const;
inline Data *data(const QScriptDeclarativeClass::Identifier &id) const;
+ inline bool isEmpty() const;
+
+ inline QDeclarativeMetaType::ModuleApiInstance *moduleApi() const;
+ void setModuleApi(QDeclarativeMetaType::ModuleApiInstance *);
protected:
virtual void clear();
@@ -96,6 +101,7 @@ private:
StringCache stringCache;
IdentifierCache identifierCache;
QDeclarativeEngine *engine;
+ QDeclarativeMetaType::ModuleApiInstance *m_moduleApi;
};
QDeclarativeTypeNameCache::Data::Data()
@@ -113,6 +119,16 @@ QDeclarativeTypeNameCache::Data *QDeclarativeTypeNameCache::data(const QScriptDe
return identifierCache.value(id);
}
+bool QDeclarativeTypeNameCache::isEmpty() const
+{
+ return identifierCache.isEmpty();
+}
+
+QDeclarativeMetaType::ModuleApiInstance *QDeclarativeTypeNameCache::moduleApi() const
+{
+ return m_moduleApi;
+}
+
QT_END_NAMESPACE
#endif // QDECLARATIVETYPENAMECACHE_P_H
diff --git a/src/declarative/qml/qdeclarativetypenamescriptclass.cpp b/src/declarative/qml/qdeclarativetypenamescriptclass.cpp
index 1cabff5a28..32fcdb4c08 100644
--- a/src/declarative/qml/qdeclarativetypenamescriptclass.cpp
+++ b/src/declarative/qml/qdeclarativetypenamescriptclass.cpp
@@ -63,7 +63,7 @@ struct TypeNameData : public QScriptDeclarativeClass::Object {
QDeclarativeTypeNameScriptClass::QDeclarativeTypeNameScriptClass(QDeclarativeEngine *bindEngine)
: QScriptDeclarativeClass(QDeclarativeEnginePrivate::getScriptEngine(bindEngine)),
- engine(bindEngine), object(0), type(0)
+ engine(bindEngine), object(0), type(0), api(0)
{
}
@@ -95,14 +95,35 @@ QDeclarativeTypeNameScriptClass::queryProperty(Object *obj, const Identifier &na
object = 0;
type = 0;
+ api = 0;
QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
if (data->typeNamespace) {
-
QDeclarativeTypeNameCache::Data *d = data->typeNamespace->data(name);
if (d && d->type) {
type = d->type;
return QScriptClass::HandlesReadAccess;
+ } else if (QDeclarativeMetaType::ModuleApiInstance *moduleApi = data->typeNamespace->moduleApi()) {
+ if (moduleApi->scriptCallback) {
+ moduleApi->scriptApi = moduleApi->scriptCallback(engine, &ep->scriptEngine);
+ moduleApi->scriptCallback = 0;
+ moduleApi->qobjectCallback = 0;
+ } else if (moduleApi->qobjectCallback) {
+ moduleApi->qobjectApi = moduleApi->qobjectCallback(engine, &ep->scriptEngine);
+ moduleApi->scriptCallback = 0;
+ moduleApi->qobjectCallback = 0;
+ }
+
+ api = moduleApi;
+ if (api->qobjectApi) {
+ return ep->objectClass->queryProperty(api->qobjectApi, name, flags, 0,
+ QDeclarativeObjectScriptClass::SkipAttachedProperties);
+ } else {
+ return QScriptClass::HandlesReadAccess;
+ }
+
+ return 0;
+
} else {
return 0;
}
@@ -147,6 +168,10 @@ QDeclarativeTypeNameScriptClass::property(Object *obj, const Identifier &name)
return Value(scriptEngine, newObject(((TypeNameData *)obj)->object, type, ((TypeNameData *)obj)->mode));
} else if (object) {
return ep->objectClass->property(object, name);
+ } else if (api && api->qobjectApi) {
+ return ep->objectClass->property(api->qobjectApi, name);
+ } else if (api) {
+ return propertyValue(api->scriptApi, name);
} else {
return Value(scriptEngine, enumValue);
}
@@ -154,11 +179,16 @@ QDeclarativeTypeNameScriptClass::property(Object *obj, const Identifier &name)
void QDeclarativeTypeNameScriptClass::setProperty(Object *, const Identifier &n, const QScriptValue &v)
{
- Q_ASSERT(object);
Q_ASSERT(!type);
QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
- ep->objectClass->setProperty(object, n, v, context());
+ if (api) {
+ Q_ASSERT(api->qobjectApi);
+ ep->objectClass->setProperty(api->qobjectApi, n, v, context());
+ } else {
+ Q_ASSERT(object);
+ ep->objectClass->setProperty(object, n, v, context());
+ }
}
QT_END_NAMESPACE
diff --git a/src/declarative/qml/qdeclarativetypenamescriptclass_p.h b/src/declarative/qml/qdeclarativetypenamescriptclass_p.h
index 8e8e19c427..9f386ba3a2 100644
--- a/src/declarative/qml/qdeclarativetypenamescriptclass_p.h
+++ b/src/declarative/qml/qdeclarativetypenamescriptclass_p.h
@@ -83,6 +83,7 @@ private:
QDeclarativeEngine *engine;
QObject *object;
QDeclarativeType *type;
+ QDeclarativeMetaType::ModuleApiInstance *api;
quint32 enumValue;
};
diff --git a/src/declarative/qml/qdeclarativevme.cpp b/src/declarative/qml/qdeclarativevme.cpp
index 06aed98594..dd080a85e9 100644
--- a/src/declarative/qml/qdeclarativevme.cpp
+++ b/src/declarative/qml/qdeclarativevme.cpp
@@ -57,8 +57,9 @@
#include "private/qdeclarativevmemetaobject_p.h"
#include "private/qdeclarativebinding_p_p.h"
#include "private/qdeclarativecontext_p.h"
-#include "private/qdeclarativecompiledbindings_p.h"
+#include "private/qdeclarativev4bindings_p.h"
#include "private/qdeclarativeglobal_p.h"
+#include "private/qdeclarativeglobalscriptclass_p.h"
#include "qdeclarativescriptstring.h"
#include <QStack>
@@ -71,6 +72,7 @@
#include <QtCore/qvarlengtharray.h>
#include <QtCore/qcoreapplication.h>
#include <QtCore/qdatetime.h>
+#include <QtScript/qscriptvalue.h>
QT_BEGIN_NAMESPACE
@@ -78,11 +80,11 @@ QDeclarativeVME::QDeclarativeVME()
{
}
-#define VME_EXCEPTION(desc) \
+#define VME_EXCEPTION(desc, line) \
{ \
QDeclarativeError error; \
error.setDescription(desc.trimmed()); \
- error.setLine(instr.line); \
+ error.setLine(line); \
error.setUrl(comp->url); \
vmeErrors << error; \
break; \
@@ -100,14 +102,13 @@ struct ListInstance
};
QObject *QDeclarativeVME::run(QDeclarativeContextData *ctxt, QDeclarativeCompiledData *comp,
- int start, int count, const QBitField &bindingSkipList)
+ int start, const QBitField &bindingSkipList)
{
QDeclarativeVMEStack<QObject *> stack;
if (start == -1) start = 0;
- if (count == -1) count = comp->bytecode.count();
- return run(stack, ctxt, comp, start, count, bindingSkipList);
+ return run(stack, ctxt, comp, start, bindingSkipList);
}
void QDeclarativeVME::runDeferred(QObject *object)
@@ -119,12 +120,11 @@ void QDeclarativeVME::runDeferred(QObject *object)
QDeclarativeContextData *ctxt = data->context;
QDeclarativeCompiledData *comp = data->deferredComponent;
- int start = data->deferredIdx + 1;
- int count = data->deferredComponent->bytecode.at(data->deferredIdx).defer.deferCount;
+ int start = data->deferredIdx;
QDeclarativeVMEStack<QObject *> stack;
stack.push(object);
- run(stack, ctxt, comp, start, count, QBitField());
+ run(stack, ctxt, comp, start, QBitField());
}
inline bool fastHasBinding(QObject *o, int index)
@@ -141,24 +141,28 @@ static void removeBindingOnProperty(QObject *o, int index)
if (binding) binding->destroy();
}
+#define QML_BEGIN_INSTR(I) \
+ case QDeclarativeInstruction::I: { \
+ const QDeclarativeInstructionMeta<(int)QDeclarativeInstruction::I>::DataType &instr = QDeclarativeInstructionMeta<(int)QDeclarativeInstruction::I>::data(genericInstr); \
+ instructionStream += QDeclarativeInstructionMeta<(int)QDeclarativeInstruction::I>::Size; \
+ Q_UNUSED(instr);
+
+#define QML_END_INSTR(I) } break;
+
#define CLEAN_PROPERTY(o, index) if (fastHasBinding(o, index)) removeBindingOnProperty(o, index)
QObject *QDeclarativeVME::run(QDeclarativeVMEStack<QObject *> &stack,
QDeclarativeContextData *ctxt,
QDeclarativeCompiledData *comp,
- int start, int count,
- const QBitField &bindingSkipList)
+ int start, const QBitField &bindingSkipList)
{
Q_ASSERT(comp);
Q_ASSERT(ctxt);
const QList<QDeclarativeCompiledData::TypeReference> &types = comp->types;
const QList<QString> &primitives = comp->primitives;
const QList<QByteArray> &datas = comp->datas;
- const QList<QDeclarativeCompiledData::CustomTypeData> &customTypeData = comp->customTypeData;
- const QList<int> &intData = comp->intData;
- const QList<float> &floatData = comp->floatData;
const QList<QDeclarativePropertyCache *> &propertyCaches = comp->propertyCaches;
- const QList<QDeclarativeParser::Object::ScriptBlock> &scripts = comp->scripts;
+ const QList<QDeclarativeScriptData *> &scripts = comp->scripts;
const QList<QUrl> &urls = comp->urls;
QDeclarativeEnginePrivate::SimpleList<QDeclarativeAbstractBinding> bindValues;
@@ -173,821 +177,725 @@ QObject *QDeclarativeVME::run(QDeclarativeVMEStack<QObject *> &stack,
QDeclarativePropertyPrivate::WriteFlags flags = QDeclarativePropertyPrivate::BypassInterceptor |
QDeclarativePropertyPrivate::RemoveBindingOnAliasWrite;
- for (int ii = start; !isError() && ii < (start + count); ++ii) {
- const QDeclarativeInstruction &instr = comp->bytecode.at(ii);
-
- switch(instr.type) {
- case QDeclarativeInstruction::Init:
- {
- if (instr.init.bindingsSize)
- bindValues = QDeclarativeEnginePrivate::SimpleList<QDeclarativeAbstractBinding>(instr.init.bindingsSize);
- if (instr.init.parserStatusSize)
- parserStatus = QDeclarativeEnginePrivate::SimpleList<QDeclarativeParserStatus>(instr.init.parserStatusSize);
- if (instr.init.contextCache != -1)
- ctxt->setIdPropertyData(comp->contextCaches.at(instr.init.contextCache));
- if (instr.init.compiledBinding != -1)
- ctxt->optimizedBindings = new QDeclarativeCompiledBindings(datas.at(instr.init.compiledBinding).constData(), ctxt);
+ const char *instructionStream = comp->bytecode.constData() + start;
+
+ bool done = false;
+ while (!isError() && !done) {
+ const QDeclarativeInstruction &genericInstr = *((QDeclarativeInstruction *)instructionStream);
+
+ switch(genericInstr.type()) {
+ QML_BEGIN_INSTR(Init)
+ if (instr.bindingsSize)
+ bindValues = QDeclarativeEnginePrivate::SimpleList<QDeclarativeAbstractBinding>(instr.bindingsSize);
+ if (instr.parserStatusSize)
+ parserStatus = QDeclarativeEnginePrivate::SimpleList<QDeclarativeParserStatus>(instr.parserStatusSize);
+ if (instr.contextCache != -1)
+ ctxt->setIdPropertyData(comp->contextCaches.at(instr.contextCache));
+ if (instr.compiledBinding != -1)
+ ctxt->optimizedBindings = new QDeclarativeV4Bindings(datas.at(instr.compiledBinding).constData(), ctxt);
+ QML_END_INSTR(Init)
+
+ QML_BEGIN_INSTR(Done)
+ done = true;
+ QML_END_INSTR(Done)
+
+ QML_BEGIN_INSTR(CreateObject)
+ QBitField bindings;
+ if (instr.bindingBits != -1) {
+ const QByteArray &bits = datas.at(instr.bindingBits);
+ bindings = QBitField((const quint32*)bits.constData(),
+ bits.size() * 8);
}
- break;
-
- case QDeclarativeInstruction::CreateObject:
- {
- QBitField bindings;
- if (instr.create.bindingBits != -1) {
- const QByteArray &bits = datas.at(instr.create.bindingBits);
- bindings = QBitField((const quint32*)bits.constData(),
- bits.size() * 8);
- }
- if (stack.isEmpty())
- bindings = bindings.united(bindingSkipList);
+ if (stack.isEmpty())
+ bindings = bindings.united(bindingSkipList);
- QObject *o =
- types.at(instr.create.type).createInstance(ctxt, bindings, &vmeErrors);
-
- if (!o) {
- VME_EXCEPTION(QCoreApplication::translate("QDeclarativeVME","Unable to create object of type %1").arg(QString::fromLatin1(types.at(instr.create.type).className)));
- }
-
- QDeclarativeData *ddata = QDeclarativeData::get(o);
- Q_ASSERT(ddata);
-
- if (stack.isEmpty()) {
- if (ddata->context) {
- Q_ASSERT(ddata->context != ctxt);
- Q_ASSERT(ddata->outerContext);
- Q_ASSERT(ddata->outerContext != ctxt);
- QDeclarativeContextData *c = ddata->context;
- while (c->linkedContext) c = c->linkedContext;
- c->linkedContext = ctxt;
- } else {
- ctxt->addObject(o);
- }
+ QObject *o =
+ types.at(instr.type).createInstance(ctxt, bindings, &vmeErrors);
- ddata->ownContext = true;
- } else if (!ddata->context) {
- ctxt->addObject(o);
- }
-
- ddata->setImplicitDestructible();
- ddata->outerContext = ctxt;
- ddata->lineNumber = instr.line;
- ddata->columnNumber = instr.create.column;
-
- if (instr.create.data != -1) {
- QDeclarativeCustomParser *customParser =
- types.at(instr.create.type).type->customParser();
- customParser->setCustomData(o, datas.at(instr.create.data));
- }
- if (!stack.isEmpty()) {
- QObject *parent = stack.top();
- if (o->isWidgetType()) {
- QWidget *widget = static_cast<QWidget*>(o);
- if (parent->isWidgetType()) {
- QWidget *parentWidget = static_cast<QWidget*>(parent);
- widget->setParent(parentWidget);
- } else {
- // TODO: parent might be a layout
- }
- } else {
- QDeclarative_setParent_noEvent(o, parent);
- }
- }
- stack.push(o);
+ if (!o) {
+ VME_EXCEPTION(QCoreApplication::translate("QDeclarativeVME","Unable to create object of type %1").arg(QString::fromLatin1(types.at(instr.type).className)), instr.line);
}
- break;
-
- case QDeclarativeInstruction::CreateSimpleObject:
- {
- QObject *o = (QObject *)operator new(instr.createSimple.typeSize +
- sizeof(QDeclarativeData));
- ::memset(o, 0, instr.createSimple.typeSize + sizeof(QDeclarativeData));
- instr.createSimple.create(o);
-
- QDeclarativeData *ddata = (QDeclarativeData *)(((const char *)o) + instr.createSimple.typeSize);
- const QDeclarativeCompiledData::TypeReference &ref = types.at(instr.createSimple.type);
- if (!ddata->propertyCache && ref.typePropertyCache) {
- ddata->propertyCache = ref.typePropertyCache;
- ddata->propertyCache->addref();
- }
- ddata->lineNumber = instr.line;
- ddata->columnNumber = instr.createSimple.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 = stack.top();
- QDeclarative_setParent_noEvent(o, parent);
-
- stack.push(o);
- }
- break;
-
- case QDeclarativeInstruction::SetId:
- {
- QObject *target = stack.top();
- ctxt->setIdProperty(instr.setId.index, target);
- }
- break;
-
-
- case QDeclarativeInstruction::SetDefault:
- {
- ctxt->contextObject = stack.top();
- }
- break;
- case QDeclarativeInstruction::CreateComponent:
- {
- QDeclarativeComponent *qcomp =
- new QDeclarativeComponent(ctxt->engine, comp, ii + 1, instr.createComponent.count,
- stack.isEmpty() ? 0 : stack.top());
-
- QDeclarativeData *ddata = QDeclarativeData::get(qcomp, true);
- Q_ASSERT(ddata);
-
- ctxt->addObject(qcomp);
-
- if (stack.isEmpty())
- ddata->ownContext = true;
-
- ddata->setImplicitDestructible();
- ddata->outerContext = ctxt;
- ddata->lineNumber = instr.line;
- ddata->columnNumber = instr.create.column;
-
- QDeclarativeComponentPrivate::get(qcomp)->creationContext = ctxt;
-
- stack.push(qcomp);
- ii += instr.createComponent.count;
- }
- break;
-
- case QDeclarativeInstruction::StoreMetaObject:
- {
- QObject *target = stack.top();
-
- QMetaObject mo;
- const QByteArray &metadata = datas.at(instr.storeMeta.data);
- QMetaObjectBuilder::fromRelocatableData(&mo, 0, metadata);
-
- const QDeclarativeVMEMetaData *data =
- (const QDeclarativeVMEMetaData *)datas.at(instr.storeMeta.aliasData).constData();
-
- (void)new QDeclarativeVMEMetaObject(target, &mo, data, comp);
-
- if (instr.storeMeta.propertyCache != -1) {
- QDeclarativeData *ddata = QDeclarativeData::get(target, true);
- if (ddata->propertyCache) ddata->propertyCache->release();
- ddata->propertyCache = propertyCaches.at(instr.storeMeta.propertyCache);
- ddata->propertyCache->addref();
+ QDeclarativeData *ddata = QDeclarativeData::get(o);
+ Q_ASSERT(ddata);
+
+ if (stack.isEmpty()) {
+ if (ddata->context) {
+ Q_ASSERT(ddata->context != ctxt);
+ Q_ASSERT(ddata->outerContext);
+ Q_ASSERT(ddata->outerContext != ctxt);
+ QDeclarativeContextData *c = ddata->context;
+ while (c->linkedContext) c = c->linkedContext;
+ c->linkedContext = ctxt;
+ } else {
+ ctxt->addObject(o);
}
- }
- break;
-
- case QDeclarativeInstruction::StoreVariant:
- {
- QObject *target = stack.top();
- CLEAN_PROPERTY(target, instr.storeString.propertyIndex);
-
- // XXX - can be more efficient
- QVariant v = QDeclarativeStringConverters::variantFromString(primitives.at(instr.storeString.value));
- void *a[] = { &v, 0, &status, &flags };
- QMetaObject::metacall(target, QMetaObject::WriteProperty,
- instr.storeString.propertyIndex, a);
- }
- break;
-
- case QDeclarativeInstruction::StoreVariantInteger:
- {
- QObject *target = stack.top();
- CLEAN_PROPERTY(target, instr.storeString.propertyIndex);
-
- QVariant v(instr.storeInteger.value);
- void *a[] = { &v, 0, &status, &flags };
- QMetaObject::metacall(target, QMetaObject::WriteProperty,
- instr.storeString.propertyIndex, a);
- }
- break;
-
- case QDeclarativeInstruction::StoreVariantDouble:
- {
- QObject *target = stack.top();
- CLEAN_PROPERTY(target, instr.storeString.propertyIndex);
-
- QVariant v(instr.storeDouble.value);
- void *a[] = { &v, 0, &status, &flags };
- QMetaObject::metacall(target, QMetaObject::WriteProperty,
- instr.storeString.propertyIndex, a);
- }
- break;
-
- case QDeclarativeInstruction::StoreVariantBool:
- {
- QObject *target = stack.top();
- CLEAN_PROPERTY(target, instr.storeString.propertyIndex);
-
- QVariant v(instr.storeBool.value);
- void *a[] = { &v, 0, &status, &flags };
- QMetaObject::metacall(target, QMetaObject::WriteProperty,
- instr.storeString.propertyIndex, a);
- }
- break;
-
- case QDeclarativeInstruction::StoreString:
- {
- QObject *target = stack.top();
- CLEAN_PROPERTY(target, instr.storeString.propertyIndex);
-
- void *a[] = { (void *)&primitives.at(instr.storeString.value), 0, &status, &flags };
- QMetaObject::metacall(target, QMetaObject::WriteProperty,
- instr.storeString.propertyIndex, a);
- }
- break;
-
- case QDeclarativeInstruction::StoreUrl:
- {
- QObject *target = stack.top();
- CLEAN_PROPERTY(target, instr.storeUrl.propertyIndex);
-
- void *a[] = { (void *)&urls.at(instr.storeUrl.value), 0, &status, &flags };
- QMetaObject::metacall(target, QMetaObject::WriteProperty,
- instr.storeUrl.propertyIndex, a);
- }
- break;
-
- case QDeclarativeInstruction::StoreFloat:
- {
- QObject *target = stack.top();
- CLEAN_PROPERTY(target, instr.storeFloat.propertyIndex);
-
- float f = instr.storeFloat.value;
- void *a[] = { &f, 0, &status, &flags };
- QMetaObject::metacall(target, QMetaObject::WriteProperty,
- instr.storeFloat.propertyIndex, a);
- }
- break;
-
- case QDeclarativeInstruction::StoreDouble:
- {
- QObject *target = stack.top();
- CLEAN_PROPERTY(target, instr.storeDouble.propertyIndex);
-
- double d = instr.storeDouble.value;
- void *a[] = { &d, 0, &status, &flags };
- QMetaObject::metacall(target, QMetaObject::WriteProperty,
- instr.storeDouble.propertyIndex, a);
- }
- break;
-
- case QDeclarativeInstruction::StoreBool:
- {
- QObject *target = stack.top();
- CLEAN_PROPERTY(target, instr.storeBool.propertyIndex);
-
- void *a[] = { (void *)&instr.storeBool.value, 0, &status, &flags };
- QMetaObject::metacall(target, QMetaObject::WriteProperty,
- instr.storeBool.propertyIndex, a);
- }
- break;
-
- case QDeclarativeInstruction::StoreInteger:
- {
- QObject *target = stack.top();
- CLEAN_PROPERTY(target, instr.storeInteger.propertyIndex);
-
- void *a[] = { (void *)&instr.storeInteger.value, 0, &status, &flags };
- QMetaObject::metacall(target, QMetaObject::WriteProperty,
- instr.storeInteger.propertyIndex, a);
- }
- break;
-
- case QDeclarativeInstruction::StoreColor:
- {
- QObject *target = stack.top();
- CLEAN_PROPERTY(target, instr.storeColor.propertyIndex);
-
- QColor c = QColor::fromRgba(instr.storeColor.value);
- void *a[] = { &c, 0, &status, &flags };
- QMetaObject::metacall(target, QMetaObject::WriteProperty,
- instr.storeColor.propertyIndex, a);
- }
- break;
-
- case QDeclarativeInstruction::StoreDate:
- {
- QObject *target = stack.top();
- CLEAN_PROPERTY(target, instr.storeDate.propertyIndex);
-
- QDate d = QDate::fromJulianDay(instr.storeDate.value);
- void *a[] = { &d, 0, &status, &flags };
- QMetaObject::metacall(target, QMetaObject::WriteProperty,
- instr.storeDate.propertyIndex, a);
- }
- break;
-
- case QDeclarativeInstruction::StoreTime:
- {
- QObject *target = stack.top();
- CLEAN_PROPERTY(target, instr.storeTime.propertyIndex);
-
- QTime t;
- t.setHMS(intData.at(instr.storeTime.valueIndex),
- intData.at(instr.storeTime.valueIndex+1),
- intData.at(instr.storeTime.valueIndex+2),
- intData.at(instr.storeTime.valueIndex+3));
- void *a[] = { &t, 0, &status, &flags };
- QMetaObject::metacall(target, QMetaObject::WriteProperty,
- instr.storeTime.propertyIndex, a);
- }
- break;
-
- case QDeclarativeInstruction::StoreDateTime:
- {
- QObject *target = stack.top();
- CLEAN_PROPERTY(target, instr.storeDateTime.propertyIndex);
-
- QTime t;
- t.setHMS(intData.at(instr.storeDateTime.valueIndex+1),
- intData.at(instr.storeDateTime.valueIndex+2),
- intData.at(instr.storeDateTime.valueIndex+3),
- intData.at(instr.storeDateTime.valueIndex+4));
- QDateTime dt(QDate::fromJulianDay(intData.at(instr.storeDateTime.valueIndex)), t);
- void *a[] = { &dt, 0, &status, &flags };
- QMetaObject::metacall(target, QMetaObject::WriteProperty,
- instr.storeDateTime.propertyIndex, a);
- }
- break;
-
- case QDeclarativeInstruction::StorePoint:
- {
- QObject *target = stack.top();
- CLEAN_PROPERTY(target, instr.storeRealPair.propertyIndex);
-
- QPoint p = QPointF(floatData.at(instr.storeRealPair.valueIndex),
- floatData.at(instr.storeRealPair.valueIndex+1)).toPoint();
- void *a[] = { &p, 0, &status, &flags };
- QMetaObject::metacall(target, QMetaObject::WriteProperty,
- instr.storeRealPair.propertyIndex, a);
- }
- break;
-
- case QDeclarativeInstruction::StorePointF:
- {
- QObject *target = stack.top();
- CLEAN_PROPERTY(target, instr.storeRealPair.propertyIndex);
-
- QPointF p(floatData.at(instr.storeRealPair.valueIndex),
- floatData.at(instr.storeRealPair.valueIndex+1));
- void *a[] = { &p, 0, &status, &flags };
- QMetaObject::metacall(target, QMetaObject::WriteProperty,
- instr.storeRealPair.propertyIndex, a);
- }
- break;
- case QDeclarativeInstruction::StoreSize:
- {
- QObject *target = stack.top();
- CLEAN_PROPERTY(target, instr.storeRealPair.propertyIndex);
-
- QSize p = QSizeF(floatData.at(instr.storeRealPair.valueIndex),
- floatData.at(instr.storeRealPair.valueIndex+1)).toSize();
- void *a[] = { &p, 0, &status, &flags };
- QMetaObject::metacall(target, QMetaObject::WriteProperty,
- instr.storeRealPair.propertyIndex, a);
+ ddata->ownContext = true;
+ } else if (!ddata->context) {
+ ctxt->addObject(o);
}
- break;
- case QDeclarativeInstruction::StoreSizeF:
- {
- QObject *target = stack.top();
- CLEAN_PROPERTY(target, instr.storeRealPair.propertyIndex);
+ ddata->setImplicitDestructible();
+ ddata->outerContext = ctxt;
+ ddata->lineNumber = instr.line;
+ ddata->columnNumber = instr.column;
- QSizeF s(floatData.at(instr.storeRealPair.valueIndex),
- floatData.at(instr.storeRealPair.valueIndex+1));
- void *a[] = { &s, 0, &status, &flags };
- QMetaObject::metacall(target, QMetaObject::WriteProperty,
- instr.storeRealPair.propertyIndex, a);
+ if (instr.data != -1) {
+ QDeclarativeCustomParser *customParser =
+ types.at(instr.type).type->customParser();
+ customParser->setCustomData(o, datas.at(instr.data));
}
- break;
-
- case QDeclarativeInstruction::StoreRect:
- {
- QObject *target = stack.top();
- CLEAN_PROPERTY(target, instr.storeRect.propertyIndex);
-
- QRect r = QRectF(floatData.at(instr.storeRect.valueIndex),
- floatData.at(instr.storeRect.valueIndex+1),
- floatData.at(instr.storeRect.valueIndex+2),
- floatData.at(instr.storeRect.valueIndex+3)).toRect();
- void *a[] = { &r, 0, &status, &flags };
- QMetaObject::metacall(target, QMetaObject::WriteProperty,
- instr.storeRect.propertyIndex, a);
+ if (!stack.isEmpty()) {
+ QObject *parent = stack.top();
+ if (o->isWidgetType()) {
+ QWidget *widget = static_cast<QWidget*>(o);
+ if (parent->isWidgetType()) {
+ QWidget *parentWidget = static_cast<QWidget*>(parent);
+ widget->setParent(parentWidget);
+ } else {
+ // TODO: parent might be a layout
+ }
+ } else {
+ QDeclarative_setParent_noEvent(o, parent);
+ }
}
- break;
-
- case QDeclarativeInstruction::StoreRectF:
- {
- QObject *target = stack.top();
- CLEAN_PROPERTY(target, instr.storeRect.propertyIndex);
-
- QRectF r(floatData.at(instr.storeRect.valueIndex),
- floatData.at(instr.storeRect.valueIndex+1),
- floatData.at(instr.storeRect.valueIndex+2),
- floatData.at(instr.storeRect.valueIndex+3));
- void *a[] = { &r, 0, &status, &flags };
- QMetaObject::metacall(target, QMetaObject::WriteProperty,
- instr.storeRect.propertyIndex, a);
+ stack.push(o);
+ QML_END_INSTR(CreateObject)
+
+ QML_BEGIN_INSTR(CreateSimpleObject)
+ QObject *o = (QObject *)operator new(instr.typeSize + sizeof(QDeclarativeData));
+ ::memset(o, 0, instr.typeSize + sizeof(QDeclarativeData));
+ instr.create(o);
+
+ QDeclarativeData *ddata = (QDeclarativeData *)(((const char *)o) + instr.typeSize);
+ const QDeclarativeCompiledData::TypeReference &ref = types.at(instr.type);
+ if (!ddata->propertyCache && ref.typePropertyCache) {
+ ddata->propertyCache = ref.typePropertyCache;
+ ddata->propertyCache->addref();
}
- break;
+ ddata->lineNumber = instr.line;
+ ddata->columnNumber = instr.column;
- case QDeclarativeInstruction::StoreVector3D:
- {
- QObject *target = stack.top();
- CLEAN_PROPERTY(target, instr.storeVector3D.propertyIndex);
-
- QVector3D p(floatData.at(instr.storeVector3D.valueIndex),
- floatData.at(instr.storeVector3D.valueIndex+1),
- floatData.at(instr.storeVector3D.valueIndex+2));
- void *a[] = { &p, 0, &status, &flags };
- QMetaObject::metacall(target, QMetaObject::WriteProperty,
- instr.storeVector3D.propertyIndex, a);
- }
- break;
+ 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;
- case QDeclarativeInstruction::StoreObject:
- {
- QObject *assignObj = stack.pop();
- QObject *target = stack.top();
- CLEAN_PROPERTY(target, instr.storeObject.propertyIndex);
+ QObject *parent = stack.top();
+ QDeclarative_setParent_noEvent(o, parent);
- void *a[] = { (void *)&assignObj, 0, &status, &flags };
- QMetaObject::metacall(target, QMetaObject::WriteProperty,
- instr.storeObject.propertyIndex, a);
- }
- break;
+ stack.push(o);
+ QML_END_INSTR(CreateSimpleObject)
+ QML_BEGIN_INSTR(SetId)
+ QObject *target = stack.top();
+ ctxt->setIdProperty(instr.index, target);
+ QML_END_INSTR(SetId)
- case QDeclarativeInstruction::AssignCustomType:
- {
- QObject *target = stack.top();
- CLEAN_PROPERTY(target, instr.assignCustomType.propertyIndex);
-
- QDeclarativeCompiledData::CustomTypeData data = customTypeData.at(instr.assignCustomType.valueIndex);
- const QString &primitive = primitives.at(data.index);
- QDeclarativeMetaType::StringConverter converter =
- QDeclarativeMetaType::customStringConverter(data.type);
- QVariant v = (*converter)(primitive);
-
- QMetaProperty prop =
- target->metaObject()->property(instr.assignCustomType.propertyIndex);
- if (v.isNull() || ((int)prop.type() != data.type && prop.userType() != data.type))
- VME_EXCEPTION(QCoreApplication::translate("QDeclarativeVME","Cannot assign value %1 to property %2").arg(primitive).arg(QString::fromUtf8(prop.name())));
-
- void *a[] = { (void *)v.data(), 0, &status, &flags };
- QMetaObject::metacall(target, QMetaObject::WriteProperty,
- instr.assignCustomType.propertyIndex, a);
- }
- break;
+ QML_BEGIN_INSTR(SetDefault)
+ ctxt->contextObject = stack.top();
+ QML_END_INSTR(SetDefault)
- case QDeclarativeInstruction::AssignSignalObject:
- {
- // XXX optimize
+ QML_BEGIN_INSTR(CreateComponent)
+ QDeclarativeComponent *qcomp =
+ new QDeclarativeComponent(ctxt->engine, comp, instructionStream - comp->bytecode.constData(),
+ stack.isEmpty() ? 0 : stack.top());
- QObject *assign = stack.pop();
- QObject *target = stack.top();
- int sigIdx = instr.assignSignalObject.signal;
- const QByteArray &pr = datas.at(sigIdx);
+ QDeclarativeData *ddata = QDeclarativeData::get(qcomp, true);
+ Q_ASSERT(ddata);
- QDeclarativeProperty prop(target, QString::fromUtf8(pr));
- if (prop.type() & QDeclarativeProperty::SignalProperty) {
+ ctxt->addObject(qcomp);
- QMetaMethod method = QDeclarativeMetaType::defaultMethod(assign);
- if (method.signature() == 0)
- VME_EXCEPTION(QCoreApplication::translate("QDeclarativeVME","Cannot assign object type %1 with no default method").arg(QString::fromLatin1(assign->metaObject()->className())));
+ if (stack.isEmpty())
+ ddata->ownContext = true;
- if (!QMetaObject::checkConnectArgs(prop.method().signature(), method.signature()))
- VME_EXCEPTION(QCoreApplication::translate("QDeclarativeVME","Cannot connect mismatched signal/slot %1 %vs. %2").arg(QString::fromLatin1(method.signature())).arg(QString::fromLatin1(prop.method().signature())));
+ ddata->setImplicitDestructible();
+ ddata->outerContext = ctxt;
+ ddata->lineNumber = instr.line;
+ ddata->columnNumber = instr.column;
- QDeclarativePropertyPrivate::connect(target, prop.index(), assign, method.methodIndex());
+ QDeclarativeComponentPrivate::get(qcomp)->creationContext = ctxt;
- } else {
- VME_EXCEPTION(QCoreApplication::translate("QDeclarativeVME","Cannot assign an object to signal property %1").arg(QString::fromUtf8(pr)));
- }
+ stack.push(qcomp);
+ instructionStream += instr.count;
+ QML_END_INSTR(CreateComponent)
+ QML_BEGIN_INSTR(StoreMetaObject)
+ QObject *target = stack.top();
- }
- break;
+ QMetaObject mo;
+ const QByteArray &metadata = datas.at(instr.data);
+ QMetaObjectBuilder::fromRelocatableData(&mo, 0, metadata);
- case QDeclarativeInstruction::StoreSignal:
- {
- QObject *target = stack.top();
- QObject *context = stack.at(stack.count() - 1 - instr.storeSignal.context);
+ const QDeclarativeVMEMetaData *data =
+ (const QDeclarativeVMEMetaData *)datas.at(instr.aliasData).constData();
- QMetaMethod signal = target->metaObject()->method(instr.storeSignal.signalIndex);
+ (void)new QDeclarativeVMEMetaObject(target, &mo, data, comp);
- QDeclarativeBoundSignal *bs = new QDeclarativeBoundSignal(target, signal, target);
- QDeclarativeExpression *expr =
- new QDeclarativeExpression(ctxt, context, primitives.at(instr.storeSignal.value));
- expr->setSourceLocation(comp->name, instr.line);
- static_cast<QDeclarativeExpressionPrivate *>(QObjectPrivate::get(expr))->name = datas.at(instr.storeSignal.name);
- bs->setExpression(expr);
+ if (instr.propertyCache != -1) {
+ QDeclarativeData *ddata = QDeclarativeData::get(target, true);
+ if (ddata->propertyCache) ddata->propertyCache->release();
+ ddata->propertyCache = propertyCaches.at(instr.propertyCache);
+ ddata->propertyCache->addref();
}
- break;
-
- case QDeclarativeInstruction::StoreImportedScript:
- {
- ctxt->addImportedScript(scripts.at(instr.storeScript.value));
+ QML_END_INSTR(StoreMetaObject)
+
+ QML_BEGIN_INSTR(StoreVariant)
+ QObject *target = stack.top();
+ CLEAN_PROPERTY(target, instr.propertyIndex);
+
+ // XXX - can be more efficient
+ QVariant v = QDeclarativeStringConverters::variantFromString(primitives.at(instr.value));
+ void *a[] = { &v, 0, &status, &flags };
+ QMetaObject::metacall(target, QMetaObject::WriteProperty,
+ instr.propertyIndex, a);
+ QML_END_INSTR(StoreVariant)
+
+ QML_BEGIN_INSTR(StoreVariantInteger)
+ QObject *target = stack.top();
+ CLEAN_PROPERTY(target, instr.propertyIndex);
+
+ QVariant v(instr.value);
+ void *a[] = { &v, 0, &status, &flags };
+ QMetaObject::metacall(target, QMetaObject::WriteProperty,
+ instr.propertyIndex, a);
+ QML_END_INSTR(StoreVariantInteger)
+
+ QML_BEGIN_INSTR(StoreVariantDouble)
+ QObject *target = stack.top();
+ CLEAN_PROPERTY(target, instr.propertyIndex);
+
+ QVariant v(instr.value);
+ void *a[] = { &v, 0, &status, &flags };
+ QMetaObject::metacall(target, QMetaObject::WriteProperty,
+ instr.propertyIndex, a);
+ QML_END_INSTR(StoreVariantDouble)
+
+ QML_BEGIN_INSTR(StoreVariantBool)
+ QObject *target = stack.top();
+ CLEAN_PROPERTY(target, instr.propertyIndex);
+
+ QVariant v(instr.value);
+ void *a[] = { &v, 0, &status, &flags };
+ QMetaObject::metacall(target, QMetaObject::WriteProperty,
+ instr.propertyIndex, a);
+ QML_END_INSTR(StoreVariantBool)
+
+ QML_BEGIN_INSTR(StoreString)
+ QObject *target = stack.top();
+ CLEAN_PROPERTY(target, instr.propertyIndex);
+
+ void *a[] = { (void *)&primitives.at(instr.value), 0, &status, &flags };
+ QMetaObject::metacall(target, QMetaObject::WriteProperty,
+ instr.propertyIndex, a);
+ QML_END_INSTR(StoreString)
+
+ QML_BEGIN_INSTR(StoreByteArray)
+ QObject *target = stack.top();
+ void *a[] = { (void *)&datas.at(instr.value), 0, &status, &flags };
+ QMetaObject::metacall(target, QMetaObject::WriteProperty,
+ instr.propertyIndex, a);
+ QML_END_INSTR(StoreByteArray)
+
+ QML_BEGIN_INSTR(StoreUrl)
+ QObject *target = stack.top();
+ CLEAN_PROPERTY(target, instr.propertyIndex);
+
+ void *a[] = { (void *)&urls.at(instr.value), 0, &status, &flags };
+ QMetaObject::metacall(target, QMetaObject::WriteProperty,
+ instr.propertyIndex, a);
+ QML_END_INSTR(StoreUrl)
+
+ QML_BEGIN_INSTR(StoreFloat)
+ QObject *target = stack.top();
+ CLEAN_PROPERTY(target, instr.propertyIndex);
+
+ float f = instr.value;
+ void *a[] = { &f, 0, &status, &flags };
+ QMetaObject::metacall(target, QMetaObject::WriteProperty,
+ instr.propertyIndex, a);
+ QML_END_INSTR(StoreFloat)
+
+ QML_BEGIN_INSTR(StoreDouble)
+ QObject *target = stack.top();
+ CLEAN_PROPERTY(target, instr.propertyIndex);
+
+ double d = instr.value;
+ void *a[] = { &d, 0, &status, &flags };
+ QMetaObject::metacall(target, QMetaObject::WriteProperty,
+ instr.propertyIndex, a);
+ QML_END_INSTR(StoreDouble)
+
+ QML_BEGIN_INSTR(StoreBool)
+ QObject *target = stack.top();
+ CLEAN_PROPERTY(target, instr.propertyIndex);
+
+ void *a[] = { (void *)&instr.value, 0, &status, &flags };
+ QMetaObject::metacall(target, QMetaObject::WriteProperty,
+ instr.propertyIndex, a);
+ QML_END_INSTR(StoreBool)
+
+ QML_BEGIN_INSTR(StoreInteger)
+ QObject *target = stack.top();
+ CLEAN_PROPERTY(target, instr.propertyIndex);
+
+ void *a[] = { (void *)&instr.value, 0, &status, &flags };
+ QMetaObject::metacall(target, QMetaObject::WriteProperty,
+ instr.propertyIndex, a);
+ QML_END_INSTR(StoreInteger)
+
+ QML_BEGIN_INSTR(StoreColor)
+ QObject *target = stack.top();
+ CLEAN_PROPERTY(target, instr.propertyIndex);
+
+ QColor c = QColor::fromRgba(instr.value);
+ void *a[] = { &c, 0, &status, &flags };
+ QMetaObject::metacall(target, QMetaObject::WriteProperty,
+ instr.propertyIndex, a);
+ QML_END_INSTR(StoreColor)
+
+ QML_BEGIN_INSTR(StoreDate)
+ QObject *target = stack.top();
+ CLEAN_PROPERTY(target, instr.propertyIndex);
+
+ QDate d = QDate::fromJulianDay(instr.value);
+ void *a[] = { &d, 0, &status, &flags };
+ QMetaObject::metacall(target, QMetaObject::WriteProperty,
+ instr.propertyIndex, a);
+ QML_END_INSTR(StoreDate)
+
+ QML_BEGIN_INSTR(StoreTime)
+ QObject *target = stack.top();
+ CLEAN_PROPERTY(target, instr.propertyIndex);
+
+ QTime *t = (QTime *)&instr.time;
+ void *a[] = { t, 0, &status, &flags };
+ QMetaObject::metacall(target, QMetaObject::WriteProperty,
+ instr.propertyIndex, a);
+ QML_END_INSTR(StoreTime)
+
+ QML_BEGIN_INSTR(StoreDateTime)
+ QObject *target = stack.top();
+ CLEAN_PROPERTY(target, instr.propertyIndex);
+
+ QTime *t = (QTime *)&instr.time;
+ QDateTime dt(QDate::fromJulianDay(instr.date), *t);
+ void *a[] = { &dt, 0, &status, &flags };
+ QMetaObject::metacall(target, QMetaObject::WriteProperty,
+ instr.propertyIndex, a);
+ QML_END_INSTR(StoreDateTime)
+
+ QML_BEGIN_INSTR(StorePoint)
+ QObject *target = stack.top();
+ CLEAN_PROPERTY(target, instr.propertyIndex);
+
+ QPoint *p = (QPoint *)&instr.point;
+ void *a[] = { p, 0, &status, &flags };
+ QMetaObject::metacall(target, QMetaObject::WriteProperty,
+ instr.propertyIndex, a);
+ QML_END_INSTR(StorePoint)
+
+ QML_BEGIN_INSTR(StorePointF)
+ QObject *target = stack.top();
+ CLEAN_PROPERTY(target, instr.propertyIndex);
+
+ QPointF *p = (QPointF *)&instr.point;
+ void *a[] = { p, 0, &status, &flags };
+ QMetaObject::metacall(target, QMetaObject::WriteProperty,
+ instr.propertyIndex, a);
+ QML_END_INSTR(StorePointF)
+
+ QML_BEGIN_INSTR(StoreSize)
+ QObject *target = stack.top();
+ CLEAN_PROPERTY(target, instr.propertyIndex);
+
+ QSize *s = (QSize *)&instr.size;
+ void *a[] = { s, 0, &status, &flags };
+ QMetaObject::metacall(target, QMetaObject::WriteProperty,
+ instr.propertyIndex, a);
+ QML_END_INSTR(StoreSize)
+
+ QML_BEGIN_INSTR(StoreSizeF)
+ QObject *target = stack.top();
+ CLEAN_PROPERTY(target, instr.propertyIndex);
+
+ QSizeF *s = (QSizeF *)&instr.size;
+ void *a[] = { s, 0, &status, &flags };
+ QMetaObject::metacall(target, QMetaObject::WriteProperty,
+ instr.propertyIndex, a);
+ QML_END_INSTR(StoreSizeF)
+
+ QML_BEGIN_INSTR(StoreRect)
+ QObject *target = stack.top();
+ CLEAN_PROPERTY(target, instr.propertyIndex);
+
+ QRect *r = (QRect *)&instr.rect;
+ void *a[] = { r, 0, &status, &flags };
+ QMetaObject::metacall(target, QMetaObject::WriteProperty,
+ instr.propertyIndex, a);
+ QML_END_INSTR(StoreRect)
+
+ QML_BEGIN_INSTR(StoreRectF)
+ QObject *target = stack.top();
+ CLEAN_PROPERTY(target, instr.propertyIndex);
+
+ QRectF *r = (QRectF *)&instr.rect;
+ void *a[] = { r, 0, &status, &flags };
+ QMetaObject::metacall(target, QMetaObject::WriteProperty,
+ instr.propertyIndex, a);
+ QML_END_INSTR(StoreRectF)
+
+ QML_BEGIN_INSTR(StoreVector3D)
+ QObject *target = stack.top();
+ CLEAN_PROPERTY(target, instr.propertyIndex);
+
+ QVector3D *v = (QVector3D *)&instr.vector;
+ void *a[] = { v, 0, &status, &flags };
+ QMetaObject::metacall(target, QMetaObject::WriteProperty,
+ instr.propertyIndex, a);
+ QML_END_INSTR(StoreVector3D)
+
+ QML_BEGIN_INSTR(StoreObject)
+ QObject *assignObj = stack.pop();
+ QObject *target = stack.top();
+ CLEAN_PROPERTY(target, instr.propertyIndex);
+
+ void *a[] = { (void *)&assignObj, 0, &status, &flags };
+ QMetaObject::metacall(target, QMetaObject::WriteProperty,
+ instr.propertyIndex, a);
+ QML_END_INSTR(StoreObject)
+
+ QML_BEGIN_INSTR(AssignCustomType)
+ QObject *target = stack.top();
+ CLEAN_PROPERTY(target, instr.propertyIndex);
+
+ const QString &primitive = primitives.at(instr.primitive);
+ int type = instr.type;
+ QDeclarativeMetaType::StringConverter converter = QDeclarativeMetaType::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(QCoreApplication::translate("QDeclarativeVME","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 = stack.pop();
+ QObject *target = stack.top();
+ int sigIdx = instr.signal;
+ const QByteArray &pr = datas.at(sigIdx);
+
+ QDeclarativeProperty prop(target, QString::fromUtf8(pr));
+ if (prop.type() & QDeclarativeProperty::SignalProperty) {
+
+ QMetaMethod method = QDeclarativeMetaType::defaultMethod(assign);
+ if (method.signature() == 0)
+ VME_EXCEPTION(QCoreApplication::translate("QDeclarativeVME","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(QCoreApplication::translate("QDeclarativeVME","Cannot connect mismatched signal/slot %1 %vs. %2").arg(QString::fromLatin1(method.signature())).arg(QString::fromLatin1(prop.method().signature())), instr.line);
+
+ QDeclarativePropertyPrivate::connect(target, prop.index(), assign, method.methodIndex());
+
+ } else {
+ VME_EXCEPTION(QCoreApplication::translate("QDeclarativeVME","Cannot assign an object to signal property %1").arg(QString::fromUtf8(pr)), instr.line);
}
- break;
- case QDeclarativeInstruction::StoreScriptString:
- {
- QObject *target = stack.top();
- QObject *scope = stack.at(stack.count() - 1 - instr.storeScriptString.scope);
- QDeclarativeScriptString ss;
- ss.setContext(ctxt->asQDeclarativeContext());
- ss.setScopeObject(scope);
- ss.setScript(primitives.at(instr.storeScriptString.value));
-
- void *a[] = { &ss, 0, &status, &flags };
- QMetaObject::metacall(target, QMetaObject::WriteProperty,
- instr.storeScriptString.propertyIndex, a);
- }
- break;
-
- case QDeclarativeInstruction::BeginObject:
- {
- QObject *target = stack.top();
- QDeclarativeParserStatus *status = reinterpret_cast<QDeclarativeParserStatus *>(reinterpret_cast<char *>(target) + instr.begin.castValue);
- parserStatus.append(status);
- status->d = &parserStatus.values[parserStatus.count - 1];
-
- status->classBegin();
- }
- break;
-
- case QDeclarativeInstruction::StoreBinding:
- case QDeclarativeInstruction::StoreBindingOnAlias:
- {
- QObject *target =
- stack.at(stack.count() - 1 - instr.assignBinding.owner);
- QObject *context =
- stack.at(stack.count() - 1 - instr.assignBinding.context);
- QDeclarativeProperty mp =
- QDeclarativePropertyPrivate::restore(datas.at(instr.assignBinding.property), target, ctxt);
-
- int coreIndex = mp.index();
-
- if ((stack.count() - instr.assignBinding.owner) == 1 && bindingSkipList.testBit(coreIndex))
- break;
-
- QDeclarativeBinding *bind = new QDeclarativeBinding((void *)datas.at(instr.assignBinding.value).constData(), comp, context, ctxt, comp->name, instr.line, 0);
- bindValues.append(bind);
- bind->m_mePtr = &bindValues.values[bindValues.count - 1];
- bind->setTarget(mp);
-
- if (instr.type == QDeclarativeInstruction::StoreBindingOnAlias) {
- QDeclarativeAbstractBinding *old = QDeclarativePropertyPrivate::setBindingNoEnable(target, coreIndex, QDeclarativePropertyPrivate::valueTypeCoreIndex(mp), bind);
- if (old) { old->destroy(); }
- } else {
- bind->addToObject(target, QDeclarativePropertyPrivate::bindingIndex(mp));
+ QML_END_INSTR(AssignSignalObject)
+
+ QML_BEGIN_INSTR(StoreSignal)
+ QObject *target = stack.top();
+ QObject *context = stack.at(stack.count() - 1 - instr.context);
+
+ QMetaMethod signal = target->metaObject()->method(instr.signalIndex);
+
+ QDeclarativeBoundSignal *bs = new QDeclarativeBoundSignal(target, signal, target);
+ QDeclarativeExpression *expr =
+ new QDeclarativeExpression(ctxt, context, primitives.at(instr.value));
+ expr->setSourceLocation(comp->name, instr.line);
+ static_cast<QDeclarativeExpressionPrivate *>(QObjectPrivate::get(expr))->name = datas.at(instr.name);
+ 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 = stack.top();
+ QObject *scope = stack.at(stack.count() - 1 - instr.scope);
+ QDeclarativeScriptString ss;
+ ss.setContext(ctxt->asQDeclarativeContext());
+ ss.setScopeObject(scope);
+ ss.setScript(primitives.at(instr.value));
+
+ void *a[] = { &ss, 0, &status, &flags };
+ QMetaObject::metacall(target, QMetaObject::WriteProperty,
+ instr.propertyIndex, a);
+ QML_END_INSTR(StoreScriptString)
+
+ QML_BEGIN_INSTR(BeginObject)
+ QObject *target = stack.top();
+ QDeclarativeParserStatus *status = reinterpret_cast<QDeclarativeParserStatus *>(reinterpret_cast<char *>(target) + instr.castValue);
+ parserStatus.append(status);
+ status->d = &parserStatus.values[parserStatus.count - 1];
+
+ status->classBegin();
+ QML_END_INSTR(BeginObject)
+
+ QML_BEGIN_INSTR(StoreBinding)
+ QObject *target =
+ stack.at(stack.count() - 1 - instr.owner);
+ QObject *context =
+ stack.at(stack.count() - 1 - instr.context);
+
+ QDeclarativeProperty mp =
+ QDeclarativePropertyPrivate::restore(datas.at(instr.property), target, ctxt);
+
+ int coreIndex = mp.index();
+
+ if ((stack.count() - instr.owner) == 1 && bindingSkipList.testBit(coreIndex))
+ break;
+
+ QDeclarativeBinding *bind = new QDeclarativeBinding((void *)datas.at(instr.value).constData(), comp, context, ctxt, comp->name, instr.line, 0);
+ bindValues.append(bind);
+ bind->m_mePtr = &bindValues.values[bindValues.count - 1];
+ bind->setTarget(mp);
+
+ bind->addToObject(target, QDeclarativePropertyPrivate::bindingIndex(mp));
+ QML_END_INSTR(StoreBinding)
+
+ QML_BEGIN_INSTR(StoreBindingOnAlias)
+ QObject *target =
+ stack.at(stack.count() - 1 - instr.owner);
+ QObject *context =
+ stack.at(stack.count() - 1 - instr.context);
+
+ QDeclarativeProperty mp =
+ QDeclarativePropertyPrivate::restore(datas.at(instr.property), target, ctxt);
+
+ int coreIndex = mp.index();
+
+ if ((stack.count() - instr.owner) == 1 && bindingSkipList.testBit(coreIndex))
+ break;
+
+ QDeclarativeBinding *bind = new QDeclarativeBinding((void *)datas.at(instr.value).constData(), comp, context, ctxt, comp->name, instr.line, 0);
+ bindValues.append(bind);
+ bind->m_mePtr = &bindValues.values[bindValues.count - 1];
+ bind->setTarget(mp);
+
+ QDeclarativeAbstractBinding *old = QDeclarativePropertyPrivate::setBindingNoEnable(target, coreIndex, QDeclarativePropertyPrivate::valueTypeCoreIndex(mp), bind);
+ if (old) { old->destroy(); }
+ QML_END_INSTR(StoreBindingOnAlias)
+
+ QML_BEGIN_INSTR(StoreCompiledBinding)
+ QObject *target =
+ stack.at(stack.count() - 1 - instr.owner);
+ QObject *scope =
+ stack.at(stack.count() - 1 - instr.context);
+
+ int property = instr.property;
+ if (stack.count() == 1 && bindingSkipList.testBit(property & 0xFFFF))
+ break;
+
+ QDeclarativeAbstractBinding *binding =
+ ctxt->optimizedBindings->configBinding(instr.value, target, scope, property);
+ bindValues.append(binding);
+ binding->m_mePtr = &bindValues.values[bindValues.count - 1];
+ binding->addToObject(target, property);
+ QML_END_INSTR(StoreCompiledBinding)
+
+ QML_BEGIN_INSTR(StoreValueSource)
+ QObject *obj = stack.pop();
+ QDeclarativePropertyValueSource *vs = reinterpret_cast<QDeclarativePropertyValueSource *>(reinterpret_cast<char *>(obj) + instr.castValue);
+ QObject *target = stack.at(stack.count() - 1 - instr.owner);
+
+ QDeclarativeProperty prop =
+ QDeclarativePropertyPrivate::restore(datas.at(instr.property), target, ctxt);
+ obj->setParent(target);
+ vs->setTarget(prop);
+ QML_END_INSTR(StoreValueSource)
+
+ QML_BEGIN_INSTR(StoreValueInterceptor)
+ QObject *obj = stack.pop();
+ QDeclarativePropertyValueInterceptor *vi = reinterpret_cast<QDeclarativePropertyValueInterceptor *>(reinterpret_cast<char *>(obj) + instr.castValue);
+ QObject *target = stack.at(stack.count() - 1 - instr.owner);
+ QDeclarativeProperty prop =
+ QDeclarativePropertyPrivate::restore(datas.at(instr.property), target, ctxt);
+ obj->setParent(target);
+ vi->setTarget(prop);
+ QDeclarativeVMEMetaObject *mo = static_cast<QDeclarativeVMEMetaObject *>((QMetaObject*)target->metaObject());
+ mo->registerInterceptor(prop.index(), QDeclarativePropertyPrivate::valueTypeCoreIndex(prop), vi);
+ QML_END_INSTR(StoreValueInterceptor)
+
+ QML_BEGIN_INSTR(StoreObjectQList)
+ QObject *assign = stack.pop();
+
+ const ListInstance &list = qliststack.top();
+ list.qListProperty.append((QDeclarativeListProperty<void>*)&list.qListProperty, assign);
+ QML_END_INSTR(StoreObjectQList)
+
+ QML_BEGIN_INSTR(AssignObjectList)
+ // This is only used for assigning interfaces
+ QObject *assign = stack.pop();
+ const ListInstance &list = qliststack.top();
+
+ int type = list.type;
+
+ void *ptr = 0;
+
+ const char *iid = QDeclarativeMetaType::interfaceIId(type);
+ if (iid)
+ ptr = assign->qt_metacast(iid);
+ if (!ptr)
+ VME_EXCEPTION(QCoreApplication::translate("QDeclarativeVME","Cannot assign object to list"), instr.line);
+
+
+ list.qListProperty.append((QDeclarativeListProperty<void>*)&list.qListProperty, ptr);
+ QML_END_INSTR(AssignObjectList)
+
+ QML_BEGIN_INSTR(StoreVariantObject)
+ QObject *assign = stack.pop();
+ QObject *target = stack.top();
+ CLEAN_PROPERTY(target, instr.propertyIndex);
+
+ QVariant v = QVariant::fromValue(assign);
+ void *a[] = { &v, 0, &status, &flags };
+ QMetaObject::metacall(target, QMetaObject::WriteProperty,
+ instr.propertyIndex, a);
+ QML_END_INSTR(StoreVariantObject)
+
+ QML_BEGIN_INSTR(StoreInterface)
+ QObject *assign = stack.pop();
+ QObject *target = stack.top();
+ CLEAN_PROPERTY(target, instr.propertyIndex);
+
+ int coreIdx = instr.propertyIndex;
+ QMetaProperty prop = target->metaObject()->property(coreIdx);
+ int t = prop.userType();
+ const char *iid = QDeclarativeMetaType::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;
}
- }
- break;
+ }
- case QDeclarativeInstruction::StoreCompiledBinding:
- {
- QObject *target =
- stack.at(stack.count() - 1 - instr.assignBinding.owner);
- QObject *scope =
- stack.at(stack.count() - 1 - instr.assignBinding.context);
-
- int property = instr.assignBinding.property;
- if (stack.count() == 1 && bindingSkipList.testBit(property & 0xFFFF))
- break;
-
- QDeclarativeAbstractBinding *binding =
- ctxt->optimizedBindings->configBinding(instr.assignBinding.value, target, scope, property);
- bindValues.append(binding);
- binding->m_mePtr = &bindValues.values[bindValues.count - 1];
- binding->addToObject(target, property);
- }
- break;
+ if (!ok)
+ VME_EXCEPTION(QCoreApplication::translate("QDeclarativeVME","Cannot assign object to interface property"), instr.line);
+ QML_END_INSTR(StoreInterface)
+
+ QML_BEGIN_INSTR(FetchAttached)
+ QObject *target = stack.top();
- case QDeclarativeInstruction::StoreValueSource:
- {
- QObject *obj = stack.pop();
- QDeclarativePropertyValueSource *vs = reinterpret_cast<QDeclarativePropertyValueSource *>(reinterpret_cast<char *>(obj) + instr.assignValueSource.castValue);
- QObject *target = stack.at(stack.count() - 1 - instr.assignValueSource.owner);
+ QObject *qmlObject = qmlAttachedPropertiesObjectById(instr.id, target);
- QDeclarativeProperty prop =
- QDeclarativePropertyPrivate::restore(datas.at(instr.assignValueSource.property), target, ctxt);
- obj->setParent(target);
- vs->setTarget(prop);
- }
- break;
+ if (!qmlObject)
+ VME_EXCEPTION(QCoreApplication::translate("QDeclarativeVME","Unable to create attached object"), instr.line);
- case QDeclarativeInstruction::StoreValueInterceptor:
- {
- QObject *obj = stack.pop();
- QDeclarativePropertyValueInterceptor *vi = reinterpret_cast<QDeclarativePropertyValueInterceptor *>(reinterpret_cast<char *>(obj) + instr.assignValueInterceptor.castValue);
- QObject *target = stack.at(stack.count() - 1 - instr.assignValueInterceptor.owner);
- QDeclarativeProperty prop =
- QDeclarativePropertyPrivate::restore(datas.at(instr.assignValueInterceptor.property), target, ctxt);
- obj->setParent(target);
- vi->setTarget(prop);
- QDeclarativeVMEMetaObject *mo = static_cast<QDeclarativeVMEMetaObject *>((QMetaObject*)target->metaObject());
- mo->registerInterceptor(prop.index(), QDeclarativePropertyPrivate::valueTypeCoreIndex(prop), vi);
- }
- break;
+ stack.push(qmlObject);
+ QML_END_INSTR(FetchAttached)
- case QDeclarativeInstruction::StoreObjectQList:
- {
- QObject *assign = stack.pop();
+ QML_BEGIN_INSTR(FetchQList)
+ QObject *target = stack.top();
- const ListInstance &list = qliststack.top();
- list.qListProperty.append((QDeclarativeListProperty<void>*)&list.qListProperty, assign);
- }
- break;
+ qliststack.push(ListInstance(instr.type));
- case QDeclarativeInstruction::AssignObjectList:
- {
- // This is only used for assigning interfaces
- QObject *assign = stack.pop();
- const ListInstance &list = qliststack.top();
+ void *a[1];
+ a[0] = (void *)&(qliststack.top().qListProperty);
+ QMetaObject::metacall(target, QMetaObject::ReadProperty,
+ instr.property, a);
+ QML_END_INSTR(FetchQList)
- int type = list.type;
+ QML_BEGIN_INSTR(FetchObject)
+ QObject *target = stack.top();
- void *ptr = 0;
+ 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);
- const char *iid = QDeclarativeMetaType::interfaceIId(type);
- if (iid)
- ptr = assign->qt_metacast(iid);
- if (!ptr)
- VME_EXCEPTION(QCoreApplication::translate("QDeclarativeVME","Cannot assign object to list"));
+ if (!obj)
+ VME_EXCEPTION(QCoreApplication::translate("QDeclarativeVME","Cannot set properties on %1 as it is null").arg(QString::fromUtf8(target->metaObject()->property(instr.property).name())), instr.line);
+ stack.push(obj);
+ QML_END_INSTR(FetchObject)
- list.qListProperty.append((QDeclarativeListProperty<void>*)&list.qListProperty, ptr);
- }
- break;
+ QML_BEGIN_INSTR(PopQList)
+ qliststack.pop();
+ QML_END_INSTR(PopQList)
- case QDeclarativeInstruction::StoreVariantObject:
- {
- QObject *assign = stack.pop();
+ QML_BEGIN_INSTR(Defer)
+ if (instr.deferCount) {
QObject *target = stack.top();
- CLEAN_PROPERTY(target, instr.storeObject.propertyIndex);
-
- QVariant v = QVariant::fromValue(assign);
- void *a[] = { &v, 0, &status, &flags };
- QMetaObject::metacall(target, QMetaObject::WriteProperty,
- instr.storeObject.propertyIndex, a);
+ QDeclarativeData *data =
+ QDeclarativeData::get(target, true);
+ comp->addref();
+ data->deferredComponent = comp;
+ data->deferredIdx = instructionStream - comp->bytecode.constData();
+ instructionStream += instr.deferCount;
}
- break;
-
- case QDeclarativeInstruction::StoreInterface:
- {
- QObject *assign = stack.pop();
- QObject *target = stack.top();
- CLEAN_PROPERTY(target, instr.storeObject.propertyIndex);
-
- int coreIdx = instr.storeObject.propertyIndex;
- QMetaProperty prop = target->metaObject()->property(coreIdx);
- int t = prop.userType();
- const char *iid = QDeclarativeMetaType::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;
+ QML_END_INSTR(Defer)
+
+ QML_BEGIN_INSTR(PopFetchedObject)
+ stack.pop();
+ QML_END_INSTR(PopFetchedObject)
+
+ QML_BEGIN_INSTR(FetchValueType)
+ QObject *target = stack.top();
+
+ if (instr.bindingSkipList != 0) {
+ // Possibly need to clear bindings
+ QDeclarativeData *targetData = QDeclarativeData::get(target);
+ if (targetData) {
+ QDeclarativeAbstractBinding *binding =
+ QDeclarativePropertyPrivate::binding(target, instr.property, -1);
+
+ if (binding && binding->bindingType() != QDeclarativeAbstractBinding::ValueTypeProxy) {
+ QDeclarativePropertyPrivate::setBinding(target, instr.property, -1, 0);
+ binding->destroy();
+ } else if (binding) {
+ QDeclarativeValueTypeProxyBinding *proxy =
+ static_cast<QDeclarativeValueTypeProxyBinding *>(binding);
+ proxy->removeBindings(instr.bindingSkipList);
}
- }
-
- if (!ok)
- VME_EXCEPTION(QCoreApplication::translate("QDeclarativeVME","Cannot assign object to interface property"));
- }
- break;
-
- case QDeclarativeInstruction::FetchAttached:
- {
- QObject *target = stack.top();
-
- QObject *qmlObject = qmlAttachedPropertiesObjectById(instr.fetchAttached.id, target);
-
- if (!qmlObject)
- VME_EXCEPTION(QCoreApplication::translate("QDeclarativeVME","Unable to create attached object"));
-
- stack.push(qmlObject);
- }
- break;
-
- case QDeclarativeInstruction::FetchQList:
- {
- QObject *target = stack.top();
-
- qliststack.push(ListInstance(instr.fetchQmlList.type));
-
- void *a[1];
- a[0] = (void *)&(qliststack.top().qListProperty);
- QMetaObject::metacall(target, QMetaObject::ReadProperty,
- instr.fetchQmlList.property, a);
- }
- break;
-
- case QDeclarativeInstruction::FetchObject:
- {
- QObject *target = stack.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.fetch.property, a);
-
- if (!obj)
- VME_EXCEPTION(QCoreApplication::translate("QDeclarativeVME","Cannot set properties on %1 as it is null").arg(QString::fromUtf8(target->metaObject()->property(instr.fetch.property).name())));
-
- stack.push(obj);
- }
- break;
-
- case QDeclarativeInstruction::PopQList:
- {
- qliststack.pop();
- }
- break;
-
- case QDeclarativeInstruction::Defer:
- {
- if (instr.defer.deferCount) {
- QObject *target = stack.top();
- QDeclarativeData *data =
- QDeclarativeData::get(target, true);
- comp->addref();
- data->deferredComponent = comp;
- data->deferredIdx = ii;
- ii += instr.defer.deferCount;
}
}
- break;
-
- case QDeclarativeInstruction::PopFetchedObject:
- {
- stack.pop();
- }
- break;
-
- case QDeclarativeInstruction::FetchValueType:
- {
- QObject *target = stack.top();
- if (instr.fetchValue.bindingSkipList != 0) {
- // Possibly need to clear bindings
- QDeclarativeData *targetData = QDeclarativeData::get(target);
- if (targetData) {
- QDeclarativeAbstractBinding *binding =
- QDeclarativePropertyPrivate::binding(target, instr.fetchValue.property, -1);
-
- if (binding && binding->bindingType() != QDeclarativeAbstractBinding::ValueTypeProxy) {
- QDeclarativePropertyPrivate::setBinding(target, instr.fetchValue.property, -1, 0);
- binding->destroy();
- } else if (binding) {
- QDeclarativeValueTypeProxyBinding *proxy =
- static_cast<QDeclarativeValueTypeProxyBinding *>(binding);
- proxy->removeBindings(instr.fetchValue.bindingSkipList);
- }
- }
- }
-
- QDeclarativeValueType *valueHandler = ep->valueTypes[instr.fetchValue.type];
- valueHandler->read(target, instr.fetchValue.property);
- stack.push(valueHandler);
- }
- break;
+ QDeclarativeValueType *valueHandler = ep->valueTypes[instr.type];
+ valueHandler->read(target, instr.property);
+ stack.push(valueHandler);
+ QML_END_INSTR(FetchValueType)
- case QDeclarativeInstruction::PopValueType:
- {
- QDeclarativeValueType *valueHandler =
- static_cast<QDeclarativeValueType *>(stack.pop());
- QObject *target = stack.top();
- valueHandler->write(target, instr.fetchValue.property,
- QDeclarativePropertyPrivate::BypassInterceptor);
- }
- break;
+ QML_BEGIN_INSTR(PopValueType)
+ QDeclarativeValueType *valueHandler =
+ static_cast<QDeclarativeValueType *>(stack.pop());
+ QObject *target = stack.top();
+ valueHandler->write(target, instr.property, QDeclarativePropertyPrivate::BypassInterceptor);
+ QML_END_INSTR(PopValueType)
default:
- qFatal("QDeclarativeCompiledData: Internal error - unknown instruction %d", instr.type);
+ qFatal("QDeclarativeCompiledData: Internal error - unknown instruction %d", genericInstr.type());
break;
}
}
@@ -1050,9 +958,72 @@ QDeclarativeCompiledData::TypeReference::createInstance(QDeclarativeContextData
return rv;
} else {
Q_ASSERT(component);
- return QDeclarativeComponentPrivate::begin(ctxt, 0, component, -1, -1, 0, errors, bindings);
+ return QDeclarativeComponentPrivate::begin(ctxt, 0, component, -1, 0, errors, bindings);
}
}
+QScriptValue QDeclarativeVME::run(QDeclarativeContextData *parentCtxt, QDeclarativeScriptData *script)
+{
+ if (script->m_loaded)
+ return script->m_value;
+
+ QDeclarativeEnginePrivate *enginePriv = QDeclarativeEnginePrivate::get(parentCtxt->engine);
+ QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(parentCtxt->engine);
+
+ bool shared = script->pragmas & QDeclarativeParser::Object::ScriptBlock::Shared;
+
+ // Create the script context if required
+ QDeclarativeContextData *ctxt = 0;
+ if (!shared) {
+ ctxt = new QDeclarativeContextData;
+ ctxt->isInternal = true;
+ ctxt->url = script->url;
+
+ // 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 {
+ ctxt->imports = parentCtxt->imports;
+ }
+
+ if (ctxt->imports) {
+ ctxt->imports->addref();
+ }
+
+ ctxt->setParent(parentCtxt, true);
+
+ for (int ii = 0; ii < script->scripts.count(); ++ii)
+ ctxt->importedScripts << run(ctxt, script->scripts.at(ii)->scriptData());
+ }
+
+ QScriptContext *scriptContext = QScriptDeclarativeClass::pushCleanContext(scriptEngine);
+ if (shared) {
+ scriptContext->pushScope(enginePriv->contextClass->newUrlContext(script->url.toString())); // XXX toString()?
+ } else {
+ scriptContext->pushScope(enginePriv->contextClass->newUrlContext(ctxt, 0, script->url.toString()));
+ }
+
+ scriptContext->pushScope(enginePriv->globalClass->staticGlobalObject());
+ QScriptValue scope = QScriptDeclarativeClass::newStaticScopeObject(scriptEngine);
+ scriptContext->pushScope(scope);
+
+ scriptEngine->evaluate(script->m_program);
+
+ if (scriptEngine->hasUncaughtException()) {
+ QDeclarativeError error;
+ QDeclarativeExpressionPrivate::exceptionToError(scriptEngine, error);
+ enginePriv->warning(error);
+ }
+
+ scriptEngine->popContext();
+
+ if (shared) {
+ script->m_loaded = true;
+ script->m_value = scope;
+ }
+
+ return scope;
+}
QT_END_NAMESPACE
diff --git a/src/declarative/qml/qdeclarativevme_p.h b/src/declarative/qml/qdeclarativevme_p.h
index 6b7b93f09e..b255e7fa55 100644
--- a/src/declarative/qml/qdeclarativevme_p.h
+++ b/src/declarative/qml/qdeclarativevme_p.h
@@ -62,7 +62,8 @@
QT_BEGIN_NAMESPACE
class QObject;
-class QDeclarativeInstruction;
+class QScriptValue;
+class QDeclarativeScriptData;
class QDeclarativeCompiledData;
class QDeclarativeCompiledData;
class QDeclarativeContextData;
@@ -101,8 +102,9 @@ public:
QDeclarativeVME();
QObject *run(QDeclarativeContextData *, QDeclarativeCompiledData *,
- int start = -1, int count = -1,
- const QBitField & = QBitField());
+ int start = -1, const QBitField & = QBitField());
+ QScriptValue run(QDeclarativeContextData *, QDeclarativeScriptData *);
+
void runDeferred(QObject *);
bool isError() const;
@@ -111,8 +113,7 @@ public:
private:
QObject *run(QDeclarativeVMEStack<QObject *> &,
QDeclarativeContextData *, QDeclarativeCompiledData *,
- int start, int count,
- const QBitField &);
+ int start, const QBitField &);
QList<QDeclarativeError> vmeErrors;
};
diff --git a/src/declarative/qml/qdeclarativevmemetaobject.cpp b/src/declarative/qml/qdeclarativevmemetaobject.cpp
index f63f264831..78519b2601 100644
--- a/src/declarative/qml/qdeclarativevmemetaobject.cpp
+++ b/src/declarative/qml/qdeclarativevmemetaobject.cpp
@@ -647,6 +647,7 @@ int QDeclarativeVMEMetaObject::metaCall(QMetaObject::Call c, int _id, void **a)
return -1; // We can't run the method
QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(ctxt->engine);
+ ep->referenceScarceResources(); // "hold" scarce resources in memory during evaluation.
QScriptValue function = method(id);
@@ -657,10 +658,19 @@ int QDeclarativeVMEMetaObject::metaCall(QMetaObject::Call c, int _id, void **a)
args << ep->scriptValueFromVariant(*(QVariant *)a[ii + 1]);
}
}
+
QScriptValue rv = function.call(ep->objectClass->newQObject(object), args);
+ if (ep->scriptEngine.hasUncaughtException()) {
+ QDeclarativeError error;
+ QDeclarativeExpressionPrivate::exceptionToError(&ep->scriptEngine, error);
+ if (error.isValid()) {
+ ep->warning(error);
+ }
+ }
if (a[0]) *reinterpret_cast<QVariant *>(a[0]) = ep->scriptValueToVariant(rv);
+ ep->dereferenceScarceResources(); // "release" scarce resources if top-level expression evaluation is complete.
return -1;
}
return -1;
diff --git a/src/declarative/qml/qdeclarativexmlhttprequest.cpp b/src/declarative/qml/qdeclarativexmlhttprequest.cpp
index 3bc9100a0e..83b7d170a4 100644
--- a/src/declarative/qml/qdeclarativexmlhttprequest.cpp
+++ b/src/declarative/qml/qdeclarativexmlhttprequest.cpp
@@ -101,6 +101,8 @@ QT_BEGIN_NAMESPACE
DEFINE_BOOL_CONFIG_OPTION(xhrDump, QML_XHR_DUMP);
+namespace {
+
class DocumentImpl;
class NodeImpl
{
@@ -323,6 +325,8 @@ public:
static QScriptValue load(QScriptEngine *engine, const QByteArray &data);
};
+}
+
QT_END_NAMESPACE
Q_DECLARE_METATYPE(Node)
@@ -1231,6 +1235,18 @@ void QDeclarativeXMLHttpRequest::downloadProgress(qint64 bytes)
}
}
+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 QDeclarativeXMLHttpRequest::error(QNetworkReply::NetworkError error)
{
Q_UNUSED(error)
@@ -1245,6 +1261,11 @@ void QDeclarativeXMLHttpRequest::error(QNetworkReply::NetworkError error)
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 ||
diff --git a/src/declarative/qml/qintrusivelist.cpp b/src/declarative/qml/qintrusivelist.cpp
new file mode 100644
index 0000000000..6c27af0777
--- /dev/null
+++ b/src/declarative/qml/qintrusivelist.cpp
@@ -0,0 +1,173 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $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 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/declarative/qml/qintrusivelist_p.h b/src/declarative/qml/qintrusivelist_p.h
new file mode 100644
index 0000000000..459d051d07
--- /dev/null
+++ b/src/declarative/qml/qintrusivelist_p.h
@@ -0,0 +1,254 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $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 void insert(N *n);
+ inline void remove(N *n);
+
+ 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>
+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>
+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/declarative/qml/qmetaobjectbuilder.cpp b/src/declarative/qml/qmetaobjectbuilder.cpp
index 4fe49ab559..f5e8369ebc 100644
--- a/src/declarative/qml/qmetaobjectbuilder.cpp
+++ b/src/declarative/qml/qmetaobjectbuilder.cpp
@@ -101,7 +101,7 @@ bool isVariantType(const char* type)
return qvariant_nameToType(type) != 0;
}
-// copied from qmetaobject.cpp
+// copied from qmetaobject_p.h
// do not touch without touching the moc as well
enum PropertyFlags {
Invalid = 0x00000000,
@@ -111,6 +111,8 @@ enum PropertyFlags {
EnumOrFlag = 0x00000008,
StdCppSet = 0x00000100,
// Override = 0x00000200,
+ Constant = 0x00000400,
+ Final = 0x00000800,
Designable = 0x00001000,
ResolveDesignable = 0x00002000,
Scriptable = 0x00004000,
@@ -618,6 +620,8 @@ QMetaPropertyBuilder QMetaObjectBuilder::addProperty(const QMetaProperty& protot
property.setUser(prototype.isUser());
property.setStdCppSet(prototype.hasStdCppSet());
property.setEnumOrFlag(prototype.isEnumType());
+ property.setConstant(prototype.isConstant());
+ property.setFinal(prototype.isFinal());
if (prototype.hasNotifySignal()) {
// Find an existing method for the notify signal, or add a new one.
QMetaMethod method = prototype.notifySignal();
@@ -2280,6 +2284,32 @@ bool QMetaPropertyBuilder::isEnumOrFlag() const
}
/*!
+ Returns true if the property is constant; otherwise returns false.
+ The default value is false.
+*/
+bool QMetaPropertyBuilder::isConstant() const
+{
+ QMetaPropertyBuilderPrivate *d = d_func();
+ if (d)
+ return d->flag(Constant);
+ else
+ return false;
+}
+
+/*!
+ Returns true if the property is final; otherwise returns false.
+ The default value is false.
+*/
+bool QMetaPropertyBuilder::isFinal() const
+{
+ QMetaPropertyBuilderPrivate *d = d_func();
+ if (d)
+ return d->flag(Final);
+ else
+ return false;
+}
+
+/*!
Sets this property to readable if \a value is true.
\sa isReadable(), setWritable()
@@ -2403,6 +2433,31 @@ void QMetaPropertyBuilder::setEnumOrFlag(bool value)
}
/*!
+ Sets the \c CONSTANT flag on this property to \a value.
+
+ \sa isConstant()
+*/
+void QMetaPropertyBuilder::setConstant(bool value)
+{
+ QMetaPropertyBuilderPrivate *d = d_func();
+ if (d)
+ d->setFlag(Constant, value);
+}
+
+/*!
+ Sets the \c FINAL flag on this property to \a value.
+
+ \sa isFinal()
+*/
+void QMetaPropertyBuilder::setFinal(bool value)
+{
+ QMetaPropertyBuilderPrivate *d = d_func();
+ if (d)
+ d->setFlag(Final, value);
+}
+
+
+/*!
\class QMetaEnumBuilder
\internal
\brief The QMetaEnumBuilder class enables modifications to an enumerator definition on a meta object builder.
diff --git a/src/declarative/qml/qmetaobjectbuilder_p.h b/src/declarative/qml/qmetaobjectbuilder_p.h
index f06a6633c9..a80ba904b6 100644
--- a/src/declarative/qml/qmetaobjectbuilder_p.h
+++ b/src/declarative/qml/qmetaobjectbuilder_p.h
@@ -258,6 +258,8 @@ public:
bool isUser() const;
bool hasStdCppSet() const;
bool isEnumOrFlag() const;
+ bool isConstant() const;
+ bool isFinal() const;
void setReadable(bool value);
void setWritable(bool value);
@@ -269,6 +271,8 @@ public:
void setUser(bool value);
void setStdCppSet(bool value);
void setEnumOrFlag(bool value);
+ void setConstant(bool value);
+ void setFinal(bool value);
private:
const QMetaObjectBuilder *_mobj;
diff --git a/src/declarative/qml/qml.pri b/src/declarative/qml/qml.pri
index bf9e54a986..62c1f97d60 100644
--- a/src/declarative/qml/qml.pri
+++ b/src/declarative/qml/qml.pri
@@ -18,7 +18,6 @@ SOURCES += \
$$PWD/qdeclarativecompiler.cpp \
$$PWD/qdeclarativecompileddata.cpp \
$$PWD/qdeclarativeboundsignal.cpp \
- $$PWD/qdeclarativedom.cpp \
$$PWD/qdeclarativerefcount.cpp \
$$PWD/qdeclarativemetatype.cpp \
$$PWD/qdeclarativestringconverters.cpp \
@@ -30,7 +29,6 @@ SOURCES += \
$$PWD/qdeclarativeenginedebug.cpp \
$$PWD/qdeclarativerewrite.cpp \
$$PWD/qdeclarativevaluetype.cpp \
- $$PWD/qdeclarativecompiledbindings.cpp \
$$PWD/qdeclarativefastproperties.cpp \
$$PWD/qdeclarativexmlhttprequest.cpp \
$$PWD/qdeclarativesqldatabase.cpp \
@@ -44,6 +42,7 @@ SOURCES += \
$$PWD/qdeclarativetypenamecache.cpp \
$$PWD/qdeclarativescriptstring.cpp \
$$PWD/qdeclarativeobjectscriptclass.cpp \
+ $$PWD/qdeclarativescarceresourcescriptclass.cpp \
$$PWD/qdeclarativecontextscriptclass.cpp \
$$PWD/qdeclarativeglobalscriptclass.cpp \
$$PWD/qdeclarativevaluetypescriptclass.cpp \
@@ -56,7 +55,8 @@ SOURCES += \
$$PWD/qdeclarativeextensionplugin.cpp \
$$PWD/qdeclarativeimport.cpp \
$$PWD/qdeclarativelist.cpp \
- $$PWD/qperformancetimer.cpp
+ $$PWD/qperformancetimer.cpp \
+ $$PWD/qintrusivelist.cpp \
HEADERS += \
$$PWD/qdeclarativeparser_p.h \
@@ -81,8 +81,6 @@ HEADERS += \
$$PWD/qdeclarativeengine_p.h \
$$PWD/qdeclarativeexpression_p.h \
$$PWD/qdeclarativeprivate.h \
- $$PWD/qdeclarativedom_p.h \
- $$PWD/qdeclarativedom_p_p.h \
$$PWD/qdeclarativerefcount_p.h \
$$PWD/qdeclarativemetatype_p.h \
$$PWD/qdeclarativeengine.h \
@@ -104,7 +102,6 @@ HEADERS += \
$$PWD/qpodvector_p.h \
$$PWD/qbitfield_p.h \
$$PWD/qdeclarativevaluetype_p.h \
- $$PWD/qdeclarativecompiledbindings_p.h \
$$PWD/qdeclarativefastproperties_p.h \
$$PWD/qdeclarativexmlhttprequest_p.h \
$$PWD/qdeclarativesqldatabase_p.h \
@@ -118,6 +115,7 @@ HEADERS += \
$$PWD/qdeclarativetypenamecache_p.h \
$$PWD/qdeclarativescriptstring.h \
$$PWD/qdeclarativeobjectscriptclass_p.h \
+ $$PWD/qdeclarativescarceresourcescriptclass_p.h \
$$PWD/qdeclarativecontextscriptclass_p.h \
$$PWD/qdeclarativeglobalscriptclass_p.h \
$$PWD/qdeclarativevaluetypescriptclass_p.h \
@@ -131,11 +129,13 @@ HEADERS += \
$$PWD/qdeclarativeextensioninterface.h \
$$PWD/qdeclarativeimport_p.h \
$$PWD/qdeclarativeextensionplugin.h \
- $$PWD/qperformancetimer_p.h
+ $$PWD/qperformancetimer_p.h \
+ $$PWD/qintrusivelist_p.h \
QT += sql
include(parser/parser.pri)
include(rewriter/rewriter.pri)
+include(v4/v4.pri)
# mirrors logic in corelib/kernel/kernel.pri
unix:!symbian: contains(QT_CONFIG, clock-gettime):include($$QT_SOURCE_TREE/config.tests/unix/clock-gettime/clock-gettime.pri)
diff --git a/src/declarative/qml/v4/qdeclarativev4bindings.cpp b/src/declarative/qml/v4/qdeclarativev4bindings.cpp
new file mode 100644
index 0000000000..5ef293de89
--- /dev/null
+++ b/src/declarative/qml/v4/qdeclarativev4bindings.cpp
@@ -0,0 +1,1530 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// #define REGISTER_CLEANUP_DEBUG
+
+#include "private/qdeclarativev4bindings_p.h"
+#include "private/qdeclarativev4program_p.h"
+#include "private/qdeclarativev4compiler_p.h"
+
+#include <private/qdeclarativefastproperties_p.h>
+#include <private/qdeclarativedebugtrace_p.h>
+#include <private/qdeclarativeanchors_p_p.h> // For AnchorLine
+#include <private/qsganchors_p_p.h> // For AnchorLine
+
+#include <QtDeclarative/qdeclarativeinfo.h>
+#include <QtCore/qnumeric.h>
+#include <QtCore/qmath.h>
+#include <math.h> // ::fmod
+
+QT_BEGIN_NAMESPACE
+
+using namespace QDeclarativeJS;
+
+namespace {
+struct Register {
+ typedef QDeclarativeRegisterType Type;
+
+ void setUndefined() { dataType = UndefinedType; }
+ void setNaN() { setqreal(qSNaN()); }
+ bool isUndefined() const { return dataType == UndefinedType; }
+
+ void setQObject(QObject *o) { *((QObject **)data) = o; dataType = QObjectStarType; }
+ QObject *getQObject() const { return *((QObject **)data); }
+
+ void setqreal(qreal v) { *((qreal *)data) = v; dataType = QRealType; }
+ qreal getqreal() const { return *((qreal *)data); }
+ qreal &getqrealref() const { return *((qreal *)data); }
+
+ void setint(int v) { *((int *)data) = v; dataType = IntType; }
+ int getint() const { return *((int *)data); }
+ int &getintref() const { return *((int *)data); }
+
+ void setbool(bool v) { *((bool *)data) = v; dataType = BoolType; }
+ bool getbool() const { return *((bool *)data); }
+ bool &getboolref() const { return *((bool *)data); }
+
+ 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; }
+
+ // int type; // Optional type
+
+ Type dataType; // Type of data
+ void *data[2]; // Object stored here
+
+ 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
+
+class QDeclarativeV4BindingsPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QDeclarativeV4Bindings)
+
+public:
+ QDeclarativeV4BindingsPrivate();
+ virtual ~QDeclarativeV4BindingsPrivate();
+
+ struct Binding : public QDeclarativeAbstractBinding, public QDeclarativeDelayedError {
+ Binding() : enabled(false), updating(0), property(0),
+ scope(0), target(0), executedBlocks(0), parent(0) {}
+
+ // Inherited from QDeclarativeAbstractBinding
+ virtual void setEnabled(bool, QDeclarativePropertyPrivate::WriteFlags flags);
+ virtual void update(QDeclarativePropertyPrivate::WriteFlags flags);
+ virtual void destroy();
+
+ int index:30;
+ bool enabled:1;
+ bool updating:1;
+ int property;
+ QObject *scope;
+ QObject *target;
+ quint32 executedBlocks;
+
+ QDeclarativeV4BindingsPrivate *parent;
+ };
+
+ typedef QDeclarativeNotifierEndpoint Subscription;
+ Subscription *subscriptions;
+ QScriptDeclarativeClass::PersistentIdentifier *identifiers;
+
+ void run(Binding *, QDeclarativePropertyPrivate::WriteFlags flags);
+
+ QDeclarativeV4Program *program;
+ Binding *bindings;
+
+ static int methodCount;
+
+ void init();
+ void run(int instr, quint32 &executedBlocks, QDeclarativeContextData *context,
+ QDeclarativeDelayedError *error, QObject *scope, QObject *output,
+ QDeclarativePropertyPrivate::WriteFlags storeFlags
+#ifdef QML_THREADED_INTERPRETER
+ , void ***decode_instr = 0
+#endif
+ );
+
+
+ inline void unsubscribe(int subIndex);
+ inline void subscribeId(QDeclarativeContextData *p, int idIndex, int subIndex);
+ inline void subscribe(QObject *o, int notifyIndex, int subIndex);
+
+ inline static qint32 toInt32(qsreal n);
+ static const qsreal D32;
+ static quint32 toUint32(qsreal n);
+};
+
+QDeclarativeV4BindingsPrivate::QDeclarativeV4BindingsPrivate()
+: subscriptions(0), identifiers(0), program(0), bindings(0)
+{
+}
+
+QDeclarativeV4BindingsPrivate::~QDeclarativeV4BindingsPrivate()
+{
+ delete [] subscriptions; subscriptions = 0;
+ delete [] identifiers; identifiers = 0;
+}
+
+int QDeclarativeV4BindingsPrivate::methodCount = -1;
+
+QDeclarativeV4Bindings::QDeclarativeV4Bindings(const char *program, QDeclarativeContextData *context)
+: QObject(*(new QDeclarativeV4BindingsPrivate))
+{
+ Q_D(QDeclarativeV4Bindings);
+
+ if (d->methodCount == -1)
+ d->methodCount = QDeclarativeV4Bindings::staticMetaObject.methodCount();
+
+ d->program = (QDeclarativeV4Program *)program;
+
+ if (program) {
+ d->init();
+
+ QDeclarativeAbstractExpression::setContext(context);
+ }
+}
+
+QDeclarativeV4Bindings::~QDeclarativeV4Bindings()
+{
+ Q_D(QDeclarativeV4Bindings);
+
+ delete [] d->bindings;
+}
+
+QDeclarativeAbstractBinding *QDeclarativeV4Bindings::configBinding(int index, QObject *target,
+ QObject *scope, int property)
+{
+ Q_D(QDeclarativeV4Bindings);
+
+ QDeclarativeV4BindingsPrivate::Binding *rv = d->bindings + index;
+
+ rv->index = index;
+ rv->property = property;
+ rv->target = target;
+ rv->scope = scope;
+ rv->parent = d;
+
+ addref(); // This is decremented in Binding::destroy()
+
+ return rv;
+}
+
+void QDeclarativeV4BindingsPrivate::Binding::setEnabled(bool e, QDeclarativePropertyPrivate::WriteFlags flags)
+{
+ if (enabled != e) {
+ enabled = e;
+
+ if (e) update(flags);
+ }
+}
+
+void QDeclarativeV4BindingsPrivate::Binding::update(QDeclarativePropertyPrivate::WriteFlags flags)
+{
+ QDeclarativeDebugTrace::startRange(QDeclarativeDebugTrace::Binding);
+ parent->run(this, flags);
+ QDeclarativeDebugTrace::endRange(QDeclarativeDebugTrace::Binding);
+}
+
+void QDeclarativeV4BindingsPrivate::Binding::destroy()
+{
+ enabled = false;
+ removeFromObject();
+ clear();
+ parent->q_func()->release();
+}
+
+int QDeclarativeV4Bindings::qt_metacall(QMetaObject::Call c, int id, void **)
+{
+ Q_D(QDeclarativeV4Bindings);
+
+ if (c == QMetaObject::InvokeMetaMethod && id >= d->methodCount) {
+ id -= d->methodCount;
+
+ QDeclarativeV4Program::BindingReferenceList *list = d->program->signalTable(id);
+
+ for (quint32 ii = 0; ii < list->count; ++ii) {
+ QDeclarativeV4Program::BindingReference *bindingRef = list->bindings + ii;
+
+ QDeclarativeV4BindingsPrivate::Binding *binding = d->bindings + bindingRef->binding;
+ if (binding->executedBlocks & bindingRef->blockMask)
+ d->run(binding, QDeclarativePropertyPrivate::DontRemoveBinding);
+ }
+ }
+ return -1;
+}
+
+void QDeclarativeV4BindingsPrivate::run(Binding *binding, QDeclarativePropertyPrivate::WriteFlags flags)
+{
+ Q_Q(QDeclarativeV4Bindings);
+
+ if (!binding->enabled)
+ return;
+
+ QDeclarativeContextData *context = q->QDeclarativeAbstractExpression::context();
+ if (!context || !context->isValid())
+ return;
+
+ if (binding->updating) {
+ QString name;
+ if (binding->property & 0xFFFF0000) {
+ QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(context->engine);
+
+ QDeclarativeValueType *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) << QCoreApplication::translate("QDeclarativeV4Bindings", "Binding loop detected for property \"%1\"").arg(name);
+ return;
+ }
+
+ binding->updating = true;
+ if (binding->property & 0xFFFF0000) {
+ QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(context->engine);
+
+ QDeclarativeValueType *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 QDeclarativeV4BindingsPrivate::unsubscribe(int subIndex)
+{
+ QDeclarativeV4BindingsPrivate::Subscription *sub = (subscriptions + subIndex);
+ sub->disconnect();
+}
+
+void QDeclarativeV4BindingsPrivate::subscribeId(QDeclarativeContextData *p, int idIndex, int subIndex)
+{
+ Q_Q(QDeclarativeV4Bindings);
+
+ unsubscribe(subIndex);
+
+ if (p->idValues[idIndex]) {
+ QDeclarativeV4BindingsPrivate::Subscription *sub = (subscriptions + subIndex);
+ sub->target = q;
+ sub->targetMethod = methodCount + subIndex;
+ sub->connect(&p->idValues[idIndex].bindings);
+ }
+}
+
+void QDeclarativeV4BindingsPrivate::subscribe(QObject *o, int notifyIndex, int subIndex)
+{
+ Q_Q(QDeclarativeV4Bindings);
+
+ QDeclarativeV4BindingsPrivate::Subscription *sub = (subscriptions + subIndex);
+ sub->target = q;
+ sub->targetMethod = methodCount + 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, QDeclarativeContextData *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) {
+ base = QUrl(QString::fromUtf8(var->toByteArray()));
+ } else if (vt == QVariant::String) {
+ base = QUrl(var->toString());
+ } else {
+ if (ok) *ok = false;
+ return QUrl();
+ }
+ } else if (type == QMetaType::QString) {
+ base = QUrl(*reg->getstringptr());
+ } else {
+ if (ok) *ok = false;
+ return QUrl();
+ }
+
+ if (!base.isEmpty() && base.isRelative())
+ return context->url.resolved(base);
+ else
+ return base;
+}
+
+static QObject *variantToQObject(const QVariant &value, bool *ok)
+{
+ if (ok) *ok = true;
+
+ if (value.userType() == QMetaType::QObjectStar) {
+ return qvariant_cast<QObject*>(value);
+ } else {
+ if (ok) *ok = false;
+ return 0;
+ }
+}
+
+void QDeclarativeV4BindingsPrivate::init()
+{
+ if (program->subscriptions)
+ subscriptions = new QDeclarativeV4BindingsPrivate::Subscription[program->subscriptions];
+ if (program->identifiers)
+ identifiers = new QScriptDeclarativeClass::PersistentIdentifier[program->identifiers];
+
+ bindings = new QDeclarativeV4BindingsPrivate::Binding[program->bindings];
+}
+
+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 == qMetaTypeId<QDeclarativeAnchorLine>()) {
+ QDeclarativeAnchorLine la = qvariant_cast<QDeclarativeAnchorLine>(qtscript);
+ QDeclarativeAnchorLine ra = qvariant_cast<QDeclarativeAnchorLine>(v4);
+
+ return la == ra;
+ } else if (type == qMetaTypeId<QSGAnchorLine>()) {
+ QSGAnchorLine la = qvariant_cast<QSGAnchorLine>(qtscript);
+ QSGAnchorLine ra = qvariant_cast<QSGAnchorLine>(v4);
+
+ return la == ra;
+ } 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,
+ QDeclarativeContextData *context, QObject *scope,
+ const Register &result, int resultType)
+{
+ QDeclarativeExpression expression(context->asQDeclarativeContext(), 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 == qMetaTypeId<QDeclarativeAnchorLine>()) {
+ v4value = qVariantFromValue<QDeclarativeAnchorLine>(*(QDeclarativeAnchorLine *)result.typeDataPtr());
+ } else if (resultType == qMetaTypeId<QSGAnchorLine>()) {
+ v4value = qVariantFromValue<QSGAnchorLine>(*(QSGAnchorLine *)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() << "QDeclarativeV4: 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,
+ QDeclarativeContextData *context, QObject *scope)
+{
+ QDeclarativeExpression expression(context->asQDeclarativeContext(), scope, binding);
+ bool isUndefined = false;
+ QVariant value = expression.evaluate(&isUndefined);
+
+ if (!expression.hasError()) {
+ QByteArray qtscriptResult = testResultToString(value, isUndefined);
+ qWarning().nospace() << "QDeclarativeV4: 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, QDeclarativeDelayedError *error,
+ QDeclarativeV4Program *program, QDeclarativeContextData *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(QDeclarativeEnginePrivate::get(context->engine)))
+ QDeclarativeEnginePrivate::warning(context->engine, error->error);
+}
+
+const qsreal QDeclarativeV4BindingsPrivate::D32 = 4294967296.0;
+
+qint32 QDeclarativeV4BindingsPrivate::toInt32(qsreal n)
+{
+ if (qIsNaN(n) || qIsInf(n) || (n == 0))
+ return 0;
+
+ double sign = (n < 0) ? -1.0 : 1.0;
+ qsreal 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 QDeclarativeV4BindingsPrivate::toUint32(qsreal n)
+{
+ if (qIsNaN(n) || qIsInf(n) || (n == 0))
+ return 0;
+
+ double sign = (n < 0) ? -1.0 : 1.0;
+ qsreal 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 **QDeclarativeV4Bindings::getDecodeInstrTable()
+{
+ static void **decode_instr;
+ if (!decode_instr) {
+ QDeclarativeV4Bindings dummy(0, 0);
+ quint32 executedBlocks = 0;
+ dummy.d_func()->run(0, executedBlocks, 0, 0, 0, 0, QDeclarativePropertyPrivate::BypassInterceptor, &decode_instr);
+ }
+ return decode_instr;
+}
+#endif
+
+void QDeclarativeV4BindingsPrivate::run(int instrIndex, quint32 &executedBlocks,
+ QDeclarativeContextData *context, QDeclarativeDelayedError *error,
+ QObject *scope, QObject *output, QDeclarativePropertyPrivate::WriteFlags storeFlags
+#ifdef QML_THREADED_INTERPRETER
+ ,void ***table
+#endif
+ )
+{
+ Q_Q(QDeclarativeV4Bindings);
+
+#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;
+
+ QDeclarativeEnginePrivate *engine = QDeclarativeEnginePrivate::get(context->engine);
+ const char *code = program->instructions();
+ code += instrIndex * QML_V4_INSTR_SIZE(Jump, jump);
+ const Instr *instr = (const Instr *) 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;
+ QDeclarativeV4BindingsPrivate::Subscription *sub = 0;
+ if (subIdx != -1) {
+ sub = (subscriptions + subIdx);
+ sub->target = q;
+ sub->targetMethod = methodCount + subIdx;
+ }
+ reg.init((Register::Type)instr->fetchAndSubscribe.valueType);
+ if (instr->fetchAndSubscribe.valueType >= FirstCleanupType)
+ MARK_REGISTER(instr->fetchAndSubscribe.reg);
+ QDeclarativeV4Compiler::fastPropertyAccessor()->accessor(instr->fetchAndSubscribe.function)(object, reg.typeDataPtr(), sub);
+ }
+ }
+ 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.
+ QScriptValue 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.
+ QScriptValue tmp(*src.getstringptr());
+ if (instr->unaryop.src == instr->unaryop.output) {
+ output.cleanupString();
+ MARK_CLEAN_REGISTER(instr->unaryop.output);
+ }
+ output.setint(tmp.toInt32());
+ }
+ }
+ 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.
+ QScriptValue 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(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 qsreal 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(Real, real_value)
+ registers[instr->real_value.reg].setqreal(instr->real_value.value);
+ QML_V4_END_INSTR(Real, real_value)
+
+ QML_V4_BEGIN_INSTR(Int, int_value)
+ registers[instr->int_value.reg].setint(instr->int_value.value);
+ QML_V4_END_INSTR(Int, int_value)
+
+ QML_V4_BEGIN_INSTR(Bool, bool_value)
+ registers[instr->bool_value.reg].setbool(instr->bool_value.value);
+ QML_V4_END_INSTR(Bool, bool_value)
+
+ QML_V4_BEGIN_INSTR(String, 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(String, 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)
+
+ 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("QDeclarativeV4: 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/declarative/qml/v4/qdeclarativev4bindings_p.h b/src/declarative/qml/v4/qdeclarativev4bindings_p.h
new file mode 100644
index 0000000000..9f225b65b6
--- /dev/null
+++ b/src/declarative/qml/v4/qdeclarativev4bindings_p.h
@@ -0,0 +1,92 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVEV4BINDINGS_P_H
+#define QDECLARATIVEV4BINDINGS_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/qdeclarativeexpression_p.h"
+#include "private/qdeclarativebinding_p.h"
+#include "private/qdeclarativev4instruction_p.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativeV4BindingsPrivate;
+class QDeclarativeV4Bindings : public QObject,
+ public QDeclarativeAbstractExpression,
+ public QDeclarativeRefCount
+{
+public:
+ QDeclarativeV4Bindings(const char *program, QDeclarativeContextData *context);
+ virtual ~QDeclarativeV4Bindings();
+
+ QDeclarativeAbstractBinding *configBinding(int index, QObject *target, QObject *scope, int property);
+
+#ifdef QML_THREADED_INTERPRETER
+ static void **getDecodeInstrTable();
+#endif
+
+protected:
+ int qt_metacall(QMetaObject::Call, int, void **);
+
+private:
+ Q_DISABLE_COPY(QDeclarativeV4Bindings)
+ Q_DECLARE_PRIVATE(QDeclarativeV4Bindings)
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QDECLARATIVEV4BINDINGS_P_H
+
diff --git a/src/declarative/qml/v4/qdeclarativev4compiler.cpp b/src/declarative/qml/v4/qdeclarativev4compiler.cpp
new file mode 100644
index 0000000000..e67a3821d7
--- /dev/null
+++ b/src/declarative/qml/v4/qdeclarativev4compiler.cpp
@@ -0,0 +1,1340 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qdeclarativev4compiler_p.h"
+#include "qdeclarativev4compiler_p_p.h"
+#include "qdeclarativev4program_p.h"
+#include "qdeclarativev4ir_p.h"
+#include "qdeclarativev4irbuilder_p.h"
+
+#include <private/qdeclarativejsast_p.h>
+#include <private/qdeclarativefastproperties_p.h>
+#include <private/qdeclarativejsengine_p.h>
+#include <private/qdeclarativeanchors_p_p.h> // For AnchorLine
+#include <private/qsganchors_p_p.h> // For AnchorLine
+
+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)
+
+Q_GLOBAL_STATIC(QDeclarativeFastProperties, fastProperties)
+
+static bool qmlBindingsTest = false;
+
+using namespace QDeclarativeJS;
+QDeclarativeV4CompilerPrivate::QDeclarativeV4CompilerPrivate()
+: _function(0) , _block(0) , _discarded(false)
+{
+}
+
+//
+// tracing
+//
+void QDeclarativeV4CompilerPrivate::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; 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) {
+ block->i(new IR::Jump(cj->iffalse));
+ }
+ } else if (IR::Jump *j = terminator->asJump()) {
+ if (j->target == next) {
+ delete block->statements.back();
+ block->statements.resize(block->statements.size() - 1);
+ }
+ }
+ }
+
+ block->offset = bytecode.size();
+
+ if (bytecode.isEmpty()) {
+ if (qmlBindingsTest || bindingsDump()) {
+ Instr id;
+ id.common.type = Instr::BindingId;
+ id.id.column = column;
+ id.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 test;
+ test.common.type = Instr::EnableV4Test;
+ test.string_value.reg = 0;
+ test.string_value.offset = offset;
+ test.string_value.length = str.length();
+ gen(test);
+ }
+ }
+
+ bool usic = false;
+ int patchesCount = patches.count();
+ qSwap(usedSubscriptionIdsChanged, usic);
+
+ int blockopIndex = bytecode.size();
+ Instr blockop;
+ blockop.block(currentBlockMask);
+ gen(blockop);
+
+ foreach (IR::Stmt *s, block->statements)
+ s->accept(this);
+
+ qSwap(usedSubscriptionIdsChanged, usic);
+
+ if (usic) {
+ if (currentBlockMask == 0x80000000) {
+ discard();
+ return;
+ }
+ currentBlockMask <<= 1;
+ } else {
+ 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
+
+
+ // back patching
+ foreach (const Patch &patch, patches) {
+ Instr &instr = bytecode[patch.offset];
+ instr.branchop.offset = patch.block->offset - patch.offset - instr.size();
+ }
+
+ patches.clear();
+}
+
+void QDeclarativeV4CompilerPrivate::trace(QVector<IR::BasicBlock *> *blocks)
+{
+ QList<IR::BasicBlock *> todo = QList<IR::BasicBlock *>::fromVector(_function->basicBlocks);
+ while (! todo.isEmpty()) {
+ IR::BasicBlock *block = todo.takeFirst();
+
+ 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 QDeclarativeV4CompilerPrivate::traceExpression(IR::Expr *e, quint8 r)
+{
+ if (!e) {
+ discard();
+ } else {
+ qSwap(currentReg, r);
+ e->accept(this);
+ qSwap(currentReg, r);
+ }
+}
+
+//
+// expressions
+//
+void QDeclarativeV4CompilerPrivate::visitConst(IR::Const *e)
+{
+ Instr i;
+ switch (e->type) {
+ case IR::BoolType:
+ i.move_reg_bool(currentReg, e->value);
+ gen(i);
+ break;
+
+ case IR::IntType:
+ i.move_reg_int(currentReg, e->value);
+ gen(i);
+ break;
+
+ case IR::RealType:
+ i.move_reg_qreal(currentReg, e->value);
+ gen(i);
+ break;
+
+ default:
+ if (qmlVerboseCompiler())
+ qWarning() << Q_FUNC_INFO << "unexpected type";
+ discard();
+ }
+}
+
+void QDeclarativeV4CompilerPrivate::visitString(IR::String *e)
+{
+ registerLiteralString(currentReg, e->value);
+}
+
+void QDeclarativeV4CompilerPrivate::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 instr;
+ instr.load_root(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 instr;
+ instr.load_scope(currentReg);
+ gen(instr);
+
+ _subscribeName << contextName();
+
+ } else if (e->storage == IR::Name::IdStorage) {
+
+ Instr instr;
+ instr.load_id(currentReg, e->index);
+ gen(instr);
+
+ _subscribeName << QLatin1String("$$$ID_") + e->id;
+
+ if (blockNeedsSubscription(_subscribeName)) {
+ Instr sub;
+ sub.subscribeId(currentReg, subscriptionIndex(_subscribeName), instr.load.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 attached;
+ attached.common.type = Instr::LoadAttached;
+ attached.attached.output = currentReg;
+ attached.attached.reg = currentReg;
+ attached.attached.exceptionId = exceptionId(e->line, e->column);
+ Q_ASSERT(e->declarativeType->attachedPropertiesId() != -1);
+ attached.attached.id = e->declarativeType->attachedPropertiesId();
+ gen(attached);
+ } break;
+
+ case IR::Name::Property: {
+ _subscribeName << e->id;
+
+ QMetaProperty prop = e->meta->property(e->index);
+ int fastFetchIndex = fastProperties()->accessorIndexForProperty(e->meta, e->index);
+
+ const int propTy = prop.userType();
+ QDeclarativeRegisterType 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;
+
+ default:
+ if (propTy == qMetaTypeId<QDeclarativeAnchorLine>()) {
+ regType = PODValueType;
+ } else if (propTy == qMetaTypeId<QSGAnchorLine>()) {
+ regType = PODValueType;
+ } else if (QDeclarativeMetaType::isQObject(propTy)) {
+ regType = QObjectStarType;
+ } else {
+ if (qmlVerboseCompiler())
+ qWarning() << "Discard unsupported property type:" << QMetaType::typeName(propTy);
+ discard(); // Unsupported type
+ return;
+ }
+
+ break;
+ } // switch
+
+ Instr fetch;
+
+ if (fastFetchIndex != -1) {
+ fetch.common.type = Instr::FetchAndSubscribe;
+ fetch.fetchAndSubscribe.reg = currentReg;
+ fetch.fetchAndSubscribe.function = fastFetchIndex;
+ fetch.fetchAndSubscribe.subscription = subscriptionIndex(_subscribeName);
+ fetch.fetchAndSubscribe.exceptionId = exceptionId(e->line, e->column);
+ fetch.fetchAndSubscribe.valueType = regType;
+ } else {
+ if (blockNeedsSubscription(_subscribeName) && prop.hasNotifySignal() && prop.notifySignalIndex() != -1) {
+ Instr sub;
+ sub.subscribe(currentReg, subscriptionIndex(_subscribeName), prop.notifySignalIndex());
+ gen(sub);
+ }
+
+ fetch.common.type = Instr::Fetch;
+ fetch.fetch.reg = currentReg;
+ fetch.fetch.index = e->index;
+ fetch.fetch.exceptionId = exceptionId(e->line, e->column);
+ fetch.fetch.valueType = regType;
+ }
+
+ gen(fetch);
+
+ } break;
+ } // switch
+}
+
+void QDeclarativeV4CompilerPrivate::visitTemp(IR::Temp *e)
+{
+ if (currentReg != e->index) {
+ Instr i;
+ i.move_reg_reg(currentReg, e->index);
+ gen(i);
+ }
+}
+
+void QDeclarativeV4CompilerPrivate::visitUnop(IR::Unop *e)
+{
+ Instr i;
+
+ 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) {
+ i.move_reg_reg(currentReg, src);
+ gen(i);
+ }
+ break;
+
+ case IR::OpNot:
+ convertToBool(e->expr, src);
+ i.unary_not(currentReg, src);
+ gen(i);
+ break;
+
+ case IR::OpUMinus:
+ if (e->expr->type == IR::RealType) {
+ i.uminus_real(currentReg, src);
+ gen(i);
+ } else if (e->expr->type == IR::IntType) {
+ convertToReal(e->expr, currentReg);
+ i.uminus_real(currentReg, src);
+ gen(i);
+ } else {
+ discard();
+ }
+ break;
+
+ case IR::OpUPlus:
+ if (e->expr->type == IR::RealType) {
+ i.uplus_real(currentReg, src);
+ gen(i);
+ } else if (e->expr->type == IR::IntType) {
+ convertToReal(e->expr, currentReg);
+ i.uplus_real(currentReg, src);
+ gen(i);
+ } else {
+ discard();
+ }
+ break;
+
+ case IR::OpCompl:
+ i.ucompl_real(currentReg, src);
+ gen(i);
+ 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 QDeclarativeV4CompilerPrivate::convertToReal(IR::Expr *expr, int reg)
+{
+ if (expr->type == IR::RealType)
+ return;
+
+ Instr conv;
+ conv.unaryop.output = reg;
+ conv.unaryop.src = reg;
+
+ switch (expr->type) {
+ case IR::BoolType:
+ conv.common.type = Instr::ConvertBoolToReal;
+ gen(conv);
+ break;
+
+ case IR::IntType:
+ conv.common.type = Instr::ConvertIntToReal;
+ gen(conv);
+ break;
+
+ case IR::RealType:
+ // nothing to do
+ return;
+
+ default:
+ discard();
+ break;
+ } // switch
+}
+
+void QDeclarativeV4CompilerPrivate::convertToInt(IR::Expr *expr, int reg)
+{
+ if (expr->type == IR::IntType)
+ return;
+
+ Instr conv;
+ conv.unaryop.output = reg;
+ conv.unaryop.src = reg;
+
+ switch (expr->type) {
+ case IR::BoolType:
+ conv.common.type = Instr::ConvertBoolToInt;
+ gen(conv);
+ break;
+
+ case IR::IntType:
+ // nothing to do
+ return;
+
+ case IR::RealType:
+ conv.common.type = Instr::ConvertRealToInt;
+ gen(conv);
+ break;
+
+ default:
+ discard();
+ break;
+ } // switch
+}
+
+void QDeclarativeV4CompilerPrivate::convertToBool(IR::Expr *expr, int reg)
+{
+ if (expr->type == IR::BoolType)
+ return;
+
+ Instr conv;
+ conv.unaryop.output = reg;
+ conv.unaryop.src = reg;
+
+ switch (expr->type) {
+ case IR::BoolType:
+ // nothing to do
+ break;
+
+ case IR::IntType:
+ conv.common.type = Instr::ConvertIntToBool;
+ gen(conv);
+ break;
+
+ case IR::RealType:
+ conv.common.type = Instr::ConvertRealToBool;
+ gen(conv);
+ return;
+
+ case IR::StringType:
+ conv.common.type = Instr::ConvertStringToBool;
+ gen(conv);
+ return;
+
+ default:
+ discard();
+ break;
+ } // switch
+}
+
+quint8 QDeclarativeV4CompilerPrivate::instructionOpcode(IR::Binop *e)
+{
+ switch (e->op) {
+ case IR::OpInvalid:
+ return Instr::Noop;
+
+ case IR::OpIfTrue:
+ case IR::OpNot:
+ case IR::OpUMinus:
+ case IR::OpUPlus:
+ case IR::OpCompl:
+ return Instr::Noop;
+
+ case IR::OpBitAnd:
+ return Instr::BitAndInt;
+
+ case IR::OpBitOr:
+ return Instr::BitOrInt;
+
+ case IR::OpBitXor:
+ return Instr::BitXorInt;
+
+ case IR::OpAdd:
+ if (e->type == IR::StringType)
+ return Instr::AddString;
+ return Instr::AddReal;
+
+ case IR::OpSub:
+ return Instr::SubReal;
+
+ case IR::OpMul:
+ return Instr::MulReal;
+
+ case IR::OpDiv:
+ return Instr::DivReal;
+
+ case IR::OpMod:
+ return Instr::ModReal;
+
+ case IR::OpLShift:
+ return Instr::LShiftInt;
+
+ case IR::OpRShift:
+ return Instr::RShiftInt;
+
+ case IR::OpURShift:
+ return Instr::URShiftInt;
+
+ case IR::OpGt:
+ if (e->left->type == IR::StringType)
+ return Instr::GtString;
+ return Instr::GtReal;
+
+ case IR::OpLt:
+ if (e->left->type == IR::StringType)
+ return Instr::LtString;
+ return Instr::LtReal;
+
+ case IR::OpGe:
+ if (e->left->type == IR::StringType)
+ return Instr::GeString;
+ return Instr::GeReal;
+
+ case IR::OpLe:
+ if (e->left->type == IR::StringType)
+ return Instr::LeString;
+ return Instr::LeReal;
+
+ case IR::OpEqual:
+ if (e->left->type == IR::StringType)
+ return Instr::EqualString;
+ return Instr::EqualReal;
+
+ case IR::OpNotEqual:
+ if (e->left->type == IR::StringType)
+ return Instr::NotEqualString;
+ return Instr::NotEqualReal;
+
+ case IR::OpStrictEqual:
+ if (e->left->type == IR::StringType)
+ return Instr::StrictEqualString;
+ return Instr::StrictEqualReal;
+
+ case IR::OpStrictNotEqual:
+ if (e->left->type == IR::StringType)
+ return Instr::StrictNotEqualString;
+ return Instr::StrictNotEqualReal;
+
+ case IR::OpAnd:
+ case IR::OpOr:
+ return Instr::Noop;
+
+ } // switch
+
+ return Instr::Noop;
+}
+
+void QDeclarativeV4CompilerPrivate::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 != Instr::Noop) {
+ Instr instr;
+ instr.common.type = opcode;
+ instr.binaryop.output = currentReg;
+ instr.binaryop.left = left;
+ instr.binaryop.right = right;
+ gen(instr);
+ }
+}
+
+void QDeclarativeV4CompilerPrivate::visitCall(IR::Call *call)
+{
+ if (IR::Name *name = call->base->asName()) {
+ if (call->args.size() == 1 && call->args.at(0)->type == IR::RealType) {
+ traceExpression(call->args.at(0), currentReg);
+
+ Instr instr;
+ instr.common.type = Instr::Noop;
+
+ switch (name->builtin) {
+ case IR::NoBuiltinSymbol:
+ break;
+
+ case IR::MathSinBultinFunction:
+ instr.math_sin_real(currentReg);
+ break;
+
+ case IR::MathCosBultinFunction:
+ instr.math_cos_real(currentReg);
+ break;
+
+ case IR::MathRoundBultinFunction:
+ instr.math_round_real(currentReg);
+ break;
+
+ case IR::MathFloorBultinFunction:
+ instr.math_floor_real(currentReg);
+ break;
+
+ case IR::MathPIBuiltinConstant:
+ break;
+ } // switch
+
+ if (instr.common.type != Instr::Noop) {
+ gen(instr);
+ return;
+ }
+ }
+ }
+
+ if (qmlVerboseCompiler())
+ qWarning() << "TODO:" << Q_FUNC_INFO << __LINE__;
+ discard();
+}
+
+
+//
+// statements
+//
+void QDeclarativeV4CompilerPrivate::visitExp(IR::Exp *s)
+{
+ traceExpression(s->expr, currentReg);
+}
+
+void QDeclarativeV4CompilerPrivate::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);
+
+ Instr conv;
+ conv.common.type = Instr::Noop;
+ if (target->type == IR::BoolType) {
+ switch (s->source->type) {
+ case IR::IntType: conv.common.type = Instr::ConvertIntToBool; break;
+ case IR::RealType: conv.common.type = Instr::ConvertRealToBool; break;
+ case IR::StringType: conv.common.type = Instr::ConvertStringToBool; break;
+ default: break;
+ } // switch
+ } else if (target->type == IR::IntType) {
+ switch (s->source->type) {
+ case IR::BoolType: conv.common.type = Instr::ConvertBoolToInt; break;
+ case IR::RealType: {
+ if (s->isMoveForReturn)
+ conv.common.type = Instr::MathRoundReal;
+ else
+ conv.common.type = Instr::ConvertRealToInt;
+ break;
+ }
+ case IR::StringType: conv.common.type = Instr::ConvertStringToInt; break;
+ default: break;
+ } // switch
+ } else if (target->type == IR::RealType) {
+ switch (s->source->type) {
+ case IR::BoolType: conv.common.type = Instr::ConvertBoolToReal; break;
+ case IR::IntType: conv.common.type = Instr::ConvertIntToReal; break;
+ case IR::StringType: conv.common.type = Instr::ConvertStringToReal; break;
+ default: break;
+ } // switch
+ } else if (target->type == IR::StringType) {
+ switch (s->source->type) {
+ case IR::BoolType: conv.common.type = Instr::ConvertBoolToString; break;
+ case IR::IntType: conv.common.type = Instr::ConvertIntToString; break;
+ case IR::RealType: conv.common.type = Instr::ConvertRealToString; break;
+ default: break;
+ } // switch
+ }
+ if (conv.common.type != Instr::Noop) {
+ conv.unaryop.output = dest;
+ conv.unaryop.src = src;
+ gen(conv);
+ } else {
+ discard();
+ }
+ } else {
+ traceExpression(s->source, dest);
+ }
+}
+
+void QDeclarativeV4CompilerPrivate::visitJump(IR::Jump *s)
+{
+ patches.append(Patch(s->target, bytecode.size()));
+
+ Instr i;
+ i.branch(0); // ### backpatch
+ gen(i);
+}
+
+void QDeclarativeV4CompilerPrivate::visitCJump(IR::CJump *s)
+{
+ traceExpression(s->cond, currentReg);
+
+ patches.append(Patch(s->iftrue, bytecode.size()));
+
+ Instr i;
+ i.branch_true(currentReg, 0); // ### backpatch
+ gen(i);
+}
+
+void QDeclarativeV4CompilerPrivate::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 test;
+ test.common.type = Instr::TestV4Store;
+ test.storetest.reg = storeReg;
+ switch (s->type) {
+ case IR::StringType:
+ test.storetest.regType = QMetaType::QString;
+ break;
+ case IR::UrlType:
+ test.storetest.regType = QMetaType::QUrl;
+ break;
+ case IR::AnchorLineType:
+ test.storetest.regType = qMetaTypeId<QDeclarativeAnchorLine>();
+ break;
+ case IR::SGAnchorLineType:
+ test.storetest.regType = qMetaTypeId<QSGAnchorLine>();
+ break;
+ case IR::ObjectType:
+ test.storetest.regType = QMetaType::QObjectStar;
+ break;
+ case IR::BoolType:
+ test.storetest.regType = QMetaType::Bool;
+ break;
+ case IR::IntType:
+ test.storetest.regType = QMetaType::Int;
+ break;
+ case IR::RealType:
+ test.storetest.regType = QMetaType::QReal;
+ break;
+ default:
+ discard();
+ return;
+ }
+ gen(test);
+ }
+
+ Instr store;
+ store.common.type = Instr::Store;
+ store.store.output = 0;
+ store.store.index = expression->property->index;
+ store.store.reg = storeReg;
+ store.store.exceptionId = exceptionId(s->line, s->column);
+ gen(store);
+}
+
+void QDeclarativeV4Compiler::dump(const QByteArray &programData)
+{
+ const QDeclarativeV4Program *program = (const QDeclarativeV4Program *)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 *code = start;
+ const char *end = code + programSize;
+ while (code < end) {
+ Instr *instr = (Instr *) code;
+ instr->dump(code - start);
+ code += instr->size();
+ }
+}
+
+QDeclarativeFastProperties *QDeclarativeV4Compiler::fastPropertyAccessor()
+{
+ return fastProperties();
+}
+
+/*!
+Clear the state associated with attempting to compile a specific binding.
+This does not clear the global "committed binding" states.
+*/
+void QDeclarativeV4CompilerPrivate::resetInstanceState()
+{
+ registerCleanups.clear();
+ data = committed.data;
+ exceptions = committed.exceptions;
+ usedSubscriptionIds.clear();
+ subscriptionIds = committed.subscriptionIds;
+ registeredStrings = committed.registeredStrings;
+ bytecode.clear();
+ patches.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 QDeclarativeV4CompilerPrivate::commitCompile()
+{
+ int rv = committed.count();
+ committed.offsets << committed.bytecode.count();
+ committed.dependencies << usedSubscriptionIds;
+ committed.bytecode += bytecode.code();
+ committed.data = data;
+ committed.exceptions = exceptions;
+ committed.subscriptionIds = subscriptionIds;
+ committed.registeredStrings = registeredStrings;
+ return rv;
+}
+
+bool QDeclarativeV4CompilerPrivate::compile(QDeclarativeJS::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::Module module;
+ IR::Function *function = 0;
+
+ QDeclarativeV4IRBuilder irBuilder(expression, engine);
+ if (!(function = irBuilder(&module, 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 QDeclarativeV4CompilerPrivate::registerLiteralString(quint8 reg, const QString &str)
+{
+ // ### string cleanup
+
+ QByteArray strdata((const char *)str.constData(), str.length() * sizeof(QChar));
+ int offset = data.count();
+ data += strdata;
+
+ Instr string;
+ string.common.type = Instr::String;
+ string.string_value.reg = reg;
+ string.string_value.offset = offset;
+ string.string_value.length = str.length();
+ gen(string);
+
+ return reg;
+}
+
+// Returns an identifier offset
+int QDeclarativeV4CompilerPrivate::registerString(const QString &string)
+{
+ Q_ASSERT(!string.isEmpty());
+
+ QHash<QString, QPair<int, int> >::ConstIterator iter = registeredStrings.find(string);
+
+ if (iter == registeredStrings.end()) {
+ 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.insert(string, qMakePair(registeredStrings.count(), rv));
+ }
+
+ Instr reg;
+ reg.common.type = Instr::InitString;
+ reg.initstring.offset = iter->first;
+ reg.initstring.dataIdx = iter->second;
+ gen(reg);
+ return reg.initstring.offset;
+}
+
+/*!
+Returns true if the current expression has not already subscribed to \a sub in currentBlockMask.
+*/
+bool QDeclarativeV4CompilerPrivate::blockNeedsSubscription(const QStringList &sub)
+{
+ QString str = sub.join(QLatin1String("."));
+
+ QHash<QString, int>::ConstIterator iter = subscriptionIds.find(str);
+ if (iter == subscriptionIds.end())
+ return true;
+
+ QHash<int, quint32>::ConstIterator uiter = usedSubscriptionIds.find(*iter);
+ if (uiter == usedSubscriptionIds.end())
+ return true;
+ else
+ return !(*uiter & currentBlockMask);
+}
+
+int QDeclarativeV4CompilerPrivate::subscriptionIndex(const QStringList &sub)
+{
+ QString str = sub.join(QLatin1String("."));
+ QHash<QString, int>::ConstIterator iter = subscriptionIds.find(str);
+ if (iter == subscriptionIds.end())
+ iter = subscriptionIds.insert(str, subscriptionIds.count());
+ if (!(usedSubscriptionIds[*iter] & currentBlockMask)) {
+ usedSubscriptionIds[*iter] |= currentBlockMask;
+ usedSubscriptionIdsChanged = true;
+ }
+ return *iter;
+}
+
+quint32 QDeclarativeV4CompilerPrivate::subscriptionBlockMask(const QStringList &sub)
+{
+ QString str = sub.join(QLatin1String("."));
+
+ QHash<QString, int>::ConstIterator iter = subscriptionIds.find(str);
+ Q_ASSERT(iter != subscriptionIds.end());
+
+ QHash<int, quint32>::ConstIterator uiter = usedSubscriptionIds.find(*iter);
+ Q_ASSERT(uiter != usedSubscriptionIds.end());
+
+ return *uiter;
+}
+
+quint8 QDeclarativeV4CompilerPrivate::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 QDeclarativeV4CompilerPrivate::exceptionId(QDeclarativeJS::AST::ExpressionNode *n)
+{
+ quint8 rv = 0xFF;
+ if (n && exceptions.count() < 0xFF) {
+ QDeclarativeJS::AST::SourceLocation l = n->firstSourceLocation();
+ rv = exceptionId(l.startLine, l.startColumn);
+ }
+ return rv;
+}
+
+QDeclarativeV4Compiler::QDeclarativeV4Compiler()
+: d(new QDeclarativeV4CompilerPrivate)
+{
+ qmlBindingsTest |= qmlBindingsTestEnv();
+}
+
+QDeclarativeV4Compiler::~QDeclarativeV4Compiler()
+{
+ delete d; d = 0;
+}
+
+/*
+Returns true if any bindings were compiled.
+*/
+bool QDeclarativeV4Compiler::isValid() const
+{
+ return !d->committed.bytecode.isEmpty();
+}
+
+/*
+-1 on failure, otherwise the binding index to use.
+*/
+int QDeclarativeV4Compiler::compile(const Expression &expression, QDeclarativeEnginePrivate *engine)
+{
+ if (!expression.expression.asAST()) return false;
+
+ if (!qmlExperimental() && expression.property->isValueTypeSubProperty)
+ return -1;
+
+ if (qmlDisableOptimizer())
+ return -1;
+
+ d->expression = &expression;
+ d->engine = engine;
+
+ if (d->compile(expression.expression.asAST())) {
+ return d->commitCompile();
+ } else {
+ return -1;
+ }
+}
+
+QByteArray QDeclarativeV4CompilerPrivate::buildSignalTable() const
+{
+ QHash<int, QList<QPair<int, quint32> > > table;
+
+ for (int ii = 0; ii < committed.count(); ++ii) {
+ const QHash<int, quint32> &deps = committed.dependencies.at(ii);
+ for (QHash<int, quint32>::ConstIterator iter = deps.begin(); iter != deps.end(); ++iter)
+ table[iter.key()].append(qMakePair(ii, iter.value()));
+ }
+
+ 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 QDeclarativeV4CompilerPrivate::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 QDeclarativeV4Compiler::program() const
+{
+ QByteArray programData;
+
+ if (isValid()) {
+ QDeclarativeV4Program prog;
+ prog.bindings = d->committed.count();
+
+ Bytecode bc;
+ Instr jump;
+ jump.common.type = Instr::Jump;
+ jump.jump.reg = -1;
+
+ for (int ii = 0; ii < d->committed.count(); ++ii) {
+ jump.jump.count = d->committed.count() - ii - 1;
+ jump.jump.count*= jump.size();
+ jump.jump.count+= d->committed.offsets.at(ii);
+ bc.append(jump);
+ }
+
+
+ QByteArray bytecode = bc.code();
+ bytecode += d->committed.bytecode;
+
+ 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(QDeclarativeV4Program) + bytecode.count();
+ size += prog.dataLength;
+
+ programData.resize(size);
+ memcpy(programData.data(), &prog, sizeof(QDeclarativeV4Program));
+ if (prog.dataLength)
+ memcpy((char *)((QDeclarativeV4Program *)programData.data())->data(), data.constData(),
+ data.size());
+ memcpy((char *)((QDeclarativeV4Program *)programData.data())->instructions(), bytecode.constData(),
+ bytecode.count());
+ }
+
+ if (bindingsDump()) {
+ qWarning().nospace() << "Subscription slots:";
+
+ for (QHash<QString, int>::ConstIterator iter = d->committed.subscriptionIds.begin();
+ iter != d->committed.subscriptionIds.end();
+ ++iter) {
+ qWarning().nospace() << " " << iter.value() << "\t-> " << iter.key();
+ }
+
+
+ QDeclarativeV4Compiler::dump(programData);
+ }
+
+ return programData;
+}
+
+void QDeclarativeV4Compiler::enableBindingsTest(bool e)
+{
+ if (e)
+ qmlBindingsTest = true;
+ else
+ qmlBindingsTest = qmlBindingsTestEnv();
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/qml/v4/qdeclarativev4compiler_p.h b/src/declarative/qml/v4/qdeclarativev4compiler_p.h
new file mode 100644
index 0000000000..c10691dc87
--- /dev/null
+++ b/src/declarative/qml/v4/qdeclarativev4compiler_p.h
@@ -0,0 +1,104 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVEV4COMPILER_P_H
+#define QDECLARATIVEV4COMPILER_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/qdeclarativeexpression_p.h"
+#include "private/qdeclarativebinding_p.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativeFastProperties;
+class QDeclarativeTypeNameCache;
+class QDeclarativeV4CompilerPrivate;
+class Q_AUTOTEST_EXPORT QDeclarativeV4Compiler
+{
+public:
+ QDeclarativeV4Compiler();
+ ~QDeclarativeV4Compiler();
+
+ // Returns true if bindings were compiled
+ bool isValid() const;
+
+ struct Expression
+ {
+ QDeclarativeParser::Object *component;
+ QDeclarativeParser::Object *context;
+ QDeclarativeParser::Property *property;
+ QDeclarativeParser::Variant expression;
+ QHash<QString, QDeclarativeParser::Object *> ids;
+ QDeclarativeTypeNameCache *importCache;
+ QDeclarativeImports imports;
+ };
+
+ // -1 on failure, otherwise the binding index to use
+ int compile(const Expression &, QDeclarativeEnginePrivate *);
+
+ // Returns the compiled program
+ QByteArray program() const;
+
+ static void dump(const QByteArray &);
+ static QDeclarativeFastProperties *fastPropertyAccessor();
+ static void enableBindingsTest(bool);
+private:
+ QDeclarativeV4CompilerPrivate *d;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QDECLARATIVEV4COMPILER_P_H
+
diff --git a/src/declarative/qml/v4/qdeclarativev4compiler_p_p.h b/src/declarative/qml/v4/qdeclarativev4compiler_p_p.h
new file mode 100644
index 0000000000..1b2a998422
--- /dev/null
+++ b/src/declarative/qml/v4/qdeclarativev4compiler_p_p.h
@@ -0,0 +1,184 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVEV4COMPILER_P_P_H
+#define QDECLARATIVEV4COMPILER_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 "qdeclarativev4instruction_p.h"
+#include "qdeclarativev4ir_p.h"
+#include <private/qdeclarativeparser_p.h>
+#include <private/qdeclarativeimport_p.h>
+#include <private/qdeclarativeengine_p.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativeV4CompilerPrivate: protected QDeclarativeJS::IR::ExprVisitor,
+ protected QDeclarativeJS::IR::StmtVisitor
+{
+public:
+ QDeclarativeV4CompilerPrivate();
+
+ void resetInstanceState();
+ int commitCompile();
+
+ const QDeclarativeV4Compiler::Expression *expression;
+ QDeclarativeEnginePrivate *engine;
+
+ QString contextName() const { return QLatin1String("$$$SCOPE_") + QString::number((quintptr)expression->context, 16); }
+
+ bool compile(QDeclarativeJS::AST::Node *);
+
+ QHash<int, QPair<int, int> > registerCleanups;
+
+ int registerLiteralString(quint8 reg, const QString &);
+ int registerString(const QString &);
+ QHash<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(QDeclarativeJS::AST::ExpressionNode *);
+ QVector<quint64> exceptions;
+
+ QHash<int, quint32> usedSubscriptionIds;
+
+ QHash<QString, int> subscriptionIds;
+ QDeclarativeJS::Bytecode bytecode;
+
+ // back patching
+ struct Patch {
+ QDeclarativeJS::IR::BasicBlock *block; // the basic block
+ int offset; // the index of the instruction to patch
+ Patch(QDeclarativeJS::IR::BasicBlock *block = 0, int index = -1)
+ : block(block), offset(index) {}
+ };
+ QVector<Patch> patches;
+
+ // Committed binding data
+ struct {
+ QList<int> offsets;
+ QList<QHash<int, quint32> > dependencies;
+
+ //QDeclarativeJS::Bytecode bytecode;
+ QByteArray bytecode;
+ QByteArray data;
+ QHash<QString, int> subscriptionIds;
+ QVector<quint64> exceptions;
+
+ QHash<QString, QPair<int, int> > registeredStrings;
+
+ int count() const { return offsets.count(); }
+ } committed;
+
+ QByteArray buildSignalTable() const;
+ QByteArray buildExceptionData() const;
+
+ void convertToReal(QDeclarativeJS::IR::Expr *expr, int reg);
+ void convertToInt(QDeclarativeJS::IR::Expr *expr, int reg);
+ void convertToBool(QDeclarativeJS::IR::Expr *expr, int reg);
+ quint8 instructionOpcode(QDeclarativeJS::IR::Binop *e);
+
+protected:
+
+ //
+ // tracing
+ //
+ void trace(int line, int column);
+ void trace(QVector<QDeclarativeJS::IR::BasicBlock *> *blocks);
+ void traceExpression(QDeclarativeJS::IR::Expr *e, quint8 r);
+
+ inline void gen(const QDeclarativeJS::Instr &i) { bytecode.append(i); }
+
+ //
+ // expressions
+ //
+ virtual void visitConst(QDeclarativeJS::IR::Const *e);
+ virtual void visitString(QDeclarativeJS::IR::String *e);
+ virtual void visitName(QDeclarativeJS::IR::Name *e);
+ virtual void visitTemp(QDeclarativeJS::IR::Temp *e);
+ virtual void visitUnop(QDeclarativeJS::IR::Unop *e);
+ virtual void visitBinop(QDeclarativeJS::IR::Binop *e);
+ virtual void visitCall(QDeclarativeJS::IR::Call *e);
+
+ //
+ // statements
+ //
+ virtual void visitExp(QDeclarativeJS::IR::Exp *s);
+ virtual void visitMove(QDeclarativeJS::IR::Move *s);
+ virtual void visitJump(QDeclarativeJS::IR::Jump *s);
+ virtual void visitCJump(QDeclarativeJS::IR::CJump *s);
+ virtual void visitRet(QDeclarativeJS::IR::Ret *s);
+
+private:
+ QStringList _subscribeName;
+ QDeclarativeJS::IR::Function *_function;
+ QDeclarativeJS::IR::BasicBlock *_block;
+ void discard() { _discarded = true; }
+ bool _discarded;
+ quint8 currentReg;
+
+ bool usedSubscriptionIdsChanged;
+ quint32 currentBlockMask;
+};
+
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QDECLARATIVEV4COMPILER_P_P_H
+
diff --git a/src/declarative/qml/v4/qdeclarativev4instruction.cpp b/src/declarative/qml/v4/qdeclarativev4instruction.cpp
new file mode 100644
index 0000000000..9c3bf914e0
--- /dev/null
+++ b/src/declarative/qml/v4/qdeclarativev4instruction.cpp
@@ -0,0 +1,559 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qdeclarativev4instruction_p.h"
+#include "qdeclarativev4bindings_p.h"
+
+#include <QtCore/qdebug.h>
+#include <private/qdeclarativeglobal_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
+
+DEFINE_BOOL_CONFIG_OPTION(qmlVerboseCompiler, QML_VERBOSE_COMPILER)
+
+namespace QDeclarativeJS {
+
+#ifdef DEBUG_INSTR_DUMP
+static struct DumpInstrAtStartup {
+ DumpInstrAtStartup() {
+#define DUMP_INSTR_AT_STARTUP(Type, FMT) { Instr i; i.common.type = Instr::Type; i.dump(0); }
+ FOR_EACH_V4_INSTR(DUMP_INSTR_AT_STARTUP);
+ }
+} dump_instr_at_startup;
+#endif
+
+int Instr::size() const
+{
+#define V4_RETURN_INSTR_SIZE(I, FMT) case I: return QML_V4_INSTR_SIZE(I, FMT);
+ switch (common.type) {
+ FOR_EACH_V4_INSTR(V4_RETURN_INSTR_SIZE)
+ }
+#undef V4_RETURN_INSTR_SIZE
+ return 0;
+}
+
+void Instr::dump(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 (common.type) {
+ case Instr::Noop:
+ INSTR_DUMP << "\t" << "Noop";
+ break;
+ case Instr::BindingId:
+ INSTR_DUMP << id.line << ":" << id.column << ":";
+ break;
+ case Instr::Subscribe:
+ INSTR_DUMP << "\t" << "Subscribe" << "\t\t" << "Object_Reg(" << subscribeop.reg << ") Notify_Signal(" << subscribeop.index << ") -> Subscribe_Slot(" << subscribeop.offset << ")";
+ break;
+ case Instr::SubscribeId:
+ INSTR_DUMP << "\t" << "SubscribeId" << "\t\t" << "Id_Offset(" << subscribeop.index << ") -> Subscribe_Slot(" << subscribeop.offset << ")";
+ break;
+ case Instr::FetchAndSubscribe:
+ INSTR_DUMP << "\t" << "FetchAndSubscribe" << "\t" << "Object_Reg(" << fetchAndSubscribe.reg << ") Fast_Accessor(" << fetchAndSubscribe.function << ") -> Output_Reg(" << fetchAndSubscribe.reg << ") Subscription_Slot(" << fetchAndSubscribe.subscription << ")";
+ break;
+ case Instr::LoadId:
+ INSTR_DUMP << "\t" << "LoadId" << "\t\t\t" << "Id_Offset(" << load.index << ") -> Output_Reg(" << load.reg << ")";
+ break;
+ case Instr::LoadScope:
+ INSTR_DUMP << "\t" << "LoadScope" << "\t\t" << "-> Output_Reg(" << load.reg << ")";
+ break;
+ case Instr::LoadRoot:
+ INSTR_DUMP << "\t" << "LoadRoot" << "\t\t" << "-> Output_Reg(" << load.reg << ")";
+ break;
+ case Instr::LoadAttached:
+ INSTR_DUMP << "\t" << "LoadAttached" << "\t\t" << "Object_Reg(" << attached.reg << ") Attached_Index(" << attached.id << ") -> Output_Reg(" << attached.output << ")";
+ break;
+ case Instr::UnaryNot:
+ INSTR_DUMP << "\t" << "UnaryNot" << "\t\t" << "Input_Reg(" << unaryop.src << ") -> Output_Reg(" << unaryop.output << ")";
+ break;
+ case Instr::UnaryMinusReal:
+ INSTR_DUMP << "\t" << "UnaryMinusReal" << "\t\t" << "Input_Reg(" << unaryop.src << ") -> Output_Reg(" << unaryop.output << ")";
+ break;
+ case Instr::UnaryMinusInt:
+ INSTR_DUMP << "\t" << "UnaryMinusInt" << "\t\t" << "Input_Reg(" << unaryop.src << ") -> Output_Reg(" << unaryop.output << ")";
+ break;
+ case Instr::UnaryPlusReal:
+ INSTR_DUMP << "\t" << "UnaryPlusReal" << "\t\t" << "Input_Reg(" << unaryop.src << ") -> Output_Reg(" << unaryop.output << ")";
+ break;
+ case Instr::UnaryPlusInt:
+ INSTR_DUMP << "\t" << "UnaryPlusInt" << "\t\t" << "Input_Reg(" << unaryop.src << ") -> Output_Reg(" << unaryop.output << ")";
+ break;
+ case Instr::ConvertBoolToInt:
+ INSTR_DUMP << "\t" << "ConvertBoolToInt" << "\t" << "Input_Reg(" << unaryop.src << ") -> Output_Reg(" << unaryop.output << ")";
+ break;
+ case Instr::ConvertBoolToReal:
+ INSTR_DUMP << "\t" << "ConvertBoolToReal" << "\t" << "Input_Reg(" << unaryop.src << ") -> Output_Reg(" << unaryop.output << ")";
+ break;
+ case Instr::ConvertBoolToString:
+ INSTR_DUMP << "\t" << "ConvertBoolToString" << "\t" << "Input_Reg(" << unaryop.src << ") -> Output_Reg(" << unaryop.output << ")";
+ break;
+ case Instr::ConvertIntToBool:
+ INSTR_DUMP << "\t" << "ConvertIntToBool" << "\t" << "Input_Reg(" << unaryop.src << ") -> Output_Reg(" << unaryop.output << ")";
+ break;
+ case Instr::ConvertIntToReal:
+ INSTR_DUMP << "\t" << "ConvertIntToReal" << "\t" << "Input_Reg(" << unaryop.src << ") -> Output_Reg(" << unaryop.output << ")";
+ break;
+ case Instr::ConvertIntToString:
+ INSTR_DUMP << "\t" << "ConvertIntToString" << "\t" << "Input_Reg(" << unaryop.src << ") -> Output_Reg(" << unaryop.output << ")";
+ break;
+ case Instr::ConvertRealToBool:
+ INSTR_DUMP << "\t" << "ConvertRealToBool" << "\t" << "Input_Reg(" << unaryop.src << ") -> Output_Reg(" << unaryop.output << ")";
+ break;
+ case Instr::ConvertRealToInt:
+ INSTR_DUMP << "\t" << "ConvertRealToInt" << "\t" << "Input_Reg(" << unaryop.src << ") -> Output_Reg(" << unaryop.output << ")";
+ break;
+ case Instr::ConvertRealToString:
+ INSTR_DUMP << "\t" << "ConvertRealToString" << "\t" << "Input_Reg(" << unaryop.src << ") -> Output_Reg(" << unaryop.output << ")";
+ break;
+ case Instr::ConvertStringToBool:
+ INSTR_DUMP << "\t" << "ConvertStringToBool" << "\t" << "Input_Reg(" << unaryop.src << ") -> Output_Reg(" << unaryop.output << ")";
+ break;
+ case Instr::ConvertStringToInt:
+ INSTR_DUMP << "\t" << "ConvertStringToInt" << "\t" << "Input_Reg(" << unaryop.src << ") -> Output_Reg(" << unaryop.output << ")";
+ break;
+ case Instr::ConvertStringToReal:
+ INSTR_DUMP << "\t" << "ConvertStringToReal" << "\t" << "Input_Reg(" << unaryop.src << ") -> Output_Reg(" << unaryop.output << ")";
+ break;
+ case Instr::MathSinReal:
+ INSTR_DUMP << "\t" << "MathSinReal" << "\t\t" << "Input_Reg(" << unaryop.src << ") -> Output_Reg(" << unaryop.output << ")";
+ break;
+ case Instr::MathCosReal:
+ INSTR_DUMP << "\t" << "MathCosReal" << "\t\t" << "Input_Reg(" << unaryop.src << ") -> Output_Reg(" << unaryop.output << ")";
+ break;
+ case Instr::MathRoundReal:
+ INSTR_DUMP << "\t" << "MathRoundReal" << "\t\t" << "Input_Reg(" << unaryop.src << ") -> Output_Reg(" << unaryop.output << ")";
+ break;
+ case Instr::MathFloorReal:
+ INSTR_DUMP << "\t" << "MathFloorReal" << "\t\t" << "Input_Reg(" << unaryop.src << ") -> Output_Reg(" << unaryop.output << ")";
+ break;
+ case Instr::MathPIReal:
+ INSTR_DUMP << "\t" << "MathPIReal" << "\t\t" << "Input_Reg(" << unaryop.src << ") -> Output_Reg(" << unaryop.output << ")";
+ break;
+ case Instr::Real:
+ INSTR_DUMP << "\t" << "Real" << "\t\t\t" << "Constant(" << real_value.value << ") -> Output_Reg(" << real_value.reg << ")";
+ break;
+ case Instr::Int:
+ INSTR_DUMP << "\t" << "Int" << "\t\t\t" << "Constant(" << int_value.value << ") -> Output_Reg(" << int_value.reg << ")";
+ break;
+ case Instr::Bool:
+ INSTR_DUMP << "\t" << "Bool" << "\t\t\t" << "Constant(" << bool_value.value << ") -> Output_Reg(" << bool_value.reg << ")";
+ break;
+ case Instr::String:
+ INSTR_DUMP << "\t" << "String" << "\t\t\t" << "String_DataIndex(" << string_value.offset << ") String_Length(" << string_value.length << ") -> Output_Register(" << string_value.reg << ")";
+ break;
+ case Instr::EnableV4Test:
+ INSTR_DUMP << "\t" << "EnableV4Test" << "\t\t" << "String_DataIndex(" << string_value.offset << ") String_Length(" << string_value.length << ")";
+ break;
+ case Instr::TestV4Store:
+ INSTR_DUMP << "\t" << "TestV4Store" << "\t\t" << "Input_Reg(" << storetest.reg << ") Reg_Type(" << storetest.regType << ")";
+ break;
+ case Instr::BitAndInt:
+ INSTR_DUMP << "\t" << "BitAndInt" << "\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
+ break;
+ case Instr::BitOrInt:
+ INSTR_DUMP << "\t" << "BitOrInt" << "\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
+ break;
+ case Instr::BitXorInt:
+ INSTR_DUMP << "\t" << "BitXorInt" << "\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
+ break;
+ case Instr::AddReal:
+ INSTR_DUMP << "\t" << "AddReal" << "\t\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
+ break;
+ case Instr::AddString:
+ INSTR_DUMP << "\t" << "AddString" << "\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
+ break;
+ case Instr::SubReal:
+ INSTR_DUMP << "\t" << "SubReal" << "\t\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
+ break;
+ case Instr::MulReal:
+ INSTR_DUMP << "\t" << "MulReal" << "\t\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
+ break;
+ case Instr::DivReal:
+ INSTR_DUMP << "\t" << "DivReal" << "\t\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
+ break;
+ case Instr::ModReal:
+ INSTR_DUMP << "\t" << "ModReal" << "\t\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
+ break;
+ case Instr::LShiftInt:
+ INSTR_DUMP << "\t" << "LShiftInt" << "\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
+ break;
+ case Instr::RShiftInt:
+ INSTR_DUMP << "\t" << "RShiftInt" << "\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
+ break;
+ case Instr::URShiftInt:
+ INSTR_DUMP << "\t" << "URShiftInt" << "\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
+ break;
+ case Instr::GtReal:
+ INSTR_DUMP << "\t" << "GtReal" << "\t\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
+ break;
+ case Instr::LtReal:
+ INSTR_DUMP << "\t" << "LtReal" << "\t\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
+ break;
+ case Instr::GeReal:
+ INSTR_DUMP << "\t" << "GeReal" << "\t\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
+ break;
+ case Instr::LeReal:
+ INSTR_DUMP << "\t" << "LeReal" << "\t\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
+ break;
+ case Instr::EqualReal:
+ INSTR_DUMP << "\t" << "EqualReal" << "\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
+ break;
+ case Instr::NotEqualReal:
+ INSTR_DUMP << "\t" << "NotEqualReal" << "\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
+ break;
+ case Instr::StrictEqualReal:
+ INSTR_DUMP << "\t" << "StrictEqualReal" << "\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
+ break;
+ case Instr::StrictNotEqualReal:
+ INSTR_DUMP << "\t" << "StrictNotEqualReal" << "\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
+ break;
+ case Instr::GtString:
+ INSTR_DUMP << "\t" << "GtString" << "\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
+ break;
+ case Instr::LtString:
+ INSTR_DUMP << "\t" << "LtString" << "\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
+ break;
+ case Instr::GeString:
+ INSTR_DUMP << "\t" << "GeString" << "\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
+ break;
+ case Instr::LeString:
+ INSTR_DUMP << "\t" << "LeString" << "\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
+ break;
+ case Instr::EqualString:
+ INSTR_DUMP << "\t" << "EqualString" << "\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
+ break;
+ case Instr::NotEqualString:
+ INSTR_DUMP << "\t" << "NotEqualString" << "\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
+ break;
+ case Instr::StrictEqualString:
+ INSTR_DUMP << "\t" << "StrictEqualString" << "\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
+ break;
+ case Instr::StrictNotEqualString:
+ INSTR_DUMP << "\t" << "StrictNotEqualString" << "\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
+ break;
+ case Instr::NewString:
+ INSTR_DUMP << "\t" << "NewString" << "\t\t" << "Register(" << construct.reg << ")";
+ break;
+ case Instr::NewUrl:
+ INSTR_DUMP << "\t" << "NewUrl" << "\t\t\t" << "Register(" << construct.reg << ")";
+ break;
+ case Instr::CleanupRegister:
+ INSTR_DUMP << "\t" << "CleanupRegister" << "\t\t" << "Register(" << cleanup.reg << ")";
+ break;
+ case Instr::Fetch:
+ INSTR_DUMP << "\t" << "Fetch" << "\t\t\t" << "Object_Reg(" << fetch.reg << ") Property_Index(" << fetch.index << ") -> Output_Reg(" << fetch.reg << ")";
+ break;
+ case Instr::Store:
+ INSTR_DUMP << "\t" << "Store" << "\t\t\t" << "Input_Reg(" << store.reg << ") -> Object_Reg(" << store.output << ") Property_Index(" << store.index << ")";
+ break;
+ case Instr::Copy:
+ INSTR_DUMP << "\t" << "Copy" << "\t\t\t" << "Input_Reg(" << copy.src << ") -> Output_Reg(" << copy.reg << ")";
+ break;
+ case Instr::Jump:
+ if (jump.reg != -1) {
+ INSTR_DUMP << "\t" << "Jump" << "\t\t\t" << "Address(" << (address + size() + jump.count) << ") [if false == Input_Reg(" << jump.reg << ")]";
+ } else {
+ INSTR_DUMP << "\t" << "Jump" << "\t\t\t" << "Address(" << (address + size() + jump.count) << ")";
+ }
+ break;
+ case Instr::BranchFalse:
+ INSTR_DUMP << "\t" << "BranchFalse" << "\t\t" << "Address(" << (address + size() + branchop.offset) << ") [if false == Input_Reg(" << branchop.reg << ")]";
+ break;
+ case Instr::BranchTrue:
+ INSTR_DUMP << "\t" << "BranchTrue" << "\t\t" << "Address(" << (address + size() + branchop.offset) << ") [if true == Input_Reg(" << branchop.reg << ")]";
+ break;
+ case Instr::Branch:
+ INSTR_DUMP << "\t" << "Branch" << "\t\t\t" << "Address(" << (address + size() + branchop.offset) << ")";
+ break;
+ case Instr::InitString:
+ INSTR_DUMP << "\t" << "InitString" << "\t\t" << "String_DataIndex(" << initstring.dataIdx << ") -> String_Slot(" << initstring.offset << ")";
+ break;
+ case Instr::Block:
+ INSTR_DUMP << "\t" << "Block" << "\t\t\t" << "Mask(" << QByteArray::number(blockop.block, 16).constData() << ")";
+ break;
+ default:
+ INSTR_DUMP << "\t" << "Unknown";
+ break;
+ }
+}
+
+void Instr::noop()
+{
+ common.type = Noop;
+}
+
+void Instr::load_root(quint8 reg)
+{
+ common.type = LoadRoot;
+ load.reg = reg;
+ load.index = 0;
+}
+
+void Instr::load_scope(quint8 reg)
+{
+ common.type = LoadScope;
+ load.reg = reg;
+ load.index = 0;
+}
+
+void Instr::load_id(quint8 reg, quint32 idIndex)
+{
+ common.type = LoadId;
+ load.reg = reg;
+ load.index = idIndex;
+}
+
+void Instr::subscribe(qint8 reg, quint16 subscribeSlot, quint32 notifyIndex)
+{
+ common.type = Instr::Subscribe;
+ subscribeop.reg = reg;
+ subscribeop.offset = subscribeSlot;
+ subscribeop.index = notifyIndex;
+}
+
+void Instr::subscribeId(qint8 reg, quint16 subscribeSlot, quint32 idIndex)
+{
+ common.type = Instr::SubscribeId;
+ subscribeop.reg = reg;
+ subscribeop.offset = subscribeSlot;
+ subscribeop.index = idIndex;
+}
+
+void Instr::move_reg_bool(quint8 reg, bool value)
+{
+ common.type = Bool;
+ bool_value.reg = reg;
+ bool_value.value = value;
+}
+
+void Instr::move_reg_int(quint8 reg, int value)
+{
+ common.type = Int;
+ int_value.reg = reg;
+ int_value.value = value;
+}
+
+void Instr::move_reg_qreal(quint8 reg, qreal value)
+{
+ common.type = Real;
+ real_value.reg = reg;
+ real_value.value = value;
+}
+
+void Instr::move_reg_reg(quint8 reg, quint8 src)
+{
+ common.type = Copy;
+ copy.reg = reg;
+ copy.src = src;
+}
+
+void Instr::unary_not(quint8 dest, quint8 src)
+{
+ common.type = UnaryNot;
+ unaryop.src = src;
+ unaryop.output = dest;
+}
+
+void Instr::uminus_real(quint8 dest, quint8 src)
+{
+ common.type = UnaryMinusReal;
+ unaryop.src = src;
+ unaryop.output = dest;
+}
+
+void Instr::uminus_int(quint8 dest, quint8 src)
+{
+ common.type = UnaryMinusInt;
+ unaryop.src = src;
+ unaryop.output = dest;
+}
+
+void Instr::uplus_real(quint8 dest, quint8 src)
+{
+ common.type = UnaryPlusReal;
+ unaryop.src = src;
+ unaryop.output = dest;
+}
+
+void Instr::uplus_int(quint8 dest, quint8 src)
+{
+ common.type = UnaryPlusInt;
+ unaryop.src = src;
+ unaryop.output = dest;
+}
+
+void Instr::ucompl_real(quint8 dest, quint8 src)
+{
+ Q_UNUSED(dest);
+ Q_UNUSED(src);
+ if (qmlVerboseCompiler())
+ qWarning() << "TODO" << Q_FUNC_INFO;
+}
+
+void Instr::ucompl_int(quint8 dest, quint8 src)
+{
+ Q_UNUSED(dest);
+ Q_UNUSED(src);
+ if (qmlVerboseCompiler())
+ qWarning() << "TODO" << Q_FUNC_INFO;
+}
+
+void Instr::math_sin_real(quint8 reg)
+{
+ common.type = MathSinReal;
+ unaryop.src = reg;
+ unaryop.output = reg;
+}
+
+void Instr::math_cos_real(quint8 reg)
+{
+ common.type = MathCosReal;
+ unaryop.src = reg;
+ unaryop.output = reg;
+}
+
+void Instr::math_round_real(quint8 reg)
+{
+ common.type = MathRoundReal;
+ unaryop.src = reg;
+ unaryop.output = reg;
+}
+
+void Instr::math_floor_real(quint8 reg)
+{
+ common.type = MathFloorReal;
+ unaryop.src = reg;
+ unaryop.output = reg;
+}
+
+void Instr::math_pi_real(quint8 reg)
+{
+ common.type = MathPIReal;
+ unaryop.src = reg;
+ unaryop.output = reg;
+}
+
+void Instr::branch_true(quint8 reg, qint16 offset)
+{
+ common.type = BranchTrue;
+ branchop.reg = reg;
+ branchop.offset = offset;
+}
+
+void Instr::branch_false(quint8 reg, qint16 offset)
+{
+ common.type = BranchFalse;
+ branchop.reg = reg;
+ branchop.offset = offset;
+}
+
+void Instr::branch(qint16 offset)
+{
+ common.type = Branch;
+ branchop.offset = offset;
+}
+
+void Instr::block(quint32 mask)
+{
+ common.type = Block;
+ blockop.block = mask;
+}
+
+Bytecode::Bytecode()
+{
+#ifdef QML_THREADED_INTERPRETER
+ decodeInstr = QDeclarativeV4Bindings::getDecodeInstrTable();
+#endif
+}
+
+void Bytecode::append(const Instr &instr)
+{
+ const char *it;
+#ifdef QML_THREADED_INTERPRETER
+ Instr i = instr;
+ i.common.code = decodeInstr[i.common.type];
+ it = (const char *) &i;
+#else
+ it = (const char *) &instr;
+#endif
+ d.append(it, instr.size());
+}
+
+void Bytecode::append(const QVector<Instr> &instrs)
+{
+ foreach (const Instr &i, instrs)
+ append(i);
+}
+
+int Bytecode::remove(int offset)
+{
+ const Instr *instr = (const Instr *) (d.begin() + offset);
+ const int instrSize = instr->size();
+ d.remove(offset, instrSize);
+ return instrSize;
+}
+
+const Instr &Bytecode::operator[](int offset) const
+{
+ return *((const Instr *) (d.begin() + offset));
+}
+
+Instr &Bytecode::operator[](int offset)
+{
+ return *((Instr *) (d.begin() + offset));
+}
+
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/qml/v4/qdeclarativev4instruction_p.h b/src/declarative/qml/v4/qdeclarativev4instruction_p.h
new file mode 100644
index 0000000000..67b152adea
--- /dev/null
+++ b/src/declarative/qml/v4/qdeclarativev4instruction_p.h
@@ -0,0 +1,444 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVEV4INSTRUCTION_P_H
+#define QDECLARATIVEV4INSTRUCTION_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>
+
+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(MathSinReal, unaryop) \
+ F(MathCosReal, unaryop) \
+ F(MathRoundReal, unaryop) \
+ F(MathFloorReal, unaryop) \
+ F(MathPIReal, unaryop) \
+ F(Real, real_value) \
+ F(Int, int_value) \
+ F(Bool, bool_value) \
+ F(String, 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(Instr) - 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(Instr::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 Instr *) code; goto *instr->common.code;
+# define QML_V4_INSTR_HEADER void *code;
+#else
+# define QML_V4_BEGIN_INSTR(I,FMT) case Instr::I:
+# define QML_V4_END_INSTR(I,FMT) code += QML_V4_INSTR_SIZE(I, FMT); instr = (const Instr *) code; break;
+# define QML_V4_INSTR_HEADER
+#endif
+
+namespace QDeclarativeJS {
+
+union Instr {
+ int size() const;
+ void dump(int = -1) const;
+ void noop();
+ void load_root(quint8 reg);
+ void load_scope(quint8 reg);
+ void load_id(quint8 reg, quint32 idIndex);
+ void subscribe(qint8 reg, quint16 offset, quint32 index);
+ void subscribeId(qint8 reg, quint16 offset, quint32 index);
+ void move_reg_bool(quint8 reg, bool value);
+ void move_reg_int(quint8 reg, int value);
+ void move_reg_qreal(quint8 reg, qreal value);
+ void move_reg_reg(quint8 reg, quint8 src);
+
+ void unary_not(quint8 dest, quint8 src);
+ void uminus_real(quint8 dest, quint8 src);
+ void uminus_int(quint8 dest, quint8 src);
+ void uplus_real(quint8 dest, quint8 src);
+ void uplus_int(quint8 dest, quint8 src);
+ void ucompl_real(quint8 dest, quint8 src);
+ void ucompl_int(quint8 dest, quint8 src);
+
+ void math_sin_real(quint8 reg);
+ void math_cos_real(quint8 reg);
+ void math_round_real(quint8 reg);
+ void math_floor_real(quint8 reg);
+ void math_pi_real(quint8 reg);
+ void branch_true(quint8 reg, qint16 offset);
+ void branch_false(quint8 reg, qint16 offset);
+ void branch(qint16 offset);
+ void block(quint32 mask);
+
+ enum {
+ FOR_EACH_V4_INSTR(QML_V4_INSTR_ENUM)
+ };
+
+ struct instr_common {
+ QML_V4_INSTR_HEADER
+ quint8 type;
+ };
+
+ struct instr_id {
+ QML_V4_INSTR_HEADER
+ quint8 type;
+ quint16 column;
+ quint32 line;
+ };
+
+ struct instr_init {
+ QML_V4_INSTR_HEADER
+ quint8 type;
+ quint16 subscriptions;
+ quint16 identifiers;
+ };
+
+ struct instr_subscribeop {
+ QML_V4_INSTR_HEADER
+ quint8 type;
+ qint8 reg;
+ quint16 offset;
+ quint32 index;
+ };
+
+ struct instr_load {
+ QML_V4_INSTR_HEADER
+ quint8 type;
+ qint8 reg;
+ quint32 index;
+ };
+
+ struct instr_attached {
+ QML_V4_INSTR_HEADER
+ quint8 type;
+ qint8 output;
+ qint8 reg;
+ quint8 exceptionId;
+ quint32 id;
+ };
+
+ struct instr_store {
+ QML_V4_INSTR_HEADER
+ quint8 type;
+ qint8 output;
+ qint8 reg;
+ quint8 exceptionId;
+ quint32 index;
+ };
+
+ struct instr_storetest {
+ QML_V4_INSTR_HEADER
+ quint8 type;
+ qint8 reg;
+ qint32 regType;
+ };
+
+ struct instr_fetchAndSubscribe {
+ QML_V4_INSTR_HEADER
+ quint8 type;
+ qint8 reg;
+ quint8 exceptionId;
+ quint8 valueType;
+ quint16 subscription;
+ quint16 function;
+ };
+
+ struct instr_fetch{
+ QML_V4_INSTR_HEADER
+ quint8 type;
+ qint8 reg;
+ quint8 exceptionId;
+ quint8 valueType;
+ quint32 index;
+ };
+
+ struct instr_copy {
+ QML_V4_INSTR_HEADER
+ quint8 type;
+ qint8 reg;
+ qint8 src;
+ };
+
+ struct instr_construct {
+ QML_V4_INSTR_HEADER
+ quint8 type;
+ qint8 reg;
+ };
+
+ struct instr_real_value {
+ QML_V4_INSTR_HEADER
+ quint8 type;
+ qint8 reg;
+ qreal value; // XXX Makes the instruction 12 bytes
+ };
+
+ struct instr_int_value {
+ QML_V4_INSTR_HEADER
+ quint8 type;
+ qint8 reg;
+ int value;
+ };
+
+ struct instr_bool_value {
+ QML_V4_INSTR_HEADER
+ quint8 type;
+ qint8 reg;
+ bool value;
+ };
+
+ struct instr_string_value {
+ QML_V4_INSTR_HEADER
+ quint8 type;
+ qint8 reg;
+ quint16 length;
+ quint32 offset;
+ };
+
+ struct instr_binaryop {
+ QML_V4_INSTR_HEADER
+ quint8 type;
+ qint8 output;
+ qint8 left;
+ qint8 right;
+ };
+
+ struct instr_unaryop {
+ QML_V4_INSTR_HEADER
+ quint8 type;
+ qint8 output;
+ qint8 src;
+ };
+
+ struct instr_jump {
+ QML_V4_INSTR_HEADER
+ quint8 type;
+ qint8 reg;
+ quint32 count;
+ };
+
+ struct instr_find {
+ QML_V4_INSTR_HEADER
+ quint8 type;
+ qint8 reg;
+ qint8 src;
+ quint8 exceptionId;
+ quint16 name;
+ quint16 subscribeIndex;
+ };
+
+ struct instr_cleanup {
+ QML_V4_INSTR_HEADER
+ quint8 type;
+ qint8 reg;
+ };
+
+ struct instr_initstring {
+ QML_V4_INSTR_HEADER
+ quint8 type;
+ quint16 offset;
+ quint32 dataIdx;
+ };
+
+ struct instr_branchop {
+ QML_V4_INSTR_HEADER
+ quint8 type;
+ quint8 reg;
+ qint16 offset;
+ };
+
+ struct instr_blockop {
+ QML_V4_INSTR_HEADER
+ quint8 type;
+ 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;
+};
+
+class Bytecode
+{
+ Q_DISABLE_COPY(Bytecode)
+
+public:
+ Bytecode();
+
+ QByteArray code() const { return d; }
+ 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(); }
+ void append(const Instr &instr);
+ void append(const QVector<Instr> &instrs);
+ int remove(int index);
+
+ const Instr &operator[](int offset) const;
+ Instr &operator[](int offset);
+
+private:
+ QByteArray d;
+#ifdef QML_THREADED_INTERPRETER
+ void **decodeInstr;
+#endif
+};
+
+}
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QDECLARATIVEV4INSTRUCTION_P_H
+
diff --git a/src/declarative/qml/v4/qdeclarativev4ir.cpp b/src/declarative/qml/v4/qdeclarativev4ir.cpp
new file mode 100644
index 0000000000..7876e6ccea
--- /dev/null
+++ b/src/declarative/qml/v4/qdeclarativev4ir.cpp
@@ -0,0 +1,832 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qdeclarativev4ir_p.h"
+
+#include <QtCore/qtextstream.h>
+#include <QtCore/qdebug.h>
+#include <math.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace QDeclarativeJS {
+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 AnchorLineType: return "AnchorLine";
+ 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";
+ }
+}
+
+IR::Type maxType(IR::Type left, IR::Type right)
+{
+ if (left == right)
+ return left;
+ else if (left >= IR::FirstNumberType && right >= IR::FirstNumberType)
+ return qMax(left, right);
+ else if ((left >= IR::FirstNumberType && right == IR::StringType) ||
+ (right >= IR::FirstNumberType && left == IR::StringType))
+ 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 QString &s)
+{
+ QString r;
+ foreach (const QChar &ch, s) {
+ 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;
+}
+
+Name::Name(Name *base, Type type, const QString &id, Symbol symbol, quint32 line, quint32 column)
+: Expr(type)
+ , base(base)
+ , id(id)
+ , symbol(symbol)
+ , ptr(0)
+ , index(-1)
+ , storage(MemberStorage)
+ , builtin(NoBuiltinSymbol)
+ , line(line)
+ , 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;
+ 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 (int i = 0; i < args.size(); ++i) {
+ if (i)
+ out << ", ";
+ args.at(i)->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);
+ qDeleteAll(temps);
+}
+
+BasicBlock *Function::newBasicBlock()
+{
+ const int index = basicBlocks.size();
+ return i(new BasicBlock(this, index));
+}
+
+void Function::dump(QTextStream &out)
+{
+ QString fname;
+ if (name)
+ fname = name->asString();
+ else
+ fname = QLatin1String("$anonymous");
+ out << "function " << fname << "() {" << endl;
+ foreach (BasicBlock *bb, basicBlocks) {
+ bb->dump(out);
+ }
+ out << '}' << endl;
+}
+
+Temp *BasicBlock::TEMP(Type type, int index)
+{
+ return function->e(new Temp(type, index));
+}
+
+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)
+{
+ return function->e(new Const(type, value));
+}
+
+Expr *BasicBlock::STRING(const QString &value)
+{
+ return function->e(new String(value));
+}
+
+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)
+{
+ return function->e(new Name(base, InvalidType, id, Name::Unbound, line, column));
+}
+
+Name *BasicBlock::SYMBOL(Type type, const QString &id, const QMetaObject *meta, int index, Name::Storage storage,
+ quint32 line, quint32 column)
+{
+ Name *name = SYMBOL(/*base = */ 0, type, id, meta, index, line, column);
+ name->storage = storage;
+ return name;
+}
+
+Name *BasicBlock::SYMBOL(Name *base, Type type, const QString &id, const QMetaObject *meta, int index, Name::Storage storage,
+ quint32 line, quint32 column)
+{
+ Name *name = new Name(base, type, id, Name::Property, line, column);
+ name->meta = meta;
+ name->index = index;
+ name->storage = storage;
+ return function->e(name);
+}
+
+Name *BasicBlock::SYMBOL(Name *base, Type type, const QString &id, const QMetaObject *meta, int index,
+ quint32 line, quint32 column)
+{
+ Name *name = new Name(base, type, id, Name::Property, line, column);
+ name->meta = meta;
+ name->index = index;
+ return function->e(name);
+}
+
+Name *BasicBlock::ID_OBJECT(const QString &id, const QDeclarativeParser::Object *object, quint32 line, quint32 column)
+{
+ Name *name = new Name(/*base = */ 0, IR::ObjectType, id, Name::IdObject, line, column);
+ name->idObject = object;
+ name->index = object->idIndex;
+ name->storage = Name::IdStorage;
+ return function->e(name);
+}
+
+Name *BasicBlock::ATTACH_TYPE(const QString &id, const QDeclarativeType *attachType, Name::Storage storage,
+ quint32 line, quint32 column)
+{
+ Name *name = new Name(/*base = */ 0, IR::AttachType, id, Name::AttachType, line, column);
+ name->declarativeType = attachType;
+ name->storage = storage;
+ return function->e(name);
+}
+
+
+Expr *BasicBlock::UNOP(AluOp op, Expr *expr)
+{
+ return function->e(new Unop(op, expr));
+}
+
+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;
+ }
+ }
+ }
+ }
+
+ return function->e(new Binop(op, left, right));
+}
+
+Expr *BasicBlock::CALL(Expr *base, const QVector<Expr *> &args)
+{
+ return function->e(new Call(base, args));
+}
+
+Stmt *BasicBlock::EXP(Expr *expr)
+{
+ return i(new Exp(expr));
+}
+
+Stmt *BasicBlock::MOVE(Expr *target, Expr *source, bool isMoveForReturn)
+{
+ return i(new Move(target, source, isMoveForReturn));
+}
+
+Stmt *BasicBlock::JUMP(BasicBlock *target)
+{
+ if (isTerminated())
+ return 0;
+ else
+ return i(new Jump(target));
+}
+
+Stmt *BasicBlock::CJUMP(Expr *cond, BasicBlock *iftrue, BasicBlock *iffalse)
+{
+ if (isTerminated())
+ return 0;
+ return i(new CJump(cond, iftrue, iffalse));
+}
+
+Stmt *BasicBlock::RET(Expr *expr, Type type, quint32 line, quint32 column)
+{
+ if (isTerminated())
+ return 0;
+ else
+ return i(new Ret(expr, type, line, column));
+}
+
+void BasicBlock::dump(QTextStream &out)
+{
+ out << 'L' << this << ':' << endl;
+ foreach (Stmt *s, statements) {
+ out << '\t';
+ s->dump(out);
+ out << endl;
+ }
+}
+
+void Module::dump(QTextStream &out)
+{
+ foreach (Function *fun, functions) {
+ fun->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(QDeclarativeJS::IR::Expr *e)
+{
+ inc();
+
+ e->accept(this);
+
+ dec();
+}
+
+void IRDump::basicblock(QDeclarativeJS::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(QDeclarativeJS::IR::Stmt *s)
+{
+ inc();
+
+ s->accept(this);
+
+ dec();
+}
+
+void IRDump::function(QDeclarativeJS::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(QDeclarativeJS::IR::Const *e)
+{
+ qWarning().nospace() << indent() << "Const:Expr { type: " << typeName(e->type) << ", value: " << e->value << "}";
+}
+
+void IRDump::visitString(QDeclarativeJS::IR::String *e)
+{
+ qWarning().nospace() << indent() << "String:Expr { type: " << typeName(e->type) << ", value: " << e->value << "}";
+}
+
+static void namedumprecur(QDeclarativeJS::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(QDeclarativeJS::IR::Name *e)
+{
+ qWarning().nospace() << indent() << "Name:Expr {";
+ namedumprecur(e, indent());
+ qWarning().nospace() << indent() << "}";
+}
+
+void IRDump::visitTemp(QDeclarativeJS::IR::Temp *e)
+{
+ qWarning().nospace() << indent() << "Temp:Expr { type: " << typeName(e->type) << ", index: " << e->index << " }";
+}
+
+void IRDump::visitUnop(QDeclarativeJS::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(QDeclarativeJS::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(QDeclarativeJS::IR::Call *e)
+{
+ Q_UNUSED(e);
+ qWarning().nospace() << indent() << "Exp::Call { }";
+}
+
+void IRDump::visitExp(QDeclarativeJS::IR::Exp *s)
+{
+ qWarning().nospace() << indent() << "Exp:Stmt {";
+ expression(s->expr);
+ qWarning().nospace() << indent() << "}";
+}
+
+void IRDump::visitMove(QDeclarativeJS::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(QDeclarativeJS::IR::Jump *s)
+{
+ qWarning().nospace() << indent() << "Jump:Stmt { BasicBlock(" << s->target << ") }";
+}
+
+void IRDump::visitCJump(QDeclarativeJS::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(QDeclarativeJS::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 QDeclarativeJS
+
+QT_END_NAMESPACE
diff --git a/src/declarative/qml/v4/qdeclarativev4ir_p.h b/src/declarative/qml/v4/qdeclarativev4ir_p.h
new file mode 100644
index 0000000000..93815e9154
--- /dev/null
+++ b/src/declarative/qml/v4/qdeclarativev4ir_p.h
@@ -0,0 +1,546 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVEV4IR_P_H
+#define QDECLARATIVEV4IR_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/qdeclarativejsast_p.h>
+#include <private/qdeclarativejsengine_p.h>
+#include <private/qdeclarativeparser_p.h>
+#include <private/qdeclarativeimport_p.h>
+#include <private/qdeclarativeengine_p.h>
+#include <private/qdeclarativev4compiler_p.h>
+
+#include <QtCore/qvector.h>
+
+// #define DEBUG_IR_STRUCTURE
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class QTextStream;
+class QDeclarativeType;
+
+namespace QDeclarativeJS {
+
+namespace IR {
+
+struct BasicBlock;
+struct Function;
+struct Module;
+
+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,
+ AnchorLineType,
+ 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 {
+ Type type;
+
+ Expr(Type type): type(type) {}
+ 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 Const: Expr {
+ double value;
+ Const(Type type, double value): Expr(type), value(value) {}
+
+ virtual void accept(ExprVisitor *v) { v->visitConst(this); }
+ virtual Const *asConst() { return this; }
+
+ virtual void dump(QTextStream &out);
+};
+
+struct String: Expr {
+ QString value;
+ String(const QString &value): Expr(StringType), value(value) {}
+
+ virtual void accept(ExprVisitor *v) { v->visitString(this); }
+ virtual String *asString() { return this; }
+
+ virtual void dump(QTextStream &out);
+ static QString escape(const QString &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;
+ QString id;
+ Symbol symbol;
+ union {
+ void *ptr;
+ const QMetaObject *meta;
+ const QDeclarativeType *declarativeType;
+ const QDeclarativeParser::Object *idObject;
+ };
+ int index;
+ Storage storage;
+ BuiltinSymbol builtin;
+ quint32 line;
+ quint32 column;
+
+ Name(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;
+ Temp(Type type, int index): Expr(type), 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;
+
+ Unop(AluOp op, Expr *expr)
+ : Expr(typeForOp(op, expr)), op(op), 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;
+ Binop(AluOp op, Expr *left, Expr *right)
+ : Expr(typeForOp(op, left, right)), op(op), left(left), 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;
+ QVector<Expr *> args;
+
+ Call(Expr *base, const QVector<Expr *> &args)
+ : Expr(typeForFunction(base)), base(base), args(args) {}
+
+ 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 {
+ 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;
+ Exp(Expr *expr): 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;
+ Move(Expr *target, Expr *source, bool isMoveForReturn): target(target), source(source), 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;
+ Jump(BasicBlock *target): 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;
+ CJump(Expr *cond, BasicBlock *iftrue, BasicBlock *iffalse)
+ : cond(cond), iftrue(iftrue), 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;
+ Ret(Expr *expr, Type type, quint32 line, quint32 column): expr(expr), type(type), line(line), 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 {
+ Module *module;
+ const NameId *name;
+ int tempCount;
+ QVector<BasicBlock *> basicBlocks;
+ QVector<Expr *> temps;
+
+ template <typename BB> inline BB i(BB i) { basicBlocks.append(i); return i; }
+ template <typename E> inline E e(E e) { temps.append(e); return e; }
+
+ Function(Module *module, const NameId *name = 0): module(module), name(name), tempCount(0) {}
+ ~Function();
+
+ BasicBlock *newBasicBlock();
+
+ virtual void dump(QTextStream &out);
+};
+
+struct BasicBlock {
+ Function *function;
+ int index;
+ QVector<Stmt *> statements;
+ int offset;
+
+ BasicBlock(Function *function, int index): function(function), index(index), offset(-1) {}
+ ~BasicBlock() { qDeleteAll(statements); }
+
+ 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.last()->asTerminator() != 0)
+ return statements.last();
+ 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 QString &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, int index, Name::Storage storage, quint32 line, quint32 column);
+ Name *SYMBOL(Name *base, Type type, const QString &id, const QMetaObject *meta, int index, quint32 line, quint32 column);
+ Name *SYMBOL(Name *base, Type type, const QString &id, const QMetaObject *meta, int index, Name::Storage storage, quint32 line, quint32 column);
+ Name *ID_OBJECT(const QString &id, const QDeclarativeParser::Object *object, quint32 line, quint32 column);
+ Name *ATTACH_TYPE(const QString &id, const QDeclarativeType *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, const QVector<Expr *> &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);
+};
+
+struct Module {
+ QVector<Function *> functions;
+
+ Module() {}
+ ~Module() { qDeleteAll(functions); }
+
+ template <typename BB> inline BB i(BB i) { functions.append(i); return i; }
+
+ Function *newFunction(const NameId *name = 0) { return i(new Function(this, name)); }
+
+ virtual void dump(QTextStream &out);
+};
+
+#ifdef DEBUG_IR_STRUCTURE
+struct IRDump : public ExprVisitor,
+ public StmtVisitor
+{
+public:
+ IRDump();
+
+ void expression(QDeclarativeJS::IR::Expr *);
+ void basicblock(QDeclarativeJS::IR::BasicBlock *);
+ void statement(QDeclarativeJS::IR::Stmt *);
+ void function(QDeclarativeJS::IR::Function *);
+protected:
+
+ const char *indent();
+
+ //
+ // expressions
+ //
+ virtual void visitConst(QDeclarativeJS::IR::Const *e);
+ virtual void visitString(QDeclarativeJS::IR::String *e);
+ virtual void visitName(QDeclarativeJS::IR::Name *e);
+ virtual void visitTemp(QDeclarativeJS::IR::Temp *e);
+ virtual void visitUnop(QDeclarativeJS::IR::Unop *e);
+ virtual void visitBinop(QDeclarativeJS::IR::Binop *e);
+ virtual void visitCall(QDeclarativeJS::IR::Call *e);
+
+ //
+ // statements
+ //
+ virtual void visitExp(QDeclarativeJS::IR::Exp *s);
+ virtual void visitMove(QDeclarativeJS::IR::Move *s);
+ virtual void visitJump(QDeclarativeJS::IR::Jump *s);
+ virtual void visitCJump(QDeclarativeJS::IR::CJump *s);
+ virtual void visitRet(QDeclarativeJS::IR::Ret *s);
+
+private:
+ int indentSize;
+ QByteArray indentData;
+ void inc();
+ void dec();
+};
+#endif
+
+} // end of namespace IR
+
+} // end of namespace QDeclarativeJS
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QDECLARATIVEV4IR_P_H
diff --git a/src/declarative/qml/v4/qdeclarativev4irbuilder.cpp b/src/declarative/qml/v4/qdeclarativev4irbuilder.cpp
new file mode 100644
index 0000000000..103d5ba0df
--- /dev/null
+++ b/src/declarative/qml/v4/qdeclarativev4irbuilder.cpp
@@ -0,0 +1,1315 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qdeclarativev4irbuilder_p.h"
+
+#include <private/qdeclarativeglobalscriptclass_p.h> // For illegalNames
+#include <private/qdeclarativeanchors_p_p.h> // For AnchorLine
+#include <private/qsganchors_p_p.h> // For AnchorLine
+#include <private/qdeclarativetypenamecache_p.h>
+
+DEFINE_BOOL_CONFIG_OPTION(qmlVerboseCompiler, QML_VERBOSE_COMPILER)
+
+QT_BEGIN_NAMESPACE
+
+using namespace QDeclarativeJS;
+
+static IR::Type irTypeFromVariantType(int t, QDeclarativeEnginePrivate *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 == qMetaTypeId<QDeclarativeAnchorLine>())
+ return IR::AnchorLineType;
+ else if (t == qMetaTypeId<QSGAnchorLine>())
+ return IR::SGAnchorLineType;
+ else if (const QMetaObject *m = engine->metaObjectForType(t)) {
+ meta = m;
+ return IR::ObjectType;
+ }
+
+ return IR::InvalidType;
+ }
+}
+
+QDeclarativeV4IRBuilder::QDeclarativeV4IRBuilder(const QDeclarativeV4Compiler::Expression *expr,
+ QDeclarativeEnginePrivate *engine)
+: m_expression(expr), m_engine(engine), _module(0), _function(0), _block(0), _discard(false)
+{
+}
+
+QDeclarativeJS::IR::Function *
+QDeclarativeV4IRBuilder::operator()(QDeclarativeJS::IR::Module *module,
+ QDeclarativeJS::AST::Node *ast)
+{
+ bool discarded = false;
+
+ qSwap(_module, module);
+
+ IR::Function *function = _module->newFunction();
+ 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);
+
+ qSwap(_module, module);
+
+ return discarded?0:function;
+}
+
+bool QDeclarativeV4IRBuilder::buildName(QStringList &name,
+ AST::Node *node,
+ QList<AST::ExpressionNode *> *nodes)
+{
+ if (node->kind == AST::Node::Kind_IdentifierExpression) {
+ name << static_cast<AST::IdentifierExpression*>(node)->name->asString();
+ 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->asString();
+ if (nodes) *nodes << expr;
+ } else {
+ return false;
+ }
+
+ return true;
+}
+
+void QDeclarativeV4IRBuilder::discard()
+{
+ _discard = true;
+}
+
+QDeclarativeV4IRBuilder::ExprResult
+QDeclarativeV4IRBuilder::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 QDeclarativeV4IRBuilder::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);
+ }
+}
+
+QDeclarativeV4IRBuilder::ExprResult
+QDeclarativeV4IRBuilder::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 QDeclarativeV4IRBuilder::sourceElement(AST::SourceElement *ast)
+{
+ accept(ast);
+}
+
+void QDeclarativeV4IRBuilder::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 QDeclarativeV4IRBuilder::visit(AST::UiProgram *)
+{
+ Q_ASSERT(!"unreachable");
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::UiImportList *)
+{
+ Q_ASSERT(!"unreachable");
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::UiImport *)
+{
+ Q_ASSERT(!"unreachable");
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::UiPublicMember *)
+{
+ Q_ASSERT(!"unreachable");
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::UiSourceElement *)
+{
+ Q_ASSERT(!"unreachable");
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::UiObjectDefinition *)
+{
+ Q_ASSERT(!"unreachable");
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::UiObjectInitializer *)
+{
+ Q_ASSERT(!"unreachable");
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::UiObjectBinding *)
+{
+ Q_ASSERT(!"unreachable");
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::UiScriptBinding *)
+{
+ Q_ASSERT(!"unreachable");
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::UiArrayBinding *)
+{
+ Q_ASSERT(!"unreachable");
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::UiObjectMemberList *)
+{
+ Q_ASSERT(!"unreachable");
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::UiArrayMemberList *)
+{
+ Q_ASSERT(!"unreachable");
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::UiQualifiedId *)
+{
+ Q_ASSERT(!"unreachable");
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::UiSignature *)
+{
+ Q_ASSERT(!"unreachable");
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::UiFormalList *)
+{
+ Q_ASSERT(!"unreachable");
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::UiFormal *)
+{
+ Q_ASSERT(!"unreachable");
+ return false;
+}
+
+
+// JS
+bool QDeclarativeV4IRBuilder::visit(AST::Program *ast)
+{
+ _function = _module->newFunction();
+ _block = _function->newBasicBlock();
+ accept(ast->elements);
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::SourceElements *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::FunctionSourceElement *)
+{
+ return true; // look inside
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::StatementSourceElement *)
+{
+ return true; // look inside
+}
+
+// object literals
+bool QDeclarativeV4IRBuilder::visit(AST::PropertyNameAndValueList *)
+{
+ Q_ASSERT(!"unreachable");
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::IdentifierPropertyName *)
+{
+ Q_ASSERT(!"unreachable");
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::StringLiteralPropertyName *)
+{
+ Q_ASSERT(!"unreachable");
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::NumericLiteralPropertyName *)
+{
+ Q_ASSERT(!"unreachable");
+ return false;
+}
+
+
+// array literals
+bool QDeclarativeV4IRBuilder::visit(AST::ElementList *)
+{
+ Q_ASSERT(!"unreachable");
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::Elision *)
+{
+ Q_ASSERT(!"unreachable");
+ return false;
+}
+
+
+// function calls
+bool QDeclarativeV4IRBuilder::visit(AST::ArgumentList *)
+{
+ Q_ASSERT(!"unreachable");
+ return false;
+}
+
+// expressions
+bool QDeclarativeV4IRBuilder::visit(AST::ObjectLiteral *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::ArrayLiteral *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::ThisExpression *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::IdentifierExpression *ast)
+{
+ const quint32 line = ast->identifierToken.startLine;
+ const quint32 column = ast->identifierToken.startColumn;
+
+ const QString name = ast->name->asString();
+
+ 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->globalClass->illegalNames().contains(name) ) {
+ if (qmlVerboseCompiler()) qWarning() << "*** illegal symbol:" << name;
+ return false;
+ } else if (const QDeclarativeParser::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 if (QDeclarativeTypeNameCache::Data *typeNameData = m_expression->importCache->data(name)) {
+ if (typeNameData->importedScriptIndex != -1) {
+ // We don't support invoking imported scripts
+ } else if (typeNameData->type) {
+ _expr.code = _block->ATTACH_TYPE(name, typeNameData->type, IR::Name::ScopeStorage, line, column);
+ } else if (typeNameData->typeNamespace) {
+ // We don't support namespaces
+ } else {
+ Q_ASSERT(!"Unreachable");
+ }
+ } 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
+ QDeclarativePropertyCache *cache = m_expression->context->synthCache;
+ const QMetaObject *metaObject = m_expression->context->metaObject();
+ if (!cache) cache = m_engine->cache(metaObject);
+
+ QDeclarativePropertyCache::Data *data = cache->property(name);
+
+ if (data && data->revision != 0) {
+ if (qmlVerboseCompiler())
+ qWarning() << "*** versioned symbol:" << name;
+ discard();
+ return false;
+ }
+
+ if (data && !(data->flags & QDeclarativePropertyCache::Data::IsFunction)) {
+ IR::Type irType = irTypeFromVariantType(data->propType, m_engine, metaObject);
+ _expr.code = _block->SYMBOL(irType, name, metaObject, data->coreIndex, IR::Name::ScopeStorage, line, column);
+ found = true;
+ }
+ }
+
+ if (!found) {
+ QDeclarativePropertyCache *cache = m_expression->component->synthCache;
+ const QMetaObject *metaObject = m_expression->component->metaObject();
+ if (!cache) cache = m_engine->cache(metaObject);
+
+ QDeclarativePropertyCache::Data *data = cache->property(name);
+
+ if (data && data->revision != 0) {
+ if (qmlVerboseCompiler())
+ qWarning() << "*** versioned symbol:" << name;
+ discard();
+ return false;
+ }
+
+ if (data && !(data->flags & QDeclarativePropertyCache::Data::IsFunction)) {
+ IR::Type irType = irTypeFromVariantType(data->propType, m_engine, metaObject);
+ _expr.code = _block->SYMBOL(irType, name, metaObject, data->coreIndex, 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 QDeclarativeV4IRBuilder::visit(AST::NullExpression *)
+{
+ // ### TODO: cx format
+ _expr.code = _block->CONST(IR::NullType, 0);
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::TrueLiteral *)
+{
+ // ### TODO: cx format
+ _expr.code = _block->CONST(IR::BoolType, 1);
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::FalseLiteral *)
+{
+ // ### TODO: cx format
+ _expr.code = _block->CONST(IR::BoolType, 0);
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::StringLiteral *ast)
+{
+ // ### TODO: cx format
+ _expr.code = _block->STRING(ast->value->asString());
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::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 QDeclarativeV4IRBuilder::visit(AST::RegExpLiteral *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::NestedExpression *)
+{
+ return true; // the value of the nested expression
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::ArrayMemberExpression *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::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->asString();
+
+ 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->asString());
+ } else if(const QMetaObject *attachedMeta = baseName->declarativeType->attachedPropertiesType()) {
+ QDeclarativePropertyCache *cache = m_engine->cache(attachedMeta);
+ QDeclarativePropertyCache::Data *data = cache->property(name);
+
+ if (!data || data->flags & QDeclarativePropertyCache::Data::IsFunction)
+ return false; // Don't support methods (or non-existing properties ;)
+
+ if(!(data->flags & QDeclarativePropertyCache::Data::IsFinal)) {
+ if (qmlVerboseCompiler())
+ qWarning() << "*** non-final attached property:"
+ << (baseName->id + QLatin1String(".") + ast->name->asString());
+ 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->coreIndex, line, column);
+ }
+ break;
+
+ case IR::Name::IdObject: {
+ const QDeclarativeParser::Object *idObject = baseName->idObject;
+ QDeclarativePropertyCache *cache =
+ idObject->synthCache?idObject->synthCache:m_engine->cache(idObject->metaObject());
+
+ QDeclarativePropertyCache::Data *data = cache->property(name);
+
+ if (!data || data->flags & QDeclarativePropertyCache::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->coreIndex, line, column);
+ }
+ break;
+
+ case IR::Name::Property:
+ if (baseName->type == IR::ObjectType) {
+ const QMetaObject *m =
+ m_engine->metaObjectForType(baseName->meta->property(baseName->index).userType());
+ QDeclarativePropertyCache *cache = m_engine->cache(m);
+
+ QDeclarativePropertyCache::Data *data = cache->property(name);
+
+ if (!data || data->flags & QDeclarativePropertyCache::Data::IsFunction)
+ return false; // Don't support methods (or non-existing properties ;)
+
+ if(!(data->flags & QDeclarativePropertyCache::Data::IsFinal)) {
+ if (qmlVerboseCompiler())
+ qWarning() << "*** non-final property access:"
+ << (baseName->id + QLatin1String(".") + ast->name->asString());
+ 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->coreIndex, line, column);
+ }
+ break;
+
+ case IR::Name::Object:
+ case IR::Name::Slot:
+ break;
+ }
+ }
+ }
+
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::NewMemberExpression *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::NewExpression *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::CallExpression *ast)
+{
+ QStringList names;
+ QList<AST::ExpressionNode *> nameNodes;
+ if (buildName(names, ast->base, &nameNodes)) {
+ //ExprResult base = expression(ast->base);
+ const QString id = names.join(QLatin1String("."));
+ const quint32 line = nameNodes.last()->firstSourceLocation().startLine;
+ const quint32 column = nameNodes.last()->firstSourceLocation().startColumn;
+ IR::Expr *base = _block->NAME(id, line, column);
+
+ QVector<IR::Expr *> args;
+ for (AST::ArgumentList *it = ast->arguments; it; it = it->next)
+ args.append(expression(it->expression));
+
+ 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 QDeclarativeV4IRBuilder::visit(AST::PostIncrementExpression *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::PostDecrementExpression *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::DeleteExpression *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::VoidExpression *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::TypeOfExpression *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::PreIncrementExpression *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::PreDecrementExpression *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::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 QDeclarativeV4IRBuilder::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 QDeclarativeV4IRBuilder::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 QDeclarativeV4IRBuilder::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 QDeclarativeV4IRBuilder::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 QDeclarativeV4IRBuilder::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);
+
+ 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 QDeclarativeV4IRBuilder::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 QDeclarativeV4IRBuilder::visit(AST::Expression *ast)
+{
+ _block->EXP(expression(ast->left));
+ _expr = expression(ast->right);
+
+ return false;
+}
+
+
+// statements
+bool QDeclarativeV4IRBuilder::visit(AST::Block *ast)
+{
+ if (ast->statements && ! ast->statements->next) {
+ // we have one and only one statement
+ accept(ast->statements->statement);
+ }
+
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::StatementList *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::VariableStatement *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::VariableDeclarationList *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::VariableDeclaration *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::EmptyStatement *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::ExpressionStatement *ast)
+{
+ if (ast->expression) {
+ // return the value of this expression
+ return true;
+ }
+
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::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 QDeclarativeV4IRBuilder::visit(AST::DoWhileStatement *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::WhileStatement *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::ForStatement *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::LocalForStatement *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::ForEachStatement *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::LocalForEachStatement *)
+{
+ discard();
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::ContinueStatement *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::BreakStatement *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::ReturnStatement *ast)
+{
+ if (ast->expression) {
+ // return the value of the expression
+ return true;
+ }
+
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::WithStatement *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::SwitchStatement *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::CaseBlock *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::CaseClauses *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::CaseClause *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::DefaultClause *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::LabelledStatement *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::ThrowStatement *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::TryStatement *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::Catch *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::Finally *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::FunctionDeclaration *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::FunctionExpression *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::FormalParameterList *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::FunctionBody *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::DebuggerStatement *)
+{
+ return false;
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/qml/v4/qdeclarativev4irbuilder_p.h b/src/declarative/qml/v4/qdeclarativev4irbuilder_p.h
new file mode 100644
index 0000000000..f0bfd6624c
--- /dev/null
+++ b/src/declarative/qml/v4/qdeclarativev4irbuilder_p.h
@@ -0,0 +1,242 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVEV4IRBUILDER_P_H
+#define QDECLARATIVEV4IRBUILDER_P_H
+
+#include <QtCore/qglobal.h>
+
+#include "qdeclarativev4ir_p.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativeV4IRBuilder : public QDeclarativeJS::AST::Visitor
+{
+public:
+ QDeclarativeV4IRBuilder(const QDeclarativeV4Compiler::Expression *, QDeclarativeEnginePrivate *);
+
+ QDeclarativeJS::IR::Function *operator()(QDeclarativeJS::IR::Module *, QDeclarativeJS::AST::Node *);
+
+protected:
+ struct ExprResult {
+ enum Format {
+ ex, // expression
+ cx // condition
+ };
+
+ QDeclarativeJS::IR::Expr *code;
+ QDeclarativeJS::IR::BasicBlock *iftrue;
+ QDeclarativeJS::IR::BasicBlock *iffalse;
+ Format hint; // requested format
+ Format format; // instruction format
+
+ ExprResult(QDeclarativeJS::IR::Expr *expr = 0)
+ : code(expr), iftrue(0), iffalse(0), hint(ex), format(ex) {}
+
+ ExprResult(QDeclarativeJS::IR::BasicBlock *iftrue, QDeclarativeJS::IR::BasicBlock *iffalse)
+ : code(0), iftrue(iftrue), iffalse(iffalse), hint(cx), format(ex) {}
+
+ inline QDeclarativeJS::IR::Type type() const { return code ? code->type : QDeclarativeJS::IR::InvalidType; }
+
+ inline QDeclarativeJS::IR::Expr *get() const { return code; }
+ inline operator QDeclarativeJS::IR::Expr *() const { return get(); }
+ inline QDeclarativeJS::IR::Expr *operator->() const { return get(); }
+ inline bool isValid() const { return code ? code->type != QDeclarativeJS::IR::InvalidType : false; }
+ inline bool is(QDeclarativeJS::IR::Type t) const { return type() == t; }
+ inline bool isNot(QDeclarativeJS::IR::Type t) const { return type() != t; }
+
+ bool isPrimitive() const {
+ switch (type()) {
+ case QDeclarativeJS::IR::UndefinedType: // ### TODO
+ case QDeclarativeJS::IR::NullType: // ### TODO
+ case QDeclarativeJS::IR::UrlType: // ### TODO
+ return false;
+
+ case QDeclarativeJS::IR::StringType:
+ case QDeclarativeJS::IR::BoolType:
+ case QDeclarativeJS::IR::IntType:
+ case QDeclarativeJS::IR::RealType:
+ case QDeclarativeJS::IR::RealNaNType:
+ return true;
+
+ default:
+ return false;
+ } // switch
+ }
+ };
+
+ inline void accept(QDeclarativeJS::AST::Node *ast) { QDeclarativeJS::AST::Node::accept(ast, this); }
+
+ ExprResult expression(QDeclarativeJS::AST::ExpressionNode *ast);
+ ExprResult statement(QDeclarativeJS::AST::Statement *ast);
+ void sourceElement(QDeclarativeJS::AST::SourceElement *ast);
+ void condition(QDeclarativeJS::AST::ExpressionNode *ast, QDeclarativeJS::IR::BasicBlock *iftrue, QDeclarativeJS::IR::BasicBlock *iffalse);
+ void binop(QDeclarativeJS::AST::BinaryExpression *ast, ExprResult left, ExprResult right);
+
+ void implicitCvt(ExprResult &expr, QDeclarativeJS::IR::Type type);
+
+ // QML
+ virtual bool visit(QDeclarativeJS::AST::UiProgram *ast);
+ virtual bool visit(QDeclarativeJS::AST::UiImportList *ast);
+ virtual bool visit(QDeclarativeJS::AST::UiImport *ast);
+ virtual bool visit(QDeclarativeJS::AST::UiPublicMember *ast);
+ virtual bool visit(QDeclarativeJS::AST::UiSourceElement *ast);
+ virtual bool visit(QDeclarativeJS::AST::UiObjectDefinition *ast);
+ virtual bool visit(QDeclarativeJS::AST::UiObjectInitializer *ast);
+ virtual bool visit(QDeclarativeJS::AST::UiObjectBinding *ast);
+ virtual bool visit(QDeclarativeJS::AST::UiScriptBinding *ast);
+ virtual bool visit(QDeclarativeJS::AST::UiArrayBinding *ast);
+ virtual bool visit(QDeclarativeJS::AST::UiObjectMemberList *ast);
+ virtual bool visit(QDeclarativeJS::AST::UiArrayMemberList *ast);
+ virtual bool visit(QDeclarativeJS::AST::UiQualifiedId *ast);
+ virtual bool visit(QDeclarativeJS::AST::UiSignature *ast);
+ virtual bool visit(QDeclarativeJS::AST::UiFormalList *ast);
+ virtual bool visit(QDeclarativeJS::AST::UiFormal *ast);
+
+ // JS
+ virtual bool visit(QDeclarativeJS::AST::Program *ast);
+ virtual bool visit(QDeclarativeJS::AST::SourceElements *ast);
+ virtual bool visit(QDeclarativeJS::AST::FunctionSourceElement *ast);
+ virtual bool visit(QDeclarativeJS::AST::StatementSourceElement *ast);
+
+ // object literals
+ virtual bool visit(QDeclarativeJS::AST::PropertyNameAndValueList *ast);
+ virtual bool visit(QDeclarativeJS::AST::IdentifierPropertyName *ast);
+ virtual bool visit(QDeclarativeJS::AST::StringLiteralPropertyName *ast);
+ virtual bool visit(QDeclarativeJS::AST::NumericLiteralPropertyName *ast);
+
+ // array literals
+ virtual bool visit(QDeclarativeJS::AST::ElementList *ast);
+ virtual bool visit(QDeclarativeJS::AST::Elision *ast);
+
+ // function calls
+ virtual bool visit(QDeclarativeJS::AST::ArgumentList *ast);
+
+ // expressions
+ virtual bool visit(QDeclarativeJS::AST::ObjectLiteral *ast);
+ virtual bool visit(QDeclarativeJS::AST::ArrayLiteral *ast);
+ virtual bool visit(QDeclarativeJS::AST::ThisExpression *ast);
+ virtual bool visit(QDeclarativeJS::AST::IdentifierExpression *ast);
+ virtual bool visit(QDeclarativeJS::AST::NullExpression *ast);
+ virtual bool visit(QDeclarativeJS::AST::TrueLiteral *ast);
+ virtual bool visit(QDeclarativeJS::AST::FalseLiteral *ast);
+ virtual bool visit(QDeclarativeJS::AST::StringLiteral *ast);
+ virtual bool visit(QDeclarativeJS::AST::NumericLiteral *ast);
+ virtual bool visit(QDeclarativeJS::AST::RegExpLiteral *ast);
+ virtual bool visit(QDeclarativeJS::AST::NestedExpression *ast);
+ virtual bool visit(QDeclarativeJS::AST::ArrayMemberExpression *ast);
+ virtual bool visit(QDeclarativeJS::AST::FieldMemberExpression *ast);
+ virtual bool visit(QDeclarativeJS::AST::NewMemberExpression *ast);
+ virtual bool visit(QDeclarativeJS::AST::NewExpression *ast);
+ virtual bool visit(QDeclarativeJS::AST::CallExpression *ast);
+ virtual bool visit(QDeclarativeJS::AST::PostIncrementExpression *ast);
+ virtual bool visit(QDeclarativeJS::AST::PostDecrementExpression *ast);
+ virtual bool visit(QDeclarativeJS::AST::DeleteExpression *ast);
+ virtual bool visit(QDeclarativeJS::AST::VoidExpression *ast);
+ virtual bool visit(QDeclarativeJS::AST::TypeOfExpression *ast);
+ virtual bool visit(QDeclarativeJS::AST::PreIncrementExpression *ast);
+ virtual bool visit(QDeclarativeJS::AST::PreDecrementExpression *ast);
+ virtual bool visit(QDeclarativeJS::AST::UnaryPlusExpression *ast);
+ virtual bool visit(QDeclarativeJS::AST::UnaryMinusExpression *ast);
+ virtual bool visit(QDeclarativeJS::AST::TildeExpression *ast);
+ virtual bool visit(QDeclarativeJS::AST::NotExpression *ast);
+ virtual bool visit(QDeclarativeJS::AST::BinaryExpression *ast);
+ virtual bool visit(QDeclarativeJS::AST::ConditionalExpression *ast);
+ virtual bool visit(QDeclarativeJS::AST::Expression *ast);
+
+ // statements
+ virtual bool visit(QDeclarativeJS::AST::Block *ast);
+ virtual bool visit(QDeclarativeJS::AST::StatementList *ast);
+ virtual bool visit(QDeclarativeJS::AST::VariableStatement *ast);
+ virtual bool visit(QDeclarativeJS::AST::VariableDeclarationList *ast);
+ virtual bool visit(QDeclarativeJS::AST::VariableDeclaration *ast);
+ virtual bool visit(QDeclarativeJS::AST::EmptyStatement *ast);
+ virtual bool visit(QDeclarativeJS::AST::ExpressionStatement *ast);
+ virtual bool visit(QDeclarativeJS::AST::IfStatement *ast);
+ virtual bool visit(QDeclarativeJS::AST::DoWhileStatement *ast);
+ virtual bool visit(QDeclarativeJS::AST::WhileStatement *ast);
+ virtual bool visit(QDeclarativeJS::AST::ForStatement *ast);
+ virtual bool visit(QDeclarativeJS::AST::LocalForStatement *ast);
+ virtual bool visit(QDeclarativeJS::AST::ForEachStatement *ast);
+ virtual bool visit(QDeclarativeJS::AST::LocalForEachStatement *ast);
+ virtual bool visit(QDeclarativeJS::AST::ContinueStatement *ast);
+ virtual bool visit(QDeclarativeJS::AST::BreakStatement *ast);
+ virtual bool visit(QDeclarativeJS::AST::ReturnStatement *ast);
+ virtual bool visit(QDeclarativeJS::AST::WithStatement *ast);
+ virtual bool visit(QDeclarativeJS::AST::SwitchStatement *ast);
+ virtual bool visit(QDeclarativeJS::AST::CaseBlock *ast);
+ virtual bool visit(QDeclarativeJS::AST::CaseClauses *ast);
+ virtual bool visit(QDeclarativeJS::AST::CaseClause *ast);
+ virtual bool visit(QDeclarativeJS::AST::DefaultClause *ast);
+ virtual bool visit(QDeclarativeJS::AST::LabelledStatement *ast);
+ virtual bool visit(QDeclarativeJS::AST::ThrowStatement *ast);
+ virtual bool visit(QDeclarativeJS::AST::TryStatement *ast);
+ virtual bool visit(QDeclarativeJS::AST::Catch *ast);
+ virtual bool visit(QDeclarativeJS::AST::Finally *ast);
+ virtual bool visit(QDeclarativeJS::AST::FunctionDeclaration *ast);
+ virtual bool visit(QDeclarativeJS::AST::FunctionExpression *ast);
+ virtual bool visit(QDeclarativeJS::AST::FormalParameterList *ast);
+ virtual bool visit(QDeclarativeJS::AST::FunctionBody *ast);
+ virtual bool visit(QDeclarativeJS::AST::DebuggerStatement *ast);
+
+private:
+ bool buildName(QStringList &name, QDeclarativeJS::AST::Node *node,
+ QList<QDeclarativeJS::AST::ExpressionNode *> *nodes);
+ void discard();
+
+ const QDeclarativeV4Compiler::Expression *m_expression;
+ QDeclarativeEnginePrivate *m_engine;
+
+ QDeclarativeJS::IR::Module *_module;
+ QDeclarativeJS::IR::Function *_function;
+ QDeclarativeJS::IR::BasicBlock *_block;
+ bool _discard;
+
+ ExprResult _expr;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QDECLARATIVEV4IRBUILDER_P_H
diff --git a/src/declarative/qml/v4/qdeclarativev4program_p.h b/src/declarative/qml/v4/qdeclarativev4program_p.h
new file mode 100644
index 0000000000..d036bd6f73
--- /dev/null
+++ b/src/declarative/qml/v4/qdeclarativev4program_p.h
@@ -0,0 +1,122 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVEV4PROGRAM_P_H
+#define QDECLARATIVEV4PROGRAM_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 "qdeclarativev4instruction_p.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+struct QDeclarativeV4Program {
+ 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 QDeclarativeRegisterType {
+ UndefinedType,
+ QObjectStarType,
+ QRealType,
+ IntType,
+ BoolType,
+
+ PODValueType,
+
+ FirstCleanupType,
+ QStringType = FirstCleanupType,
+ QUrlType,
+ QVariantType,
+};
+
+const char *QDeclarativeV4Program::data() const
+{
+ return ((const char *)this) + sizeof(QDeclarativeV4Program);
+}
+
+const char *QDeclarativeV4Program::instructions() const
+{
+ return (const char *)(data() + dataLength);
+}
+
+QDeclarativeV4Program::BindingReferenceList *QDeclarativeV4Program::signalTable(int signalIndex) const
+{
+ quint32 *signalTable = (quint32 *)(data() + signalTableOffset);
+ return (BindingReferenceList *)(signalTable + signalTable[signalIndex]);
+}
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QDECLARATIVEV4PROGRAM_P_H
+
diff --git a/src/declarative/qml/v4/v4.pri b/src/declarative/qml/v4/v4.pri
new file mode 100644
index 0000000000..085f0ae443
--- /dev/null
+++ b/src/declarative/qml/v4/v4.pri
@@ -0,0 +1,17 @@
+INCLUDEPATH += $$PWD
+
+HEADERS += \
+ $$PWD/qdeclarativev4compiler_p.h \
+ $$PWD/qdeclarativev4compiler_p_p.h \
+ $$PWD/qdeclarativev4ir_p.h \
+ $$PWD/qdeclarativev4irbuilder_p.h \
+ $$PWD/qdeclarativev4instruction_p.h \
+ $$PWD/qdeclarativev4bindings_p.h \
+ $$PWD/qdeclarativev4program_p.h \
+
+SOURCES += \
+ $$PWD/qdeclarativev4compiler.cpp \
+ $$PWD/qdeclarativev4ir.cpp \
+ $$PWD/qdeclarativev4irbuilder.cpp \
+ $$PWD/qdeclarativev4instruction.cpp \
+ $$PWD/qdeclarativev4bindings.cpp \
diff --git a/src/declarative/scenegraph/coreapi/qsgdefaultrenderer.cpp b/src/declarative/scenegraph/coreapi/qsgdefaultrenderer.cpp
new file mode 100644
index 0000000000..e2bd8f6134
--- /dev/null
+++ b/src/declarative/scenegraph/coreapi/qsgdefaultrenderer.cpp
@@ -0,0 +1,538 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#define GL_GLEXT_PROTOTYPES
+
+#include "qsgdefaultrenderer_p.h"
+#include "qsgmaterial.h"
+
+#include <QtCore/qvarlengtharray.h>
+#include <QtGui/qapplication.h>
+#include <QtCore/qpair.h>
+#include <QtCore/QElapsedTimer>
+
+//#define FORCE_NO_REORDER
+
+// #define RENDERER_DEBUG
+#ifdef RENDERER_DEBUG
+#define DEBUG_THRESHOLD 0
+QElapsedTimer debugTimer;
+int materialChanges;
+int geometryNodesDrawn;
+#endif
+
+QT_BEGIN_NAMESPACE
+
+static bool nodeLessThan(QSGGeometryNode *a, QSGGeometryNode *b)
+{
+ // Sort by clip...
+ if (a->clipList() != b->clipList())
+ return a->clipList() < b->clipList();
+
+ // Sort by material definition
+ QSGMaterialType *aDef = a->material()->type();
+ QSGMaterialType *bDef = b->material()->type();
+
+ if (aDef != bDef)
+ return aDef < bDef;
+
+ // Sort by material state
+ int cmp = a->material()->compare(b->material());
+ if (cmp != 0)
+ return cmp < 0;
+
+ return a->matrix() < b->matrix();
+}
+
+static bool nodeLessThanWithRenderOrder(QSGGeometryNode *a, QSGGeometryNode *b)
+{
+ // Sort by clip...
+ if (a->clipList() != b->clipList())
+ return a->clipList() < b->clipList();
+
+ // Sort by material definition
+ QSGMaterialType *aDef = a->material()->type();
+ QSGMaterialType *bDef = b->material()->type();
+
+ if (!(a->material()->flags() & QSGMaterial::Blending)) {
+ int aOrder = a->renderOrder();
+ int bOrder = b->renderOrder();
+ if (aOrder != bOrder)
+ return aOrder > bOrder;
+ }
+
+ if (aDef != bDef)
+ return aDef < bDef;
+
+ // Sort by material state
+ int cmp = a->material()->compare(b->material());
+ if (cmp != 0)
+ return cmp < 0;
+
+ return a->matrix() < b->matrix();
+}
+
+// Minimum heap.
+template <typename T, int prealloc = 256>
+class Heap
+{
+public:
+ void insert(const T &x);
+ const T &top() const { return v[0]; }
+ T pop();
+ bool isEmpty() const { return v.isEmpty(); }
+private:
+ static int parent(int i) { return (i - 1) >> 1; }
+ static int left(int i) { return (i << 1) | 1; }
+ static int right(int i) { return (i + 1) << 1; }
+ QVarLengthArray<T, prealloc> v;
+};
+
+template <typename T, int prealloc>
+void Heap<T, prealloc>::insert(const T &x)
+{
+ int i = v.size();
+ v.append(x);
+ while (i != 0 && v[i] < v[parent(i)]) {
+ qSwap(v[parent(i)], v[i]);
+ i = parent(i);
+ }
+}
+
+template <typename T, int prealloc>
+T Heap<T, prealloc>::pop()
+{
+ T x = top();
+ if (v.size() > 1)
+ qSwap(v[0], v[v.size() - 1]);
+ v.resize(v.size() - 1);
+ int i = 0;
+ while (left(i) < v.size()) {
+ int low = left(i);
+ if (right(i) < v.size() && v[right(i)] < v[low])
+ low = right(i);
+ if (!(v[low] < v[i]))
+ break;
+ qSwap(v[i], v[low]);
+ i = low;
+ }
+ return x;
+}
+
+
+QMLRenderer::QMLRenderer(QSGContext *context)
+ : QSGRenderer(context)
+ , m_opaqueNodes(64)
+ , m_transparentNodes(64)
+ , m_tempNodes(64)
+ , m_rebuild_lists(false)
+ , m_needs_sorting(false)
+ , m_sort_front_to_back(false)
+ , m_currentRenderOrder(1)
+{
+ QStringList args = qApp->arguments();
+#if defined(QML_RUNTIME_TESTING)
+ m_render_opaque_nodes = !args.contains(QLatin1String("--no-opaque-nodes"));
+ m_render_alpha_nodes = !args.contains(QLatin1String("--no-alpha-nodes"));
+#endif
+}
+
+void QMLRenderer::nodeChanged(QSGNode *node, QSGNode::DirtyFlags flags)
+{
+ QSGRenderer::nodeChanged(node, flags);
+
+ quint32 rebuildFlags = QSGNode::DirtyNodeAdded | QSGNode::DirtyNodeRemoved
+ | QSGNode::DirtyMaterial | QSGNode::DirtyOpacity
+ | QSGNode::DirtyForceUpdate;
+
+ if (flags & rebuildFlags)
+ m_rebuild_lists = true;
+
+ if (flags & (rebuildFlags | QSGNode::DirtyClipList))
+ m_needs_sorting = true;
+}
+
+void QMLRenderer::render()
+{
+#if defined (QML_RUNTIME_TESTING)
+ static bool dumpTree = qApp->arguments().contains(QLatin1String("--dump-tree"));
+ if (dumpTree) {
+ printf("\n\n");
+ QSGNodeDumper::dump(rootNode());
+ }
+#endif
+
+#ifdef RENDERER_DEBUG
+ debugTimer.invalidate();
+ debugTimer.start();
+ geometryNodesDrawn = 0;
+ materialChanges = 0;
+#endif
+
+ glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+ glDisable(GL_BLEND);
+
+ glFrontFace(isMirrored() ? GL_CW : GL_CCW);
+ glDisable(GL_CULL_FACE);
+
+ glEnable(GL_DEPTH_TEST);
+ glDepthMask(true);
+ glDepthFunc(GL_GREATER);
+#if defined(QT_OPENGL_ES)
+ glClearDepthf(0);
+#else
+ glClearDepth(0);
+#endif
+
+ glDisable(GL_SCISSOR_TEST);
+ glClearColor(m_clear_color.redF(), m_clear_color.greenF(), m_clear_color.blueF(), m_clear_color.alphaF());
+
+#ifdef RENDERER_DEBUG
+ int debugtimeSetup = debugTimer.elapsed();
+#endif
+
+ bindable()->clear(clearMode());
+
+#ifdef RENDERER_DEBUG
+ int debugtimeClear = debugTimer.elapsed();
+#endif
+
+ QRect r = viewportRect();
+ glViewport(r.x(), deviceRect().bottom() - r.bottom(), r.width(), r.height());
+ m_projectionMatrix = projectMatrix();
+ m_projectionMatrix.push();
+ m_modelViewMatrix.setToIdentity();
+
+ m_currentClip = 0;
+ glDisable(GL_STENCIL_TEST);
+
+ m_currentMaterial = 0;
+ m_currentProgram = 0;
+ m_currentMatrix = 0;
+
+ if (m_rebuild_lists) {
+ m_opaqueNodes.reset();
+ m_transparentNodes.reset();
+ m_currentRenderOrder = 1;
+ buildLists(rootNode());
+ m_rebuild_lists = false;
+ }
+
+#ifdef RENDERER_DEBUG
+ int debugtimeLists = debugTimer.elapsed();
+#endif
+
+
+ if (m_needs_sorting) {
+ if (!m_opaqueNodes.isEmpty()) {
+ qSort(&m_opaqueNodes.first(), &m_opaqueNodes.first() + m_opaqueNodes.size(),
+ m_sort_front_to_back
+ ? nodeLessThanWithRenderOrder
+ : nodeLessThan);
+ }
+ m_needs_sorting = false;
+ }
+
+#ifdef RENDERER_DEBUG
+ int debugtimeSorting = debugTimer.elapsed();
+#endif
+
+ m_renderOrderMatrix.setToIdentity();
+ m_renderOrderMatrix.scale(1, 1, qreal(1) / m_currentRenderOrder);
+
+ glDisable(GL_BLEND);
+ glDepthMask(true);
+#ifdef QML_RUNTIME_TESTING
+ if (m_render_opaque_nodes)
+#endif
+ {
+#if defined (QML_RUNTIME_TESTING)
+ if (dumpTree)
+ qDebug() << "Opaque Nodes:";
+#endif
+ renderNodes(m_opaqueNodes);
+ }
+
+#ifdef RENDERER_DEBUG
+ int debugtimeOpaque = debugTimer.elapsed();
+ int opaqueNodes = geometryNodesDrawn;
+ int opaqueMaterialChanges = materialChanges;
+#endif
+
+ glEnable(GL_BLEND);
+ glDepthMask(false);
+#ifdef QML_RUNTIME_TESTING
+ if (m_render_alpha_nodes)
+#endif
+ {
+#if defined (QML_RUNTIME_TESTING)
+ if (dumpTree)
+ qDebug() << "Alpha Nodes:";
+#endif
+ renderNodes(m_transparentNodes);
+ }
+
+#ifdef RENDERER_DEBUG
+ int debugtimeAlpha = debugTimer.elapsed();
+#endif
+
+
+ if (m_currentProgram)
+ m_currentProgram->deactivate();
+
+ m_projectionMatrix.pop();
+
+#ifdef RENDERER_DEBUG
+ if (debugTimer.elapsed() > DEBUG_THRESHOLD) {
+ printf(" --- Renderer breakdown:\n"
+ " - setup=%d, clear=%d, building=%d, sorting=%d, opaque=%d, alpha=%d\n"
+ " - material changes: opaque=%d, alpha=%d, total=%d\n"
+ " - geometry ndoes: opaque=%d, alpha=%d, total=%d\n",
+ debugtimeSetup,
+ debugtimeClear - debugtimeSetup,
+ debugtimeLists - debugtimeClear,
+ debugtimeSorting - debugtimeLists,
+ debugtimeOpaque - debugtimeSorting,
+ debugtimeAlpha - debugtimeOpaque,
+ opaqueMaterialChanges, materialChanges - opaqueMaterialChanges, materialChanges,
+ opaqueNodes, geometryNodesDrawn - opaqueNodes, geometryNodesDrawn);
+ }
+#endif
+
+}
+
+class Foo : public QPair<int, QSGGeometryNode *>
+{
+public:
+ Foo() { }
+ Foo(int i, QSGGeometryNode *n) : QPair<int, QSGGeometryNode *>(i, n) { }
+ bool operator < (const Foo &other) const { return nodeLessThan(second, other.second); }
+};
+
+void QMLRenderer::setSortFrontToBackEnabled(bool sort)
+{
+ printf("setting sorting to... %d\n", sort);
+ m_sort_front_to_back = sort;
+}
+
+bool QMLRenderer::isSortFrontToBackEnabled() const
+{
+ return m_sort_front_to_back;
+}
+
+void QMLRenderer::buildLists(QSGNode *node)
+{
+ if (node->isSubtreeBlocked())
+ return;
+
+ if (node->type() == QSGNode::GeometryNodeType) {
+ QSGGeometryNode *geomNode = static_cast<QSGGeometryNode *>(node);
+ qreal opacity = geomNode->inheritedOpacity();
+ QSGMaterial *m = geomNode->activeMaterial();
+
+#ifdef FORCE_NO_REORDER
+ if (true) {
+#else
+ if ((m->flags() & QSGMaterial::Blending) || opacity < 1) {
+#endif
+ geomNode->setRenderOrder(m_currentRenderOrder - 1);
+ m_transparentNodes.add(geomNode);
+ } else {
+ geomNode->setRenderOrder(m_currentRenderOrder);
+ m_opaqueNodes.add(geomNode);
+ m_currentRenderOrder += 2;
+ }
+ }
+
+ int count = node->childCount();
+ if (!count)
+ return;
+
+#ifdef FORCE_NO_REORDER
+ static bool reorder = false;
+#else
+ static bool reorder = !qApp->arguments().contains(QLatin1String("--no-reorder"));
+#endif
+
+ if (reorder && count > 1 && (node->flags() & QSGNode::ChildrenDoNotOverlap)) {
+ QVarLengthArray<int, 16> beginIndices(count);
+ QVarLengthArray<int, 16> endIndices(count);
+ int baseCount = m_transparentNodes.size();
+ for (int i = 0; i < count; ++i) {
+ beginIndices[i] = m_transparentNodes.size();
+ buildLists(node->childAtIndex(i));
+ endIndices[i] = m_transparentNodes.size();
+ }
+
+ int childNodeCount = m_transparentNodes.size() - baseCount;
+ if (childNodeCount) {
+ Heap<Foo, 16> heap;
+ m_tempNodes.reset();
+ m_tempNodes.reserve(childNodeCount);
+ while (childNodeCount) {
+ for (int i = 0; i < count; ++i) {
+ if (beginIndices[i] != endIndices[i])
+ heap.insert(Foo(i, m_transparentNodes.at(beginIndices[i]++)));
+ }
+ while (!heap.isEmpty()) {
+ Foo foo = heap.pop();
+ m_tempNodes.add(foo.second);
+ --childNodeCount;
+ int i = foo.first;
+ if (beginIndices[i] != endIndices[i] && !nodeLessThan(m_transparentNodes.at(beginIndices[i]), foo.second))
+ heap.insert(Foo(i, m_transparentNodes.at(beginIndices[i]++)));
+ }
+ }
+ Q_ASSERT(m_tempNodes.size() == m_transparentNodes.size() - baseCount);
+
+ qMemCopy(&m_transparentNodes.at(baseCount), &m_tempNodes.at(0), m_tempNodes.size() * sizeof(QSGGeometryNode *));
+ }
+ } else {
+ for (int i = 0; i < count; ++i)
+ buildLists(node->childAtIndex(i));
+ }
+}
+
+void QMLRenderer::renderNodes(const QDataBuffer<QSGGeometryNode *> &list)
+{
+ const float scale = 1.0f / m_currentRenderOrder;
+ int count = list.size();
+ int currentRenderOrder = 0x80000000;
+
+ //int clipChangeCount = 0;
+ //int programChangeCount = 0;
+ //int materialChangeCount = 0;
+
+ for (int i = 0; i < count; ++i) {
+ QSGGeometryNode *geomNode = list.at(i);
+
+ QSGMaterialShader::RenderState::DirtyStates updates;
+
+#if defined (QML_RUNTIME_TESTING)
+ static bool dumpTree = qApp->arguments().contains(QLatin1String("--dump-tree"));
+ if (dumpTree)
+ qDebug() << geomNode;
+#endif
+
+ bool changeMatrix = m_currentMatrix != geomNode->matrix();
+
+ if (changeMatrix) {
+ m_currentMatrix = geomNode->matrix();
+ if (m_currentMatrix)
+ m_modelViewMatrix = *m_currentMatrix;
+ else
+ m_modelViewMatrix.setToIdentity();
+ updates |= QSGMaterialShader::RenderState::DirtyMatrix;
+ }
+
+ bool changeOpacity = m_render_opacity != geomNode->inheritedOpacity();
+ if (changeOpacity) {
+ updates |= QSGMaterialShader::RenderState::DirtyOpacity;
+ m_render_opacity = geomNode->inheritedOpacity();
+ }
+
+
+ Q_ASSERT(geomNode->activeMaterial());
+
+ QSGMaterial *material = geomNode->activeMaterial();
+ QSGMaterialShader *program = m_context->prepareMaterial(material);
+ Q_ASSERT(program->program()->isLinked());
+
+ bool changeClip = geomNode->clipList() != m_currentClip;
+ QSGRenderer::ClipType clipType = QSGRenderer::NoClip;
+ if (changeClip) {
+ clipType = updateStencilClip(geomNode->clipList());
+ m_currentClip = geomNode->clipList();
+#ifdef FORCE_NO_REORDER
+ glDepthMask(false);
+#else
+ glDepthMask((material->flags() & QSGMaterial::Blending) == 0 && m_render_opacity == 1);
+#endif
+ //++clipChangeCount;
+ }
+
+ bool changeProgram = (changeClip && clipType == QSGRenderer::StencilClip) || m_currentProgram != program;
+ if (changeProgram) {
+ if (m_currentProgram)
+ m_currentProgram->deactivate();
+ m_currentProgram = program;
+ m_currentProgram->activate();
+ //++programChangeCount;
+ updates |= (QSGMaterialShader::RenderState::DirtyMatrix | QSGMaterialShader::RenderState::DirtyOpacity);
+
+#ifdef RENDERER_DEBUG
+ materialChanges++;
+#endif
+ }
+
+ bool changeRenderOrder = currentRenderOrder != geomNode->renderOrder();
+ if (changeRenderOrder) {
+ currentRenderOrder = geomNode->renderOrder();
+ m_renderOrderMatrix(2, 3) = currentRenderOrder * scale;
+ m_projectionMatrix.pop();
+ m_projectionMatrix.push();
+ m_projectionMatrix *= m_renderOrderMatrix;
+ updates |= QSGMaterialShader::RenderState::DirtyMatrix;
+ }
+
+ if (changeProgram || m_currentMaterial != material) {
+ program->updateState(state(updates), material, changeProgram ? 0 : m_currentMaterial);
+ m_currentMaterial = material;
+ //++materialChangeCount;
+ }
+
+ //glDepthRange((geomNode->renderOrder() + 0.1) * scale, (geomNode->renderOrder() + 0.9) * scale);
+
+ const QSGGeometry *g = geomNode->geometry();
+ bindGeometry(program, g);
+ draw(geomNode);
+
+#ifdef RENDERER_DEBUG
+ geometryNodesDrawn++;
+#endif
+ }
+ //qDebug("Clip: %i, shader program: %i, material: %i times changed while drawing %s items",
+ // clipChangeCount, programChangeCount, materialChangeCount,
+ // &list == &m_transparentNodes ? "transparent" : "opaque");
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/scenegraph/coreapi/qsgdefaultrenderer_p.h b/src/declarative/scenegraph/coreapi/qsgdefaultrenderer_p.h
new file mode 100644
index 0000000000..ca1f5592cf
--- /dev/null
+++ b/src/declarative/scenegraph/coreapi/qsgdefaultrenderer_p.h
@@ -0,0 +1,98 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QMLRENDERER_H
+#define QMLRENDERER_H
+
+#include "qsgrenderer_p.h"
+
+#include <QtGui/private/qdatabuffer_p.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QMLRenderer : public QSGRenderer
+{
+ Q_OBJECT
+public:
+ QMLRenderer(QSGContext *context);
+
+ void render();
+
+ void nodeChanged(QSGNode *node, QSGNode::DirtyFlags flags);
+
+ void setSortFrontToBackEnabled(bool sort);
+ bool isSortFrontToBackEnabled() const;
+
+private:
+ void buildLists(QSGNode *node);
+ void renderNodes(const QDataBuffer<QSGGeometryNode *> &list);
+
+ const QSGClipNode *m_currentClip;
+ QSGMaterial *m_currentMaterial;
+ QSGMaterialShader *m_currentProgram;
+ const QMatrix4x4 *m_currentMatrix;
+ QMatrix4x4 m_renderOrderMatrix;
+ QDataBuffer<QSGGeometryNode *> m_opaqueNodes;
+ QDataBuffer<QSGGeometryNode *> m_transparentNodes;
+ QDataBuffer<QSGGeometryNode *> m_tempNodes;
+
+ bool m_rebuild_lists;
+ bool m_needs_sorting;
+ bool m_sort_front_to_back;
+ int m_currentRenderOrder;
+
+
+
+#ifdef QML_RUNTIME_TESTING
+ bool m_render_opaque_nodes;
+ bool m_render_alpha_nodes;
+#endif
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QMLRENDERER_H
diff --git a/src/declarative/scenegraph/coreapi/qsggeometry.cpp b/src/declarative/scenegraph/coreapi/qsggeometry.cpp
new file mode 100644
index 0000000000..1bfffae0bf
--- /dev/null
+++ b/src/declarative/scenegraph/coreapi/qsggeometry.cpp
@@ -0,0 +1,310 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt scene graph research project.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsggeometry.h"
+
+QT_BEGIN_NAMESPACE
+
+
+/*!
+ Convenience function which returns attributes to be used for 2D solid
+ color drawing.
+ */
+
+const QSGGeometry::AttributeSet &QSGGeometry::defaultAttributes_Point2D()
+{
+ static Attribute data[] = {
+ { 0, 2, GL_FLOAT }
+ };
+ static AttributeSet attrs = { 1, sizeof(float) * 2, data };
+ return attrs;
+}
+
+/*!
+ Convenience function which returns attributes to be used for textured 2D drawing.
+ */
+
+const QSGGeometry::AttributeSet &QSGGeometry::defaultAttributes_TexturedPoint2D()
+{
+ static Attribute data[] = {
+ { 0, 2, GL_FLOAT },
+ { 1, 2, GL_FLOAT }
+ };
+ static AttributeSet attrs = { 2, sizeof(float) * 4, data };
+ return attrs;
+}
+
+/*!
+ Convenience function which returns attributes to be used for per vertex colored 2D drawing.
+ */
+
+const QSGGeometry::AttributeSet &QSGGeometry::defaultAttributes_ColoredPoint2D()
+{
+ static Attribute data[] = {
+ { 0, 2, GL_FLOAT },
+ { 1, 4, GL_UNSIGNED_BYTE }
+ };
+ static AttributeSet attrs = { 2, 2 * sizeof(float) + 4 * sizeof(char), data };
+ return attrs;
+}
+
+
+/*!
+ \class QSGGeometry
+ \brief The QSGGeometry class provides low-level storage for graphics primitives
+ in the QML Scene Graph.
+
+ The QSGGeometry class provides a few convenience attributes and attribute accessors
+ by default. The defaultAttributes_Point2D() function returns attributes to be used
+ in normal solid color rectangles, while the defaultAttributes_TexturedPoint2D function
+ returns attributes to be used for the common pixmap usecase.
+ */
+
+
+/*!
+ Constructs a geometry object based on \a attributes.
+
+ The object allocate space for \a vertexCount vertices based on the accumulated
+ size in \a attributes and for \a indexCount.
+
+ Geometry objects are constructed with GL_TRIANGLE_STRIP as default drawing mode.
+
+ The attribute structure is assumed to be POD and the geometry object
+ assumes this will not go away. There is no memory management involved.
+ */
+
+QSGGeometry::QSGGeometry(const QSGGeometry::AttributeSet &attributes,
+ int vertexCount,
+ int indexCount,
+ int indexType)
+ : m_drawing_mode(GL_TRIANGLE_STRIP)
+ , m_vertex_count(0)
+ , m_index_count(0)
+ , m_index_type(indexType)
+ , m_attributes(attributes)
+ , m_data(0)
+ , m_index_data_offset(-1)
+ , m_owns_data(false)
+{
+ Q_ASSERT(m_attributes.count > 0);
+ Q_ASSERT(m_attributes.stride > 0);
+
+ // Because allocate reads m_vertex_count, m_index_count and m_owns_data, these
+ // need to be set before calling allocate...
+ allocate(vertexCount, indexCount);
+}
+
+QSGGeometry::~QSGGeometry()
+{
+ if (m_owns_data)
+ qFree(m_data);
+}
+
+/*!
+ \fn int QSGGeometry::vertexCount() const
+
+ Returns the number of vertices in this geometry object.
+ */
+
+/*!
+ \fn int QSGGeometry::indexCount() const
+
+ Returns the number of indices in this geometry object.
+ */
+
+
+
+/*!
+ \fn void *QSGGeometry::vertexData()
+
+ Returns a pointer to the raw vertex data of this geometry object.
+
+ \sa vertexDataAsPoint2D(), vertexDataAsTexturedPoint2D
+ */
+
+/*!
+ \fn const void *QSGGeometry::vertexData() const
+
+ Returns a pointer to the raw vertex data of this geometry object.
+
+ \sa vertexDataAsPoint2D(), vertexDataAsTexturedPoint2D
+ */
+
+/*!
+ Returns a pointer to the raw index data of this geometry object.
+
+ \sa indexDataAsUShort(), indexDataAsUInt()
+ */
+void *QSGGeometry::indexData()
+{
+ return m_index_data_offset < 0
+ ? 0
+ : ((char *) m_data + m_index_data_offset);
+}
+
+/*!
+ Returns a pointer to the raw index data of this geometry object.
+
+ \sa indexDataAsUShort(), indexDataAsUInt()
+ */
+const void *QSGGeometry::indexData() const
+{
+ return m_index_data_offset < 0
+ ? 0
+ : ((char *) m_data + m_index_data_offset);
+}
+
+/*!
+ Sets the drawing mode to be used for this geometry.
+
+ The default value is GL_TRIANGLE_STRIP.
+ */
+void QSGGeometry::setDrawingMode(GLenum mode)
+{
+ m_drawing_mode = mode;
+}
+
+/*!
+ \fn int QSGGeometry::drawingMode() const
+
+ Returns the drawing mode of this geometry.
+
+ The default value is GL_TRIANGLE_STRIP.
+ */
+
+/*!
+ \fn int QSGGeometry::indexType() const
+
+ Returns the primitive type used for indices in this
+ geometry object.
+ */
+
+
+/*!
+ Resizes the vertex and index data of this geometry object to fit \a vertexCount
+ vertices and \a indexCount indices.
+
+ Vertex and index data will be invalidated after this call and the caller must
+ */
+void QSGGeometry::allocate(int vertexCount, int indexCount)
+{
+ if (vertexCount == m_vertex_count && indexCount == m_index_count)
+ return;
+
+ m_vertex_count = vertexCount;
+ m_index_count = indexCount;
+
+ bool canUsePrealloc = m_index_count <= 0;
+ int vertexByteSize = m_attributes.stride * m_vertex_count;
+
+ if (m_owns_data)
+ qFree(m_data);
+
+ if (canUsePrealloc && vertexByteSize <= (int) sizeof(m_prealloc)) {
+ m_data = (void *) &m_prealloc[0];
+ m_index_data_offset = -1;
+ m_owns_data = false;
+ } else {
+ Q_ASSERT(m_index_type == GL_UNSIGNED_INT || m_index_type == GL_UNSIGNED_SHORT);
+ int indexByteSize = indexCount * (m_index_type == GL_UNSIGNED_SHORT ? sizeof(quint16) : sizeof(quint32));
+ m_data = (void *) qMalloc(vertexByteSize + indexByteSize);
+ m_index_data_offset = vertexByteSize;
+ m_owns_data = true;
+ }
+
+}
+
+/*!
+ Updates the geometry \a g with the coordinates in \a rect.
+
+ The function assumes the geometry object contains a single triangle strip
+ of QSGGeometry::Point2D vertices
+ */
+void QSGGeometry::updateRectGeometry(QSGGeometry *g, const QRectF &rect)
+{
+ Point2D *v = g->vertexDataAsPoint2D();
+ v[0].x = rect.left();
+ v[0].y = rect.top();
+
+ v[1].x = rect.left();
+ v[1].y = rect.bottom();
+
+ v[2].x = rect.right();
+ v[2].y = rect.top();
+
+ v[3].x = rect.right();
+ v[3].y = rect.bottom();
+}
+
+/*!
+ Updates the geometry \a g with the coordinates in \a rect and texture
+ coordinates from \a textureRect.
+
+ \a textureRect should be in normalized coordinates.
+
+ \a g is assumed to be a triangle strip of four vertices of type
+ QSGGeometry::TexturedPoint2D.
+ */
+void QSGGeometry::updateTexturedRectGeometry(QSGGeometry *g, const QRectF &rect, const QRectF &textureRect)
+{
+ TexturedPoint2D *v = g->vertexDataAsTexturedPoint2D();
+ v[0].x = rect.left();
+ v[0].y = rect.top();
+ v[0].tx = textureRect.left();
+ v[0].ty = textureRect.top();
+
+ v[1].x = rect.left();
+ v[1].y = rect.bottom();
+ v[1].tx = textureRect.left();
+ v[1].ty = textureRect.bottom();
+
+ v[2].x = rect.right();
+ v[2].y = rect.top();
+ v[2].tx = textureRect.right();
+ v[2].ty = textureRect.top();
+
+ v[3].x = rect.right();
+ v[3].y = rect.bottom();
+ v[3].tx = textureRect.right();
+ v[3].ty = textureRect.bottom();
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/scenegraph/coreapi/qsggeometry.h b/src/declarative/scenegraph/coreapi/qsggeometry.h
new file mode 100644
index 0000000000..514fdc466f
--- /dev/null
+++ b/src/declarative/scenegraph/coreapi/qsggeometry.h
@@ -0,0 +1,254 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt scene graph research project.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGGEOMETRY_H
+#define QSGGEOMETRY_H
+
+#include <QtOpenGL/qgl.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class Q_DECLARATIVE_EXPORT QSGGeometry
+{
+public:
+ struct Attribute
+ {
+ int position;
+ int tupleSize;
+ int type;
+ };
+
+ struct AttributeSet {
+ int count;
+ int stride;
+ const Attribute *attributes;
+ };
+
+ struct Point2D {
+ float x, y;
+ void set(float nx, float ny) {
+ x = nx; y = ny;
+ }
+ };
+ struct TexturedPoint2D {
+ float x, y;
+ float tx, ty;
+ void set(float nx, float ny, float ntx, float nty) {
+ x = nx; y = ny; tx = ntx; ty = nty;
+ }
+ };
+ struct ColoredPoint2D {
+ float x, y;
+ unsigned char r, g, b, a;
+ void set(float nx, float ny, uchar nr, uchar ng, uchar nb, uchar na) {
+ x = nx; y = ny;
+ r = nr; g = ng, b = nb; a = na;
+ }
+ };
+
+ static const AttributeSet &defaultAttributes_Point2D();
+ static const AttributeSet &defaultAttributes_TexturedPoint2D();
+ static const AttributeSet &defaultAttributes_ColoredPoint2D();
+
+ QSGGeometry(const QSGGeometry::AttributeSet &attribs,
+ int vertexCount,
+ int indexCount = 0,
+ int indexType = GL_UNSIGNED_SHORT);
+ virtual ~QSGGeometry();
+
+ void setDrawingMode(GLenum mode);
+ inline GLenum drawingMode() const { return m_drawing_mode; }
+
+ void allocate(int vertexCount, int indexCount = 0);
+
+ int vertexCount() const { return m_vertex_count; }
+
+ void *vertexData() { return m_data; }
+ inline Point2D *vertexDataAsPoint2D();
+ inline TexturedPoint2D *vertexDataAsTexturedPoint2D();
+ inline ColoredPoint2D *vertexDataAsColoredPoint2D();
+
+ inline const void *vertexData() const { return m_data; }
+ inline const Point2D *vertexDataAsPoint2D() const;
+ inline const TexturedPoint2D *vertexDataAsTexturedPoint2D() const;
+ inline const ColoredPoint2D *vertexDataAsColoredPoint2D() const;
+
+ inline int indexType() const { return m_index_type; }
+
+ int indexCount() const { return m_index_count; }
+
+ void *indexData();
+ inline uint *indexDataAsUInt();
+ inline quint16 *indexDataAsUShort();
+
+ const void *indexData() const;
+ inline const uint *indexDataAsUInt() const;
+ inline const quint16 *indexDataAsUShort() const;
+
+ inline int attributeCount() const { return m_attributes.count; }
+ inline const Attribute *attributes() const { return m_attributes.attributes; }
+ inline int stride() const { return m_attributes.stride; }
+
+ static void updateRectGeometry(QSGGeometry *g, const QRectF &rect);
+ static void updateTexturedRectGeometry(QSGGeometry *g, const QRectF &rect, const QRectF &sourceRect);
+
+private:
+ int m_drawing_mode;
+ int m_vertex_count;
+ int m_index_count;
+ int m_index_type;
+ const AttributeSet &m_attributes;
+ void *m_data;
+ int m_index_data_offset;
+
+ void *m_reserved_pointer;
+
+ uint m_owns_data : 1;
+ uint m_reserved_bits : 31;
+
+ float m_prealloc[16];
+};
+
+inline uint *QSGGeometry::indexDataAsUInt()
+{
+ Q_ASSERT(m_index_type == GL_UNSIGNED_INT);
+ return (uint *) indexData();
+}
+
+inline quint16 *QSGGeometry::indexDataAsUShort()
+{
+ Q_ASSERT(m_index_type == GL_UNSIGNED_SHORT);
+ return (quint16 *) indexData();
+}
+
+inline const uint *QSGGeometry::indexDataAsUInt() const
+{
+ Q_ASSERT(m_index_type == GL_UNSIGNED_INT);
+ return (uint *) indexData();
+}
+
+inline const quint16 *QSGGeometry::indexDataAsUShort() const
+{
+ Q_ASSERT(m_index_type == GL_UNSIGNED_SHORT);
+ return (quint16 *) indexData();
+}
+
+inline QSGGeometry::Point2D *QSGGeometry::vertexDataAsPoint2D()
+{
+ Q_ASSERT(m_attributes.count == 1);
+ Q_ASSERT(m_attributes.stride == 2 * sizeof(float));
+ Q_ASSERT(m_attributes.attributes[0].tupleSize == 2);
+ Q_ASSERT(m_attributes.attributes[0].type == GL_FLOAT);
+ Q_ASSERT(m_attributes.attributes[0].position == 0);
+ return (Point2D *) m_data;
+}
+
+inline QSGGeometry::TexturedPoint2D *QSGGeometry::vertexDataAsTexturedPoint2D()
+{
+ Q_ASSERT(m_attributes.count == 2);
+ Q_ASSERT(m_attributes.stride == 4 * sizeof(float));
+ Q_ASSERT(m_attributes.attributes[0].position == 0);
+ Q_ASSERT(m_attributes.attributes[0].tupleSize == 2);
+ Q_ASSERT(m_attributes.attributes[0].type == GL_FLOAT);
+ Q_ASSERT(m_attributes.attributes[1].position == 1);
+ Q_ASSERT(m_attributes.attributes[1].tupleSize == 2);
+ Q_ASSERT(m_attributes.attributes[1].type == GL_FLOAT);
+ return (TexturedPoint2D *) m_data;
+}
+
+inline QSGGeometry::ColoredPoint2D *QSGGeometry::vertexDataAsColoredPoint2D()
+{
+ Q_ASSERT(m_attributes.count == 2);
+ Q_ASSERT(m_attributes.stride == 2 * sizeof(float) + 4 * sizeof(char));
+ Q_ASSERT(m_attributes.attributes[0].position == 0);
+ Q_ASSERT(m_attributes.attributes[0].tupleSize == 2);
+ Q_ASSERT(m_attributes.attributes[0].type == GL_FLOAT);
+ Q_ASSERT(m_attributes.attributes[1].position == 1);
+ Q_ASSERT(m_attributes.attributes[1].tupleSize == 4);
+ Q_ASSERT(m_attributes.attributes[1].type == GL_UNSIGNED_BYTE);
+ return (ColoredPoint2D *) m_data;
+}
+
+inline const QSGGeometry::Point2D *QSGGeometry::vertexDataAsPoint2D() const
+{
+ Q_ASSERT(m_attributes.count == 1);
+ Q_ASSERT(m_attributes.stride == 2 * sizeof(float));
+ Q_ASSERT(m_attributes.attributes[0].tupleSize == 2);
+ Q_ASSERT(m_attributes.attributes[0].type == GL_FLOAT);
+ Q_ASSERT(m_attributes.attributes[0].position == 0);
+ return (const Point2D *) m_data;
+}
+
+inline const QSGGeometry::TexturedPoint2D *QSGGeometry::vertexDataAsTexturedPoint2D() const
+{
+ Q_ASSERT(m_attributes.count == 2);
+ Q_ASSERT(m_attributes.stride == 4 * sizeof(float));
+ Q_ASSERT(m_attributes.attributes[0].position == 0);
+ Q_ASSERT(m_attributes.attributes[0].tupleSize == 2);
+ Q_ASSERT(m_attributes.attributes[0].type == GL_FLOAT);
+ Q_ASSERT(m_attributes.attributes[1].position == 1);
+ Q_ASSERT(m_attributes.attributes[1].tupleSize == 2);
+ Q_ASSERT(m_attributes.attributes[1].type == GL_FLOAT);
+ return (const TexturedPoint2D *) m_data;
+}
+
+inline const QSGGeometry::ColoredPoint2D *QSGGeometry::vertexDataAsColoredPoint2D() const
+{
+ Q_ASSERT(m_attributes.count == 2);
+ Q_ASSERT(m_attributes.stride == 2 * sizeof(float) + 4 * sizeof(char));
+ Q_ASSERT(m_attributes.attributes[0].position == 0);
+ Q_ASSERT(m_attributes.attributes[0].tupleSize == 2);
+ Q_ASSERT(m_attributes.attributes[0].type == GL_FLOAT);
+ Q_ASSERT(m_attributes.attributes[1].position == 1);
+ Q_ASSERT(m_attributes.attributes[1].tupleSize == 4);
+ Q_ASSERT(m_attributes.attributes[1].type == GL_UNSIGNED_BYTE);
+ return (const ColoredPoint2D *) m_data;
+}
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QSGGEOMETRY_H
diff --git a/src/declarative/scenegraph/coreapi/qsgmaterial.cpp b/src/declarative/scenegraph/coreapi/qsgmaterial.cpp
new file mode 100644
index 0000000000..afec4a59f3
--- /dev/null
+++ b/src/declarative/scenegraph/coreapi/qsgmaterial.cpp
@@ -0,0 +1,535 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgmaterial.h"
+#include "qsgrenderer_p.h"
+
+QT_BEGIN_NAMESPACE
+
+
+/*!
+ \class QSGMaterialShader
+ \brief The QSGMaterialShader class implements a material renders geometry.
+
+ The QSGMaterial and QSGMaterialShader form a tight relationship. For one
+ scene graph (including nested graphs), there is one unique QSGMaterialShader
+ instance which encapsulates the QGLShaderProgram the scene graph uses
+ to render that material, such as a shader to flat coloring of geometry.
+ Each QSGGeometryNode can have a unique QSGMaterial containing the
+ how the shader should be configured when drawing that node, such as
+ the actual color to used to render the geometry.
+
+ An instance of QSGMaterialShader is never created explicitely by the user,
+ it will be created on demand by the scene graph through
+ QSGMaterial::createShader(). The scene graph will make sure that there
+ is only one instance of each shader implementation through a scene graph.
+
+ The source code returned from vertexShader() is used to control what the
+ material does with the vertiex data that comes in from the geometry.
+ The source code returned from the fragmentShader() is used to control
+ what how the material should fill each individual pixel in the geometry.
+ The vertex and fragment source code is queried once during initialization,
+ changing what is returned from these functions later will not have
+ any effect.
+
+ The activate() function is called by the scene graph when a shader is
+ is starting to be used. The deactivate function is called by the scene
+ graph when the shader is no longer going to be used. While active,
+ the scene graph may make one or more calls to updateState() which
+ will update the state of the shader for each individual geometry to
+ render.
+
+ The attributeNames() returns the name of the attributes used in the
+ vertexShader(). These are used in the default implementation of
+ activate() and deactive() to decide whice vertex registers are enabled.
+
+ The initialize() function is called during program creation to allow
+ subclasses to prepare for use, such as resolve uniform names in the
+ vertexShader() and fragmentShader().
+
+ A minimal example:
+ \code
+ class Shader : public QSGMaterialShader
+ {
+ public:
+ const char *vertexShader() const {
+ return
+ "attribute highp vec4 vertex; \n"
+ "uniform highp mat4 matrix; \n"
+ "void main() { \n"
+ " gl_Position = matrix * vertex; \n"
+ "}";
+ }
+
+ const char *fragmentShader() const {
+ return
+ "uniform lowp float opacity; \n"
+ "void main() { \n"
+ " gl_FragColor = vec4(1, 0, 0, 1) * opacity; \n"
+ "}";
+ }
+
+ char const *const *attributeNames() const
+ {
+ static char const *const names[] = { "vertex", 0 };
+ return names;
+ }
+
+ void initialize()
+ {
+ QSGMaterialShader::initialize();
+ m_id_matrix = program()->uniformLocation("matrix");
+ m_id_opacity = program()->uniformLocation("opacity");
+ }
+
+ void updateState(const RenderState &state, QSGMaterial *newMaterial, QSGMaterial *oldMaterial)
+ {
+ Q_ASSERT(program()->isLinked());
+ if (state.isMatrixDirty())
+ program()->setUniformValue(m_id_matrix, state.combinedMatrix());
+ if (state.isOpacityDirty())
+ program()->setUniformValue(m_id_opacity, state.opacity());
+ }
+
+ private:
+ int m_id_matrix;
+ int m_id_opacity;
+ };
+ \endcode
+
+ \warning Instances of QSGMaterialShader belongs to the Scene Graph rendering
+ thread, and cannot be used from the GUI thread.
+
+ */
+
+
+
+/*!
+ Creates a new QSGMaterialShader.
+ */
+QSGMaterialShader::QSGMaterialShader()
+{
+}
+
+
+
+/*!
+ \fn QGLShaderProgram *QSGMaterialShader::program() const
+
+ Returns the shader program used by this QSGMaterialShader.
+ */
+
+
+
+/*!
+ This function is called by the scene graph to indicate that geometry is
+ about to be rendered using this shader.
+
+ State that is global for all uses of the shader, independent of the geometry
+ that is being drawn, can be setup in this function.
+
+ If reimplemented, make sure to either call the base class implementation to
+ enable the vertex attribute registers.
+ */
+
+void QSGMaterialShader::activate()
+{
+ Q_ASSERT(program()->isLinked());
+
+ program()->bind();
+ char const *const *attr = attributeNames();
+ for (int i = 0; attr[i]; ++i) {
+ if (*attr[i])
+ program()->enableAttributeArray(i);
+ }
+}
+
+
+
+/*!
+ This function is called by the scene graph to indicate that geometry will
+ no longer to be rendered using this shader.
+
+ If reimplemented, make sure to either call the base class implementation to
+ disable the vertex attribute registers.
+ */
+
+void QSGMaterialShader::deactivate()
+{
+ char const *const *attr = attributeNames();
+ for (int i = 0; attr[i]; ++i) {
+ if (*attr[i])
+ program()->disableAttributeArray(i);
+ }
+}
+
+
+
+/*!
+ This function is called by the scene graph before geometry is rendered
+ to make sure the shader is in the right state.
+
+ The current rendering \a state is passed from the scene graph. If the state
+ indicates that any state is dirty, the updateState implementation must
+ update accordingly for the geometry to render correctly.
+
+ The subclass specific state, such as the color of a flat color material, should
+ be extracted from \a newMaterial to update the color uniforms accordingly.
+
+ The \a oldMaterial can be used to minimze state changes when updating
+ material states. The \a oldMaterial is 0 if this shader was just activated.
+
+ \sa activate(), deactivate()
+ */
+
+void QSGMaterialShader::updateState(const RenderState &state, QSGMaterial *newMaterial, QSGMaterial *oldMaterial)
+{
+}
+
+
+
+/*!
+ This function is called when the shader is initialized to compile the
+ actual QGLShaderProgram. Do not call it explicitely.
+
+ The default implementation will extract the vertexShader() and
+ fragmentShader() and bind the names returned from attributeNames()
+ to consecutive vertex attribute registers starting at 0.
+ */
+
+void QSGMaterialShader::compile()
+{
+ Q_ASSERT_X(!m_program.isLinked(), "QSGSMaterialShader::compile()", "Compile called multiple times!");
+
+ program()->addShaderFromSourceCode(QGLShader::Vertex, vertexShader());
+ program()->addShaderFromSourceCode(QGLShader::Fragment, fragmentShader());
+
+ char const *const *attr = attributeNames();
+#ifndef QT_NO_DEBUG
+ int maxVertexAttribs = 0;
+ glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &maxVertexAttribs);
+ for (int i = 0; attr[i]; ++i) {
+ if (i >= maxVertexAttribs) {
+ qFatal("List of attribute names is either too long or not null-terminated.\n"
+ "Maximum number of attributes on this hardware is %i.\n"
+ "Vertex shader:\n%s\n"
+ "Fragment shader:\n%s\n",
+ maxVertexAttribs, vertexShader(), fragmentShader());
+ }
+ if (*attr[i])
+ program()->bindAttributeLocation(attr[i], i);
+ }
+#else
+ for (int i = 0; attr[i]; ++i) {
+ if (*attr[i])
+ program()->bindAttributeLocation(attr[i], i);
+ }
+#endif
+
+ if (!program()->link()) {
+ qWarning("QSGMaterialShader: Shader compilation failed:");
+ qWarning() << program()->log();
+ }
+}
+
+
+
+/*!
+ \class QSGMaterialShader::RenderState
+ \brief The QSGMaterialShader::RenderState encapsulates the current rendering state
+ during a call to QSGMaterialShader::updateState().
+
+ The render state contains a number of accessors that the shader needs to respect
+ in order to conform to the current state of the scene graph.
+
+ The instance is only valid inside a call to QSGMaterialShader::updateState() and
+ should not be used outisde this function.
+ */
+
+
+
+/*!
+ \enum QSGMaterialShader::RenderState::DirtyState
+
+ \value DirtyMatrix Used to indicate that the matrix has changed and must be updated.
+
+ \value DirtyOpacity Used to indicate that the opacity has changed and must be updated.
+ */
+
+
+
+/*!
+ \fn bool QSGMaterialShader::RenderState::isMatrixDirty() const
+
+ Convenience function to check if the dirtyStates() indicates that the matrix
+ needs to be updated.
+ */
+
+
+
+/*!
+ \fn bool QSGMaterialShader::RenderState::isOpacityDirty() const
+
+ Conveience function to check if the dirtyStates() indicates that the opacity
+ needs to be updated.
+ */
+
+
+
+/*!
+ \fn QSGMaterialShader::RenderState::DirtyStates QSGMaterialShader::RenderState::dirtyStates() const
+
+ Returns which rendering states that have changed and needs to be updated
+ for geometry rendered with this material to conform to the current
+ rendering state.
+ */
+
+
+
+/*!
+ Returns the accumulated opacity to be used for rendering
+ */
+
+float QSGMaterialShader::RenderState::opacity() const
+{
+ Q_ASSERT(m_data);
+ return static_cast<const QSGRenderer *>(m_data)->renderOpacity();
+}
+
+
+
+/*!
+ Returns the matrix combined of modelview matrix and project matrix.
+ */
+
+QMatrix4x4 QSGMaterialShader::RenderState::combinedMatrix() const
+{
+ Q_ASSERT(m_data);
+ return static_cast<const QSGRenderer *>(m_data)->combinedMatrix();
+}
+
+
+
+/*!
+ Returns the model view matrix.
+ */
+
+QMatrix4x4 QSGMaterialShader::RenderState::modelViewMatrix() const
+{
+ Q_ASSERT(m_data);
+ return const_cast<QSGRenderer *>(static_cast<const QSGRenderer *>(m_data))->modelViewMatrix().top();
+}
+
+
+
+/*!
+ Returns the viewport rect of the surface being rendered to.
+ */
+
+QRect QSGMaterialShader::RenderState::viewportRect() const
+{
+ Q_ASSERT(m_data);
+ return static_cast<const QSGRenderer *>(m_data)->viewportRect();
+}
+
+
+
+/*!
+ Returns the device rect of the surface being rendered to
+ */
+
+QRect QSGMaterialShader::RenderState::deviceRect() const
+{
+ Q_ASSERT(m_data);
+ return static_cast<const QSGRenderer *>(m_data)->deviceRect();
+}
+
+
+
+/*!
+ Returns the QGLContext that is being used for rendering
+ */
+
+const QGLContext *QSGMaterialShader::RenderState::context() const
+{
+ return static_cast<const QSGRenderer *>(m_data)->glContext();
+}
+
+
+#ifndef QT_NO_DEBUG
+static int qt_material_count = 0;
+
+static void qt_print_material_count()
+{
+ qDebug("Number of leaked materials: %i", qt_material_count);
+ qt_material_count = -1;
+}
+#endif
+
+/*!
+ \class QSGMaterialType
+ \brief The QSGMaterialType class is used as a unique type token in combination with QSGMaterial.
+
+ It serves no purpose outside the QSGMaterial::type() function.
+ */
+
+/*!
+ \class QSGMaterial
+ \brief The QSGMaterial class encapsulates rendering state for a shader program.
+
+ The QSGMaterial and QSGMaterialShader subclasses form a tight relationship. For
+ one scene graph (including nested graphs), there is one unique QSGMaterialShader
+ instance which encapsulates the QGLShaderProgram the scene graph uses
+ to render that material, such as a shader to flat coloring of geometry.
+ Each QSGGeometryNode can have a unique QSGMaterial containing the
+ how the shader should be configured when drawing that node, such as
+ the actual color to used to render the geometry.
+
+ The QSGMaterial has two virtual functions that both need to be implemented.
+ The function type() should return a unique instance for all instances of a
+ specific subclass. The createShader() function should return a new instance
+ of QSGMaterialShader, specific to the subclass of QSGMaterial.
+
+ A minimal QSGMaterial implementation could look like this:
+ \code
+ class Material : public QSGMaterial
+ {
+ public:
+ QSGMaterialType *type() const { static QSGMaterialType type; return &type; }
+ QSGMaterialShader *createShader() const { return new Shader; }
+ };
+ \endcode
+
+ \warning Instances of QSGMaterial belongs to the Scene Graph rendering thread,
+ and cannot be used from the GUI thread.
+ */
+
+QSGMaterial::QSGMaterial()
+ : m_flags(0)
+{
+#ifndef QT_NO_DEBUG
+ ++qt_material_count;
+ static bool atexit_registered = false;
+ if (!atexit_registered) {
+ atexit(qt_print_material_count);
+ atexit_registered = true;
+ }
+#endif
+}
+
+QSGMaterial::~QSGMaterial()
+{
+#ifndef QT_NO_DEBUG
+ --qt_material_count;
+ if (qt_material_count < 0)
+ qDebug("Material destroyed after qt_print_material_count() was called.");
+#endif
+}
+
+
+
+/*!
+ \enum QSGMaterial::Flag
+
+ \value Blending Set this flag to true if the material requires GL_BLEND to be
+ enabled during rendering.
+ */
+
+
+
+/*!
+ Sets the flags \a flags on this material if \a on is true;
+ otherwise clears the attribute.
+*/
+
+void QSGMaterial::setFlag(Flags flags, bool on)
+{
+ if (on)
+ m_flags |= flags;
+ else
+ m_flags &= ~flags;
+}
+
+
+
+/*!
+ Compares this material to \a other and returns 0 if they are equal; -1 if
+ this material should sort before \a other and 1 if \a other should sort
+ before.
+
+ The scene graph can reorder geometry nodes to minimize state changes.
+ The compare function is called during the sorting process so that
+ the materials can be sorted to minimize state changes in each
+ call to QSGMaterialShader::updateState().
+
+ The this pointer and \a other is guaranteed to have the same type().
+ */
+
+int QSGMaterial::compare(const QSGMaterial *other) const
+{
+ Q_ASSERT(other && type() == other->type());
+ return qint64(this) - qint64(other);
+}
+
+
+
+/*!
+ \fn QSGMaterialType QSGMaterial::type() const
+
+ This function is called by the scene graph to return a unique instance
+ per subclass.
+ */
+
+
+
+/*!
+ \fn QSGMaterialShader *QSGMaterial::createShader() const
+
+ This function returns a new instance of a the QSGMaterialShader
+ implementatation used to render geometry for a specifc implementation
+ of QSGMaterial.
+
+ The function will be called only once for each material type that
+ exists in the scene graph and will be cached internally.
+*/
+
+
+QT_END_NAMESPACE
diff --git a/src/declarative/scenegraph/coreapi/qsgmaterial.h b/src/declarative/scenegraph/coreapi/qsgmaterial.h
new file mode 100644
index 0000000000..66e37c5cde
--- /dev/null
+++ b/src/declarative/scenegraph/coreapi/qsgmaterial.h
@@ -0,0 +1,144 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef MATERIAL_H
+#define MATERIAL_H
+
+#include <qglshaderprogram.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QSGMaterial;
+
+class Q_DECLARATIVE_EXPORT QSGMaterialShader
+{
+public:
+ class Q_DECLARATIVE_EXPORT RenderState {
+ public:
+ enum DirtyState
+ {
+ DirtyMatrix = 0x0001,
+ DirtyOpacity = 0x0002
+ };
+ Q_DECLARE_FLAGS(DirtyStates, DirtyState)
+
+ inline DirtyStates dirtyStates() const { return m_dirty; }
+
+ inline bool isMatrixDirty() const { return m_dirty & DirtyMatrix; }
+ inline bool isOpacityDirty() const { return m_dirty & DirtyOpacity; }
+
+ float opacity() const;
+ QMatrix4x4 combinedMatrix() const;
+ QMatrix4x4 modelViewMatrix() const;
+ QRect viewportRect() const;
+ QRect deviceRect() const;
+
+ const QGLContext *context() const;
+
+ private:
+ friend class QSGRenderer;
+ DirtyStates m_dirty;
+ const void *m_data;
+ };
+
+ QSGMaterialShader();
+
+ virtual void activate();
+ virtual void deactivate();
+ // First time a material is used, oldMaterial is null.
+ virtual void updateState(const RenderState &state, QSGMaterial *newMaterial, QSGMaterial *oldMaterial);
+ virtual char const *const *attributeNames() const = 0; // Array must end with null.
+
+ inline QGLShaderProgram *program() { return &m_program; }
+
+protected:
+
+ friend class QSGContext;
+
+ virtual void compile();
+ virtual void initialize() { }
+
+ virtual const char *vertexShader() const = 0;
+ virtual const char *fragmentShader() const = 0;
+
+private:
+ QGLShaderProgram m_program;
+ void *m_reserved;
+};
+
+struct QSGMaterialType { };
+
+class Q_DECLARATIVE_EXPORT QSGMaterial
+{
+public:
+ enum Flag {
+ Blending = 0x0001
+ };
+ Q_DECLARE_FLAGS(Flags, Flag)
+
+ QSGMaterial();
+ virtual ~QSGMaterial();
+
+ virtual QSGMaterialType *type() const = 0;
+ virtual QSGMaterialShader *createShader() const = 0;
+ virtual int compare(const QSGMaterial *other) const;
+
+ QSGMaterial::Flags flags() const { return m_flags; }
+ void setFlag(Flags flags, bool on = true);
+
+private:
+ Flags m_flags;
+ void *m_reserved;
+ Q_DISABLE_COPY(QSGMaterial)
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QSGMaterial::Flags)
+Q_DECLARE_OPERATORS_FOR_FLAGS(QSGMaterialShader::RenderState::DirtyStates)
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/declarative/scenegraph/coreapi/qsgmatrix4x4stack.cpp b/src/declarative/scenegraph/coreapi/qsgmatrix4x4stack.cpp
new file mode 100644
index 0000000000..07ba21d17c
--- /dev/null
+++ b/src/declarative/scenegraph/coreapi/qsgmatrix4x4stack.cpp
@@ -0,0 +1,380 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgmatrix4x4stack.h"
+#include "qsgmatrix4x4stack_p.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QSGMatrix4x4Stack
+ \brief The QSGMatrix4x4Stack class manages stacks of transformation matrices in GL applications.
+ \since 4.8
+ \ingroup qt3d
+ \ingroup qt3d::enablers
+
+ Transformation matrices are one of the basic building blocks of
+ 3D applications, allowing object models to be positioned, scaled,
+ rotated, and projected onto the screen.
+
+ GL systems support several standard kinds of matrices, particularly
+ modelview and projection matrices. These matrices are typically
+ organized into stacks, which allow the current matrix state to be
+ saved with push() and restored later with pop().
+
+ QSGMatrix4x4Stack assists QGLPainter with the management of matrix
+ stacks, providing operations to set and modify transformation
+ matrices in each of the standard matrix stacks.
+
+ In the following example, a standard orthographic projection matrix for a
+ view is set via the QGLPainter::projectionMatrix() stack, and
+ then a modelview matrix is set via the QGLPainter::modelViewMatrix()
+ stack to scale and translate an object prior to drawing:
+
+ \code
+ QGLPainter painter(this);
+
+ QMatrix4x4 projm;
+ projm.ortho(window->rect());
+ painter.projectionMatrix() = projm;
+
+ painter.modelViewMatrix().setToIdentity();
+ painter.modelViewMatrix().translate(-1.0f, 2.0f, 0.0f);
+ painter.modelViewMatrix().scale(0.5f);
+ \endcode
+
+ Later, the application can save the current modelview matrix state
+ and draw a different object with a different modelview matrix:
+
+ \code
+ painter.modelViewMatrix().push();
+ painter.modelViewMatrix().setToIdentity();
+ painter.modelViewMatrix().scale(2.0f);
+ \endcode
+
+ For efficiency, the matrix values are kept client-side until they
+ are needed by a QGLPainter::draw() operation. Until then, changes
+ to the matrix will not be reflected in the GL server. The application
+ can force the GL server to update the server with a call to
+ QGLPainter::update().
+
+ QSGMatrix4x4Stack is supported on all GL platforms, including OpenGL/ES 2.0
+ which doesn't support matrix stacks natively. On that platform, the
+ matrix stack is simulated in client memory. When the application
+ selects a shader program to draw under OpenGL/ES 2.0, it calls
+ top() to obtain the actual value to be set on the shader program.
+
+ \sa QGLPainter
+*/
+
+/*!
+ Creates a matrix stack.
+*/
+QSGMatrix4x4Stack::QSGMatrix4x4Stack()
+ : d_ptr(new QSGMatrix4x4StackPrivate)
+{
+}
+
+/*!
+ Destroy this matrix stack.
+*/
+QSGMatrix4x4Stack::~QSGMatrix4x4Stack()
+{
+}
+
+/*!
+ Pushes the current matrix onto the matrix stack. The matrix can
+ be restored with pop(). The new top of stack will have the
+ same value as the previous top of stack.
+
+ The depths of the traditional \c{GL_MODELVIEW} and \c{GL_PROJECTION}
+ matrix stacks in the GL server are system-dependent and easy to
+ overflow in nested rendering code using \c{glPushMatrix()}.
+ By contrast, the push() function provides an arbitrary-sized stack
+ in client memory.
+
+ \sa pop(), top()
+*/
+void QSGMatrix4x4Stack::push()
+{
+ Q_D(QSGMatrix4x4Stack);
+ d->stack.push(d->matrix);
+}
+
+/*!
+ Pops the top-most matrix from this matrix stack and sets the
+ current matrix to the next value down. Does nothing if the
+ matrix stack contains a single entry.
+
+ \sa push()
+*/
+void QSGMatrix4x4Stack::pop()
+{
+ Q_D(QSGMatrix4x4Stack);
+ if (!d->stack.isEmpty())
+ d->matrix = d->stack.pop();
+ d->isDirty = true;
+}
+
+/*!
+ Set the matrix at the top of this matrix stack to the identity matrix.
+
+ \sa operator=()
+*/
+void QSGMatrix4x4Stack::setToIdentity()
+{
+ Q_D(QSGMatrix4x4Stack);
+ d->matrix.setToIdentity();
+ d->isDirty = true;
+}
+
+/*!
+ Returns a const reference to the current matrix at the top of this
+ matrix stack. This is typically used to fetch the matrix so it can
+ be set on user-defined shader programs.
+
+ \sa operator=()
+*/
+const QMatrix4x4 &QSGMatrix4x4Stack::top() const
+{
+ Q_D(const QSGMatrix4x4Stack);
+ return d->matrix;
+}
+
+/*!
+ \fn QSGMatrix4x4Stack::operator const QMatrix4x4 &() const
+
+ Returns a const reference to the current matrix at the top of
+ this matrix stack.
+
+ \sa top()
+*/
+
+/*!
+ Assigns \a matrix to the matrix at the top of this matrix stack.
+
+ \sa top()
+*/
+QSGMatrix4x4Stack& QSGMatrix4x4Stack::operator=(const QMatrix4x4& matrix)
+{
+ Q_D(QSGMatrix4x4Stack);
+ d->matrix = matrix;
+ d->isDirty = true;
+ return *this;
+}
+
+/*!
+ Multiplies the matrix at the top of this matrix stack by \a matrix.
+
+ \sa top()
+*/
+QSGMatrix4x4Stack& QSGMatrix4x4Stack::operator*=(const QMatrix4x4& matrix)
+{
+ Q_D(QSGMatrix4x4Stack);
+ d->matrix *= matrix;
+ d->isDirty = true;
+ return *this;
+}
+
+/*!
+ Multiplies the current matrix at the top of this matrix stack by another
+ that translates coordinates by (\a x, \a y, \a z). The following example
+ translates the modelview matrix by (1, -3, 0):
+
+ \code
+ QGLPainter painter(this);
+ painter.modelViewMatrix().translate(1.0f, -3.0f, 0.0f);
+ \endcode
+
+ \sa scale(), rotate()
+*/
+void QSGMatrix4x4Stack::translate(qreal x, qreal y, qreal z)
+{
+ Q_D(QSGMatrix4x4Stack);
+ d->matrix.translate(x, y, z);
+ d->isDirty = true;
+}
+
+/*!
+ Multiplies the current matrix at the top of this matrix statck by another
+ that translates coordinates by the components of \a vector.
+
+ \sa scale(), rotate()
+*/
+void QSGMatrix4x4Stack::translate(const QVector3D& vector)
+{
+ Q_D(QSGMatrix4x4Stack);
+ d->matrix.translate(vector);
+ d->isDirty = true;
+}
+
+/*!
+ Multiplies the current matrix at the top of this matrix stack by another
+ that scales coordinates by the components \a x, \a y, and \a z.
+ The following example scales the modelview matrix by (1, 2, 1):
+
+ \code
+ QGLPainter painter(this);
+ painter.modelViewMatrix().scale(1.0f, 2.0f, 1.0f);
+ \endcode
+
+ \sa translate(), rotate()
+*/
+void QSGMatrix4x4Stack::scale(qreal x, qreal y, qreal z)
+{
+ Q_D(QSGMatrix4x4Stack);
+ d->matrix.scale(x, y, z);
+ d->isDirty = true;
+}
+
+/*!
+ Multiplies the current matrix at the top of this matrix stack by another
+ that scales coordinates by the given \a factor. The following example
+ scales the modelview matrix by a factor of 2:
+
+ \code
+ QGLPainter painter(this);
+ painter.modelViewMatrix().scale(2.0f);
+ \endcode
+
+ \sa translate(), rotate()
+*/
+void QSGMatrix4x4Stack::scale(qreal factor)
+{
+ Q_D(QSGMatrix4x4Stack);
+ d->matrix.scale(factor);
+ d->isDirty = true;
+}
+
+/*!
+ Multiplies the current matrix at the top of this matrix stack by another
+ that scales coordinates by the components of \a vector.
+
+ \sa translate(), rotate()
+*/
+void QSGMatrix4x4Stack::scale(const QVector3D& vector)
+{
+ Q_D(QSGMatrix4x4Stack);
+ d->matrix.scale(vector);
+ d->isDirty = true;
+}
+
+/*!
+ Multiplies the current matrix at the top of this matrix stack by another
+ that rotates coordinates through \a angle degrees about the vector
+ (\a x, \a y, \a z). The following example rotates the modelview
+ matrix by 45 degress about the vector (1, -3, 0):
+
+ \code
+ QGLPainter painter(this);
+ painter.modelViewMatrix().rotate(45.0f, 1.0f, -3.0f, 0.0f);
+ \endcode
+
+ \sa scale(), translate()
+*/
+void QSGMatrix4x4Stack::rotate(qreal angle, qreal x, qreal y, qreal z)
+{
+ Q_D(QSGMatrix4x4Stack);
+ d->matrix.rotate(angle, x, y, z);
+ d->isDirty = true;
+}
+
+/*!
+ Multiplies the current matrix at the top of this matrix stack by another
+ that rotates coordinates through \a angle degrees about \a vector.
+
+ \sa scale(), translate()
+*/
+void QSGMatrix4x4Stack::rotate(qreal angle, const QVector3D& vector)
+{
+ Q_D(QSGMatrix4x4Stack);
+ d->matrix.rotate(angle, vector);
+ d->isDirty = true;
+}
+
+/*!
+ Multiplies the current matrix at the top of this matrix stack by the
+ \a quaternion. Thus \c {painter->modelViewMatrix().rotate(quaternion)}
+ is equivalent to the following code:
+ \code
+ QMatrix4x4 mat;
+ mat.rotate(quaternion);
+ painter->modelViewMatrix() *= mat;
+ \endcode
+ which rotates coordinates according to the given \a quaternion.
+
+ \sa scale(), translate()
+*/
+void QSGMatrix4x4Stack::rotate(const QQuaternion &quaternion)
+{
+ Q_D(QSGMatrix4x4Stack);
+ d->matrix.rotate(quaternion);
+ d->isDirty = true;
+}
+
+/*!
+ Returns true if the top of this matrix stack has been modified;
+ false otherwise.
+
+ \sa setDirty()
+*/
+bool QSGMatrix4x4Stack::isDirty() const
+{
+ Q_D(const QSGMatrix4x4Stack);
+ return d->isDirty;
+}
+
+/*!
+ Sets the \a dirty flag on this matrix stack, which indicates
+ if it has been modified.
+
+ A matrix stack may also be set to dirty by translate(),
+ scale(), operator*(), etc.
+
+ \sa isDirty()
+*/
+void QSGMatrix4x4Stack::setDirty(bool dirty)
+{
+ Q_D(QSGMatrix4x4Stack);
+ d->isDirty = dirty;
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/scenegraph/coreapi/qsgmatrix4x4stack.h b/src/declarative/scenegraph/coreapi/qsgmatrix4x4stack.h
new file mode 100644
index 0000000000..2336598fdc
--- /dev/null
+++ b/src/declarative/scenegraph/coreapi/qsgmatrix4x4stack.h
@@ -0,0 +1,104 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGMATRIX4X4STACK_H
+#define QSGMATRIX4X4STACK_H
+
+#include <QtGui/qmatrix4x4.h>
+#include <QtCore/qscopedpointer.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QSGMatrix4x4StackPrivate;
+
+class Q_DECLARATIVE_EXPORT QSGMatrix4x4Stack
+{
+public:
+ QSGMatrix4x4Stack();
+ ~QSGMatrix4x4Stack();
+
+ const QMatrix4x4 &top() const;
+
+ void push();
+ void pop();
+
+ void setToIdentity();
+
+ void translate(qreal x, qreal y, qreal z);
+ void translate(const QVector3D& vector);
+ void scale(qreal x, qreal y, qreal z);
+ void scale(qreal factor);
+ void scale(const QVector3D& vector);
+ void rotate(qreal angle, qreal x, qreal y, qreal z);
+ void rotate(qreal angle, const QVector3D& vector);
+ void rotate(const QQuaternion &quaternion);
+
+ QSGMatrix4x4Stack& operator=(const QMatrix4x4& matrix);
+ QSGMatrix4x4Stack& operator*=(const QMatrix4x4& matrix);
+
+ operator const QMatrix4x4 &() const;
+
+ bool isDirty() const;
+ void setDirty(bool dirty);
+
+private:
+ Q_DISABLE_COPY(QSGMatrix4x4Stack)
+ Q_DECLARE_PRIVATE(QSGMatrix4x4Stack)
+
+ QScopedPointer<QSGMatrix4x4StackPrivate> d_ptr;
+
+ friend class QGLPainter;
+};
+
+inline QSGMatrix4x4Stack::operator const QMatrix4x4 &() const
+{
+ return top();
+}
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/declarative/scenegraph/coreapi/qsgmatrix4x4stack_p.h b/src/declarative/scenegraph/coreapi/qsgmatrix4x4stack_p.h
new file mode 100644
index 0000000000..6e5c08ca03
--- /dev/null
+++ b/src/declarative/scenegraph/coreapi/qsgmatrix4x4stack_p.h
@@ -0,0 +1,73 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGMATRIX4X4STACK_P_H
+#define QSGMATRIX4X4STACK_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtGui/qmatrix4x4.h>
+#include <QtCore/qstack.h>
+
+QT_BEGIN_NAMESPACE
+
+class QSGMatrix4x4StackPrivate
+{
+public:
+ QSGMatrix4x4StackPrivate() : isDirty(true) {}
+
+ QMatrix4x4 matrix;
+ QStack<QMatrix4x4> stack;
+ bool isDirty;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/declarative/scenegraph/coreapi/qsgnode.cpp b/src/declarative/scenegraph/coreapi/qsgnode.cpp
new file mode 100644
index 0000000000..3472c933d7
--- /dev/null
+++ b/src/declarative/scenegraph/coreapi/qsgnode.cpp
@@ -0,0 +1,1187 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgnode.h"
+#include "qsgrenderer_p.h"
+#include "qsgnodeupdater_p.h"
+#include "qsgmaterial.h"
+
+#include "limits.h"
+
+QT_BEGIN_NAMESPACE
+
+#ifndef QT_NO_DEBUG
+static int qt_node_count = 0;
+
+static void qt_print_node_count()
+{
+ qDebug("Number of leaked nodes: %i", qt_node_count);
+ qt_node_count = -1;
+}
+#endif
+
+/*!
+ \class QSGNode
+ \bried The QSGNode class is the base class for all nodes in the scene graph.
+
+ The QSGNode class can be used as a child container. Children are added with
+ the appendChildNode(), prependChildNode(), insertChildNodeBefore() and
+ insertChildNodeAfter(). Ordering of nodes is important as geometry nodes
+ will be rendered in the order they are added to the scene graph.
+ Actually, the scene may reorder nodes freely, but the resulting visual
+ order is still guaranteed.
+
+ If nodes change every frame, the preprocess() function can be used to
+ apply changes to a node for every frame its rendered. The use of preprocess()
+ must be explicitly enabled by setting the QSGNode::UsePreprocess flag
+ on the node.
+
+ The virtual isSubtreeBlocked() function can be used to disable a subtree all
+ together. Nodes in a blocked subtree will not be preprocessed() and not
+ rendered.
+
+ Anything related to QSGNode should happen on the scene graph rendering thread.
+ */
+
+QSGNode::QSGNode()
+ : m_parent(0)
+ , m_type(BasicNodeType)
+ , m_nodeFlags(OwnedByParent)
+ , m_flags(0)
+{
+ init();
+}
+
+QSGNode::QSGNode(NodeType type)
+ : m_parent(0)
+ , m_type(type)
+ , m_nodeFlags(OwnedByParent)
+ , m_flags(0)
+{
+ init();
+}
+
+void QSGNode::init()
+{
+#ifndef QT_NO_DEBUG
+ ++qt_node_count;
+ static bool atexit_registered = false;
+ if (!atexit_registered) {
+ atexit(qt_print_node_count);
+ atexit_registered = true;
+ }
+#endif
+}
+
+QSGNode::~QSGNode()
+{
+#ifndef QT_NO_DEBUG
+ --qt_node_count;
+ if (qt_node_count < 0)
+ qDebug("Material destroyed after qt_print_node_count() was called.");
+#endif
+ destroy();
+}
+
+
+/*!
+ \fn void QSGNode::preprocess()
+
+ Override this function to do processing on the node before it is rendered.
+
+ Preprocessing needs to be explicitly enabled by setting the flag
+ QSGNode::UsePreprocess. The flag needs to be set before the node is added
+ to the scene graph and will cause the preprocess() function to be called
+ for every frame the node is rendered.
+
+ The preprocess function is called before the update pass that propegates
+ opacity and transformations through the scene graph. That means that
+ functions like QSGOpacityNode::combinedOpacity() and
+ QSGTransformNode::combinedMatrix() will not contain up-to-date values.
+ If such values are changed during the preprocess, these changes will be
+ propegated through the scene graph before it is rendered.
+
+ \warning Beware of deleting nodes while they are being preprocessed. It is
+ possible, with a small performance hit, to delete a single node during its
+ own preprocess call. Deleting a subtree which has nodes that also use
+ preprocessing may result in a segmentation fault. This is done for
+ performance reasons.
+ */
+
+
+
+
+/*!
+ \fn bool QSGNode::isSubtreeBlocked() const
+
+ Returns whether this node and its subtree is available for use.
+
+ Blocked subtrees will not get their dirty states updated and they
+ will not be rendered.
+
+ The QSGOpacityNode will return a blocked subtree when accumulated opacity
+ is 0, for instance.
+ */
+
+
+void QSGNode::destroy()
+{
+ if (m_parent) {
+ m_parent->removeChildNode(this);
+ Q_ASSERT(m_parent == 0);
+ }
+ for (int ii = m_children.count() - 1; ii >= 0; --ii) {
+ QSGNode *child = m_children.at(ii);
+ removeChildNode(child);
+ Q_ASSERT(child->m_parent == 0);
+ if (child->flags() & OwnedByParent)
+ delete child;
+ }
+ Q_ASSERT(m_children.isEmpty());
+}
+
+
+/*!
+ Prepends \a node to this node's the list of children.
+
+ Ordering of nodes is important as geometry nodes will be rendered in the
+ order they are added to the scene graph.
+ */
+
+void QSGNode::prependChildNode(QSGNode *node)
+{
+ Q_ASSERT_X(!m_children.contains(node), "QSGNode::prependChildNode", "QSGNode is already a child!");
+ Q_ASSERT_X(!node->m_parent, "QSGNode::prependChildNode", "QSGNode already has a parent");
+
+#ifndef QT_NO_DEBUG
+ if (node->type() == QSGNode::GeometryNodeType) {
+ QSGGeometryNode *g = static_cast<QSGGeometryNode *>(node);
+ Q_ASSERT_X(g->material(), "QSGNode::prependChildNode", "QSGGeometryNode is missing material");
+ Q_ASSERT_X(g->geometry(), "QSGNode::prependChildNode", "QSGGeometryNode is missing geometry");
+ }
+#endif
+
+ m_children.prepend(node);
+ node->m_parent = this;
+
+ node->markDirty(DirtyNodeAdded);
+}
+
+/*!
+ Appends \a node to this node's list of children.
+
+ Ordering of nodes is important as geometry nodes will be rendered in the
+ order they are added to the scene graph.
+ */
+
+void QSGNode::appendChildNode(QSGNode *node)
+{
+ Q_ASSERT_X(!m_children.contains(node), "QSGNode::appendChildNode", "QSGNode is already a child!");
+ Q_ASSERT_X(!node->m_parent, "QSGNode::appendChildNode", "QSGNode already has a parent");
+
+#ifndef QT_NO_DEBUG
+ if (node->type() == QSGNode::GeometryNodeType) {
+ QSGGeometryNode *g = static_cast<QSGGeometryNode *>(node);
+ Q_ASSERT_X(g->material(), "QSGNode::appendChildNode", "QSGGeometryNode is missing material");
+ Q_ASSERT_X(g->geometry(), "QSGNode::appendChildNode", "QSGGeometryNode is missing geometry");
+ }
+#endif
+
+ m_children.append(node);
+ node->m_parent = this;
+
+ node->markDirty(DirtyNodeAdded);
+}
+
+
+
+/*!
+ Inserts \a node to this node's list of children before the node specified with \a before.
+
+ Ordering of nodes is important as geometry nodes will be rendered in the
+ order they are added to the scene graph.
+ */
+
+void QSGNode::insertChildNodeBefore(QSGNode *node, QSGNode *before)
+{
+ Q_ASSERT_X(!m_children.contains(node), "QSGNode::insertChildNodeBefore", "QSGNode is already a child!");
+ Q_ASSERT_X(!node->m_parent, "QSGNode::insertChildNodeBefore", "QSGNode already has a parent");
+ Q_ASSERT_X(node->type() != RootNodeType, "QSGNode::insertChildNodeBefore", "RootNodes cannot be children of other nodes");
+
+#ifndef QT_NO_DEBUG
+ if (node->type() == QSGNode::GeometryNodeType) {
+ QSGGeometryNode *g = static_cast<QSGGeometryNode *>(node);
+ Q_ASSERT_X(g->material(), "QSGNode::insertChildNodeBefore", "QSGGeometryNode is missing material");
+ Q_ASSERT_X(g->geometry(), "QSGNode::insertChildNodeBefore", "QSGGeometryNode is missing geometry");
+ }
+#endif
+
+ int idx = before?m_children.indexOf(before):-1;
+ if (idx == -1)
+ m_children.append(node);
+ else
+ m_children.insert(idx, node);
+ node->m_parent = this;
+
+ node->markDirty(DirtyNodeAdded);
+}
+
+
+
+/*!
+ Inserts \a node to this node's list of children after the node specified with \a after.
+
+ Ordering of nodes is important as geometry nodes will be rendered in the
+ order they are added to the scene graph.
+ */
+
+void QSGNode::insertChildNodeAfter(QSGNode *node, QSGNode *after)
+{
+ Q_ASSERT_X(!m_children.contains(node), "QSGNode::insertChildNodeAfter", "QSGNode is already a child!");
+ Q_ASSERT_X(!node->m_parent, "QSGNode::insertChildNodeAfter", "QSGNode already has a parent");
+ Q_ASSERT_X(node->type() != RootNodeType, "QSGNode::insertChildNodeAfter", "RootNodes cannot be children of other nodes");
+
+#ifndef QT_NO_DEBUG
+ if (node->type() == QSGNode::GeometryNodeType) {
+ QSGGeometryNode *g = static_cast<QSGGeometryNode *>(node);
+ Q_ASSERT_X(g->material(), "QSGNode::insertChildNodeAfter", "QSGGeometryNode is missing material");
+ Q_ASSERT_X(g->geometry(), "QSGNode::insertChildNodeAfter", "QSGGeometryNode is missing geometry");
+ }
+#endif
+
+ int idx = after?m_children.indexOf(after):-1;
+ if (idx == -1)
+ m_children.append(node);
+ else
+ m_children.insert(idx + 1, node);
+ node->m_parent = this;
+
+ node->markDirty(DirtyNodeAdded);
+}
+
+
+
+/*!
+ Removes \a node fromt his node's list of children.
+ */
+
+void QSGNode::removeChildNode(QSGNode *node)
+{
+ Q_ASSERT(m_children.contains(node));
+ Q_ASSERT(node->parent() == this);
+
+ m_children.removeOne(node);
+
+ node->markDirty(DirtyNodeRemoved);
+ node->m_parent = 0;
+}
+
+
+/*!
+ Sets the flag \a f on this node if \a enabled is true;
+ otherwise clears the flag.
+
+ \sa flags()
+*/
+
+void QSGNode::setFlag(Flag f, bool enabled)
+{
+ if (enabled)
+ m_nodeFlags |= f;
+ else
+ m_nodeFlags &= ~f;
+}
+
+
+/*!
+ Sets the flags \a f on this node if \a enabled is true;
+ otherwise clears the flags.
+
+ \sa flags()
+*/
+
+void QSGNode::setFlags(Flags f, bool enabled)
+{
+ if (enabled)
+ m_nodeFlags |= f;
+ else
+ m_nodeFlags &= ~f;
+}
+
+
+
+/*!
+ Marks this node with the states in \a flags as dirty.
+
+ When a node is marked dirty, it recursively mark the parent chain
+ as dirty and notify all connected renderers that the has dirty states.
+ */
+
+void QSGNode::markDirty(DirtyFlags flags)
+{
+ m_flags |= (flags & DirtyPropagationMask);
+
+ DirtyFlags subtreeFlags = DirtyFlags((flags & DirtyPropagationMask) << 16);
+ QSGNode *p = m_parent;
+ while (p) {
+ p->m_flags |= subtreeFlags;
+ if (p->type() == RootNodeType)
+ static_cast<QSGRootNode *>(p)->notifyNodeChange(this, flags);
+ p = p->m_parent;
+ }
+}
+
+
+
+/*!
+ \class QSGBasicGeometryNode
+ \brief The QSGBasicGeometryNode serves as a baseclass for geometry based nodes
+
+ The QSGBasicGeometryNode class should not be used by itself. It is only encapsulates
+ shared functionality between the QSGGeometryNode and QSGClipNode classes.
+ */
+
+
+/*!
+ Creates a new basic geometry node.
+ */
+QSGBasicGeometryNode::QSGBasicGeometryNode(NodeType type)
+ : QSGNode(type)
+ , m_geometry(0)
+ , m_matrix(0)
+ , m_clip_list(0)
+{
+}
+
+
+/*!
+ Deletes this QSGBasicGeometryNode.
+
+ If the node has the flag QSGNode::OwnsGeometry set, it will also delete the
+ geometry object it is pointing to. This flag is not set by default.
+ */
+
+QSGBasicGeometryNode::~QSGBasicGeometryNode()
+{
+ destroy();
+ if (flags() & OwnsGeometry)
+ delete m_geometry;
+}
+
+
+/*!
+ \fn QSGGeometry *QSGBasicGeometryNode::geometry() const
+
+ Returns this node's geometry.
+
+ The geometry is null by default.
+ */
+
+
+/*!
+ Sets the geometry of this node to \a geometry.
+
+ If the node has the flag QSGNode::OwnsGeometry set, it will also delete the
+ geometry object it is pointing to. This flag is not set by default.
+ */
+
+void QSGBasicGeometryNode::setGeometry(QSGGeometry *geometry)
+{
+ if (flags() & OwnsGeometry)
+ delete m_geometry;
+ m_geometry = geometry;
+ markDirty(DirtyGeometry);
+}
+
+
+
+/*!
+ \class QSGGeometryNode
+ \brief The QSGGeometryNode class is used for all rendered content in the scene graph.
+
+ The QSGGeometryNode consists of geometry and material. The geometry defines the mesh,
+ the vertices and their structure, to be drawn. The Material defines how the shape is
+ filled.
+
+ A geometry node must have both geometry and a normal material before it is added to
+ the scene graph.
+
+ The geometry node supports two types of materials, the opaqueMaterial and the normal
+ material. The opaqueMaterial is used when the accumulated scene graph opacity at the
+ time of rendering is 1. The primary usecase is to special case opaque rendering
+ to avoid an extra operation in the fragment shader can have significant performance
+ impact on embedded graphics chips. The opaque material is optional.
+
+ */
+
+
+/*!
+ Creates a new geometry node without geometry and material.
+ */
+
+QSGGeometryNode::QSGGeometryNode()
+ : QSGBasicGeometryNode(GeometryNodeType)
+ , m_render_order(0)
+ , m_material(0)
+ , m_opaque_material(0)
+ , m_opacity(1)
+{
+}
+
+
+/*!
+ Deletes this geometry node.
+
+ The flags QSGNode::OwnsMaterial, QSGNode::OwnsOpaqueMaterial and
+ QSGNode::OwnsGeometry decides weither the geometry node should also
+ delete the materials and geometry. By default, these flags are disabled.
+ */
+
+QSGGeometryNode::~QSGGeometryNode()
+{
+ destroy();
+ if (flags() & OwnsMaterial)
+ delete m_material;
+ if (flags() & OwnsOpaqueMaterial)
+ delete m_opaque_material;
+}
+
+
+
+/*!
+ \fn int QSGGeometryNode::renderOrder() const
+
+ Returns the render order of this geometry node.
+
+ \internal
+ */
+
+
+/*!
+ Sets the render order of this node to be \a order.
+
+ GeometryNodes are rendered in an order that visually looks like
+ low order nodes are rendered prior to high order nodes. For opaque
+ geometry there is little difference as z-testing will handle
+ the discard, but for translucent objects, the rendering should
+ normally be specified in the order of back-to-front.
+
+ The default render order is 0.
+
+ \internal
+ */
+void QSGGeometryNode::setRenderOrder(int order)
+{
+ m_render_order = order;
+}
+
+
+
+/*!
+ Sets the material of this geometry node to \a material.
+
+ Geometry nodes must have a material before they can be added to the
+ scene graph.
+ */
+void QSGGeometryNode::setMaterial(QSGMaterial *material)
+{
+ if (flags() & OwnsMaterial)
+ delete m_material;
+ m_material = material;
+#ifndef QT_NO_DEBUG
+ if (m_material != 0 && m_opaque_material == m_material)
+ qWarning("QSGGeometryNode: using same material for both opaque and translucent");
+#endif
+ markDirty(DirtyMaterial);
+}
+
+
+
+/*!
+ Sets the opaque material of this geometry to \a material.
+
+ The opaque material will be preferred by the renderer over the
+ default material, as returned by the material() function, if
+ it is not null and the geometry item has an inherited opacity of
+ 1.
+
+ The opaqueness refers to scene graph opacity, the material is still
+ allowed to set QSGMaterial::Blending to true and draw transparent
+ pixels.
+ */
+void QSGGeometryNode::setOpaqueMaterial(QSGMaterial *material)
+{
+ if (flags() & OwnsOpaqueMaterial)
+ delete m_opaque_material;
+ m_opaque_material = material;
+#ifndef QT_NO_DEBUG
+ if (m_opaque_material != 0 && m_opaque_material == m_material)
+ qWarning("QSGGeometryNode: using same material for both opaque and translucent");
+#endif
+
+ markDirty(DirtyMaterial);
+}
+
+
+
+/*!
+ Returns the material which should currently be used for geometry node.
+
+ If the inherited opacity of the node is 1 and there is an opaque material
+ set on this node, it will be returned; otherwise, the default material
+ will be returned.
+
+ \warning This function requires the scene graph above this item to be
+ completely free of dirty states, so it can only be called during rendering
+
+ \internal
+
+ \sa setMaterial, setOpaqueMaterial
+ */
+QSGMaterial *QSGGeometryNode::activeMaterial() const
+{
+ Q_ASSERT_X(dirtyFlags() == 0, "QSGGeometryNode::activeMaterial()", "function assumes that all dirty states are cleaned up");
+ if (m_opaque_material && m_opacity > 0.999)
+ return m_opaque_material;
+ return m_material;
+}
+
+
+/*!
+ Sets the inherited opacity of this geometry to \a opacity.
+
+ This function is meant to be called by the node preprocessing
+ prior to rendering the tree, so it will not mark the tree as
+ dirty.
+
+ \internal
+ */
+void QSGGeometryNode::setInheritedOpacity(qreal opacity)
+{
+ Q_ASSERT(opacity >= 0 && opacity <= 1);
+ m_opacity = opacity;
+}
+
+
+/*!
+ \class QSGClipNode
+ \brief The QSGClipNode implements the clipping functionality in the scene graph.
+
+ Clipping applies to the node's subtree and can be nested. Multiple clip nodes will be
+ accumulated by intersecting all their geometries. The accumulation happens
+ as part of the rendering.
+
+ Clip nodes must have a geometry before they can be added to the scene graph.
+
+ Clipping is usually implemented by using the stencil buffer.
+ */
+
+
+
+/*!
+ Creates a new QSGClipNode without a geometry.
+
+ The clip node must have a geometry before it can be added to the
+ scene graph.
+ */
+
+QSGClipNode::QSGClipNode()
+ : QSGBasicGeometryNode(ClipNodeType)
+{
+}
+
+
+
+/*!
+ Deletes this QSGClipNode.
+
+ If the flag QSGNode::OwnsGeometry is set, the geometry will also be
+ deleted.
+ */
+
+QSGClipNode::~QSGClipNode()
+{
+ destroy();
+}
+
+
+
+/*!
+ \fn bool QSGClipNode::isRectangular() const
+
+ Returns if this clip node has a rectangular clip.
+ */
+
+
+
+/*!
+ Sets whether this clip node has a rectangular clip to \a rectHint.
+
+ This is an optimization hint which means that the renderer can
+ use scissoring instead of stencil, which is significnatly faster.
+
+ When this hint is and it is applicable, the clip region will be
+ generated from clipRect() rather than geometry().
+ */
+
+void QSGClipNode::setIsRectangular(bool rectHint)
+{
+ m_is_rectangular = rectHint;
+}
+
+
+
+/*!
+ \fn void QSGClipNode::clipRect() const
+
+ Returns the clip rect of this node.
+ */
+
+
+/*!
+ Sets the clip rect of this clip node to \a rect.
+
+ When a rectangular clip is set in combination with setIsRectangular
+ the renderer may in some cases use a more optimal clip method.
+ */
+void QSGClipNode::setClipRect(const QRectF &rect)
+{
+ m_clip_rect = rect;
+}
+
+
+/*!
+ \class QSGTransformNode
+ \brief The QSGTransformNode implements transformations in the scene graph
+
+ Transformations apply the node's subtree and can be nested. Multiple transform nodes
+ will be accumulated by intersecting all their matrices. The accumulation happens
+ as part of the rendering.
+
+ The transform nodes implement a 4x4 matrix which in theory supports full 3D
+ transformations. However, because the renderer optimizes for 2D use-cases rather
+ than 3D use-cases, rendering a scene with full 3D transformations needs to
+ be done with some care.
+ */
+
+QSGTransformNode::QSGTransformNode()
+ : QSGNode(TransformNodeType)
+{
+}
+
+
+
+/*!
+ Deletes this transform node.
+ */
+
+QSGTransformNode::~QSGTransformNode()
+{
+ destroy();
+}
+
+
+
+/*!
+ \fn QMatrix4x4 QSGTransformNode::matrix() const
+
+ Returns this transform node's matrix.
+ */
+
+
+
+/*!
+ Sets this transform node's matrix to \a matrix.
+ */
+
+void QSGTransformNode::setMatrix(const QMatrix4x4 &matrix)
+{
+ m_matrix = matrix;
+ markDirty(DirtyMatrix);
+}
+
+
+/*!
+ Sets the combined matrix of this matrix to \a transform.
+
+ This function is meant to be called by the node preprocessing
+ prior to rendering the tree, so it will not mark the tree as
+ dirty.
+
+ \internal
+ */
+void QSGTransformNode::setCombinedMatrix(const QMatrix4x4 &matrix)
+{
+ m_combined_matrix = matrix;
+}
+
+
+
+/*!
+ \class QSGRootNode
+ \brief The QSGRootNode is the toplevel root of any scene graph.
+
+ The root node is used to attach a scene graph to a renderer.
+
+ \internal
+ */
+
+
+
+/*!
+ \fn QSGRootNode::QSGRootNode()
+
+ Creates a new root node.
+ */
+
+QSGRootNode::QSGRootNode()
+ : QSGNode(RootNodeType)
+{
+}
+
+
+/*!
+ Deletes the root node.
+
+ When a root node is deleted it removes itself from all of renderers
+ that are referencing it.
+ */
+
+QSGRootNode::~QSGRootNode()
+{
+ while (!m_renderers.isEmpty())
+ m_renderers.last()->setRootNode(0);
+ destroy();
+}
+
+
+
+/*!
+ Called to notify all renderers that \a node has been marked as dirty
+ with \a flags.
+ */
+
+void QSGRootNode::notifyNodeChange(QSGNode *node, DirtyFlags flags)
+{
+ for (int i=0; i<m_renderers.size(); ++i) {
+ m_renderers.at(i)->nodeChanged(node, flags);
+ }
+}
+
+
+
+/*!
+ \class QSGOpacityNode
+ \brief The QSGOpacityNode is used
+
+ Opacity apply to its subtree and can be nested. Multiple opacity nodes
+ will be accumulated by multiplying their opacity. The accumulation happens
+ as part of the rendering.
+
+ When nested opacity gets below a certain threshold, the subtree might
+ be marked as blocked, causing isSubtreeBlocked() to return true. This
+ is done for performance reasons.
+
+ */
+
+
+
+/*!
+ Constructs an opacity node with a default opacity of 1.
+
+ Opacity accumulate downwards in the scene graph so a node with two
+ QSGOpacityNode instances above it, both with opacity of 0.5, will have
+ effective opacity of 0.25.
+
+ The default opacity of nodes is 1.
+ */
+QSGOpacityNode::QSGOpacityNode()
+ : QSGNode(OpacityNodeType)
+ , m_opacity(1)
+ , m_combined_opacity(1)
+{
+}
+
+
+
+/*!
+ Deletes the opacity node.
+ */
+
+QSGOpacityNode::~QSGOpacityNode()
+{
+ destroy();
+}
+
+
+
+/*!
+ \fn qreal QSGOpacityNode::opacity() const
+
+ Returns this opacity node's opacity.
+ */
+
+
+
+/*!
+ Sets the opacity of this node to \a opacity.
+
+ Before rendering the graph, the renderer will do an update pass
+ over the subtree to propegate the opacity to its children.
+
+ The value will be bounded to the range 0 to 1.
+ */
+
+void QSGOpacityNode::setOpacity(qreal opacity)
+{
+ opacity = qBound<qreal>(0, opacity, 1);
+ if (m_opacity == opacity)
+ return;
+ m_opacity = opacity;
+ markDirty(DirtyOpacity);
+}
+
+
+
+/*!
+ \fn qreal QSGOpacityNode::combinedOpacity() const
+
+ Returns this node's accumulated opacity.
+
+ This vaule is calculated during rendering and only stored
+ in the opacity node temporarily.
+
+ \internal
+ */
+
+
+
+/*!
+ Sets the combined opacity of this node to \a opacity.
+
+ This function is meant to be called by the node preprocessing
+ prior to rendering the tree, so it will not mark the tree as
+ dirty.
+
+ \internal
+ */
+
+void QSGOpacityNode::setCombinedOpacity(qreal opacity)
+{
+ m_combined_opacity = opacity;
+}
+
+
+
+/*!
+ For performance reasons, we block the subtree when the nested opacity
+ gets below a certain threshold.
+
+ \internal
+ */
+
+bool QSGOpacityNode::isSubtreeBlocked() const
+{
+ return m_combined_opacity < 0.001;
+}
+
+
+
+/*!
+ \class QSGNodeVisitor
+ \bried The QSGNodeVisitor class is a helper class for traversing the scene graph.
+
+ \internal
+ */
+
+QSGNodeVisitor::~QSGNodeVisitor()
+{
+
+}
+
+
+void QSGNodeVisitor::visitNode(QSGNode *n)
+{
+ switch (n->type()) {
+ case QSGNode::TransformNodeType: {
+ QSGTransformNode *t = static_cast<QSGTransformNode *>(n);
+ enterTransformNode(t);
+ visitChildren(t);
+ leaveTransformNode(t);
+ break; }
+ case QSGNode::GeometryNodeType: {
+ QSGGeometryNode *g = static_cast<QSGGeometryNode *>(n);
+ enterGeometryNode(g);
+ visitChildren(g);
+ leaveGeometryNode(g);
+ break; }
+ case QSGNode::ClipNodeType: {
+ QSGClipNode *c = static_cast<QSGClipNode *>(n);
+ enterClipNode(c);
+ visitChildren(c);
+ leaveClipNode(c);
+ break; }
+ case QSGNode::OpacityNodeType: {
+ QSGOpacityNode *o = static_cast<QSGOpacityNode *>(n);
+ enterOpacityNode(o);
+ visitChildren(o);
+ leaveOpacityNode(o);
+ break; }
+ default:
+ visitChildren(n);
+ break;
+ }
+}
+
+void QSGNodeVisitor::visitChildren(QSGNode *n)
+{
+ int count = n->childCount();
+ for (int i=0; i<count; ++i) {
+ visitNode(n->childAtIndex(i));
+ }
+}
+
+
+
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug d, const QSGGeometryNode *n)
+{
+ if (!n) {
+ d << "QSGGeometryNode(null)";
+ return d;
+ }
+ d << "QSGGeometryNode(" << hex << (void *) n << dec;
+
+ const QSGGeometry *g = n->geometry();
+
+ if (!g) {
+ d << "no geometry";
+ } else {
+
+ switch (g->drawingMode()) {
+ case GL_TRIANGLE_STRIP: d << "strip"; break;
+ case GL_TRIANGLE_FAN: d << "fan"; break;
+ case GL_TRIANGLES: d << "triangles"; break;
+ default: break;
+ }
+
+ d << g->vertexCount();
+
+ if (g->attributeCount() > 0 && g->attributes()->type == GL_FLOAT) {
+ float x1 = 1e10, x2 = -1e10, y1=1e10, y2=-1e10;
+ int stride = g->stride();
+ for (int i = 0; i < g->vertexCount(); ++i) {
+ float x = ((float *)((char *)const_cast<QSGGeometry *>(g)->vertexData() + i * stride))[0];
+ float y = ((float *)((char *)const_cast<QSGGeometry *>(g)->vertexData() + i * stride))[1];
+
+ x1 = qMin(x1, x);
+ x2 = qMax(x2, x);
+ y1 = qMin(y1, y);
+ y2 = qMax(y2, y);
+ }
+
+ d << "x1=" << x1 << "y1=" << y1 << "x2=" << x2 << "y2=" << y2;
+ }
+ }
+
+ d << "order=" << n->renderOrder();
+ if (n->material())
+ d << "effect=" << n->material() << "type=" << n->material()->type();
+
+
+ d << ")";
+#ifdef QML_RUNTIME_TESTING
+ d << n->description;
+#endif
+ d << "dirty=" << hex << (int) n->dirtyFlags() << dec;
+ return d;
+}
+
+QDebug operator<<(QDebug d, const QSGClipNode *n)
+{
+ if (!n) {
+ d << "QSGClipNode(null)";
+ return d;
+ }
+ d << "QSGClipNode(" << hex << (void *) n << dec;
+
+ if (n->childCount())
+ d << "children=" << n->childCount();
+
+ d << "is rect?" << (n->isRectangular() ? "yes" : "no");
+
+ d << ")";
+#ifdef QML_RUNTIME_TESTING
+ d << n->description;
+#endif
+ d << "dirty=" << hex << (int) n->dirtyFlags() << dec << (n->isSubtreeBlocked() ? "*BLOCKED*" : "");
+ return d;
+}
+
+QDebug operator<<(QDebug d, const QSGTransformNode *n)
+{
+ if (!n) {
+ d << "QSGTransformNode(null)";
+ return d;
+ }
+ const QMatrix4x4 m = n->matrix();
+ d << "QSGTransformNode(";
+ d << hex << (void *) n << dec;
+ if (m.isIdentity())
+ d << "identity";
+ else if (m.determinant() == 1 && m(0, 0) == 1 && m(1, 1) == 1 && m(2, 2) == 1)
+ d << "translate" << m(0, 3) << m(1, 3) << m(2, 3);
+ else
+ d << "det=" << n->matrix().determinant();
+#ifdef QML_RUNTIME_TESTING
+ d << n->description;
+#endif
+ d << "dirty=" << hex << (int) n->dirtyFlags() << dec << (n->isSubtreeBlocked() ? "*BLOCKED*" : "");
+ d << ")";
+ return d;
+}
+
+QDebug operator<<(QDebug d, const QSGOpacityNode *n)
+{
+ if (!n) {
+ d << "QSGOpacityNode(null)";
+ return d;
+ }
+ d << "QSGOpacityNode(";
+ d << hex << (void *) n << dec;
+ d << "opacity=" << n->opacity()
+ << "combined=" << n->combinedOpacity()
+ << (n->isSubtreeBlocked() ? "*BLOCKED*" : "");
+#ifdef QML_RUNTIME_TESTING
+ d << n->description;
+#endif
+ d << "dirty=" << hex << (int) n->dirtyFlags() << dec;
+ d << ")";
+ return d;
+}
+
+
+QDebug operator<<(QDebug d, const QSGRootNode *n)
+{
+ if (!n) {
+ d << "QSGRootNode(null)";
+ return d;
+ }
+ d << "QSGRootNode" << hex << (void *) n << "dirty=" << (int) n->dirtyFlags() << dec
+ << (n->isSubtreeBlocked() ? "*BLOCKED*" : "");
+#ifdef QML_RUNTIME_TESTING
+ d << n->description;
+#endif
+ d << ")";
+ return d;
+}
+
+
+
+QDebug operator<<(QDebug d, const QSGNode *n)
+{
+ if (!n) {
+ d << "QSGNode(null)";
+ return d;
+ }
+ switch (n->type()) {
+ case QSGNode::GeometryNodeType:
+ d << static_cast<const QSGGeometryNode *>(n);
+ break;
+ case QSGNode::TransformNodeType:
+ d << static_cast<const QSGTransformNode *>(n);
+ break;
+ case QSGNode::ClipNodeType:
+ d << static_cast<const QSGClipNode *>(n);
+ break;
+ case QSGNode::RootNodeType:
+ d << static_cast<const QSGRootNode *>(n);
+ break;
+ case QSGNode::OpacityNodeType:
+ d << static_cast<const QSGOpacityNode *>(n);
+ break;
+ default:
+ d << "QSGNode(" << hex << (void *) n << dec
+ << "dirty=" << hex << (int) n->dirtyFlags() << dec
+ << (n->isSubtreeBlocked() ? "*BLOCKED*" : "");
+#ifdef QML_RUNTIME_TESTING
+ d << n->description;
+#endif
+ d << ")";
+ break;
+ }
+ return d;
+}
+
+
+/*!
+ \class QSGNodeDumper
+ \brief The QSGNodeDumper class provides a way of dumping a scene grahp to the console.
+
+ This class is solely for debugging purposes.
+
+ \internal
+ */
+
+void QSGNodeDumper::dump(QSGNode *n)
+{
+ QSGNodeDumper dump;
+ dump.visitNode(n);
+}
+
+void QSGNodeDumper::visitNode(QSGNode *n)
+{
+ if (n->isSubtreeBlocked())
+ return;
+ qDebug() << QString(m_indent * 2, QLatin1Char(' ')) << n;
+ QSGNodeVisitor::visitNode(n);
+}
+
+void QSGNodeDumper::visitChildren(QSGNode *n)
+{
+ ++m_indent;
+ QSGNodeVisitor::visitChildren(n);
+ --m_indent;
+}
+
+#endif
+
+QT_END_NAMESPACE
diff --git a/src/declarative/scenegraph/coreapi/qsgnode.h b/src/declarative/scenegraph/coreapi/qsgnode.h
new file mode 100644
index 0000000000..a391b55bc5
--- /dev/null
+++ b/src/declarative/scenegraph/coreapi/qsgnode.h
@@ -0,0 +1,359 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef NODE_H
+#define NODE_H
+
+#include "qsggeometry.h"
+#include <QtGui/QMatrix4x4>
+
+#include <float.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+#define QML_RUNTIME_TESTING
+
+class QSGRenderer;
+
+class QSGNode;
+class QSGRootNode;
+class QSGGeometryNode;
+class QSGTransformNode;
+class QSGClipNode;
+
+class Q_DECLARATIVE_EXPORT QSGNode
+{
+public:
+ enum NodeType {
+ BasicNodeType,
+ RootNodeType,
+ GeometryNodeType,
+ TransformNodeType,
+ ClipNodeType,
+ OpacityNodeType,
+ UserNodeType = 1024
+ };
+
+ enum DirtyFlag {
+ DirtyMatrix = 0x0001,
+ DirtyClipList = 0x0002,
+ DirtyNodeAdded = 0x0004,
+ DirtyNodeRemoved = 0x0008,
+ DirtyGeometry = 0x0010,
+ DirtyRenderOrder = 0x0020,
+ DirtyMaterial = 0x0040,
+ DirtyOpacity = 0x0080,
+ DirtyForceUpdate = 0x0100,
+ DirtyAll = 0xffff,
+
+ DirtyPropagationMask = DirtyMatrix
+ | DirtyClipList
+ | DirtyNodeAdded
+ | DirtyOpacity
+ | DirtyForceUpdate,
+
+ };
+ Q_DECLARE_FLAGS(DirtyFlags, DirtyFlag)
+
+ enum Flag {
+ // Lower 16 bites reserved for general node
+ OwnedByParent = 0x0001,
+ UsePreprocess = 0x0002,
+ ChildrenDoNotOverlap = 0x0004,
+
+ // Upper 16 bits reserved for node subclasses
+
+ // QSGBasicGeometryNode
+ OwnsGeometry = 0x00010000,
+ OwnsMaterial = 0x00020000,
+ OwnsOpaqueMaterial = 0x00040000
+ };
+ Q_DECLARE_FLAGS(Flags, Flag)
+
+ QSGNode();
+ virtual ~QSGNode();
+
+ QSGNode *parent() const { return m_parent; }
+
+ void removeChildNode(QSGNode *node);
+ void prependChildNode(QSGNode *node);
+ void appendChildNode(QSGNode *node);
+ void insertChildNodeBefore(QSGNode *node, QSGNode *before);
+ void insertChildNodeAfter(QSGNode *node, QSGNode *after);
+
+ int childCount() const { return m_children.size(); }
+ QSGNode *childAtIndex(int i) const { return m_children.at(i); }
+
+ inline NodeType type() const { return m_type; }
+
+ void clearDirty() { m_flags = 0; }
+ void markDirty(DirtyFlags flags);
+ DirtyFlags dirtyFlags() const { return m_flags; }
+
+ virtual bool isSubtreeBlocked() const { return false; }
+
+ Flags flags() const { return m_nodeFlags; }
+ void setFlag(Flag, bool = true);
+ void setFlags(Flags, bool = true);
+
+ virtual void preprocess() { }
+
+#ifdef QML_RUNTIME_TESTING
+ QString description;
+#endif
+
+protected:
+ QSGNode(NodeType type);
+
+ // When a node is destroyed, it will detach from the scene graph and the renderer will be
+ // notified about the change. If the node is detached in the base node's destructor, the
+ // renderer can't safely cast the node to its original type, since at this point it has been
+ // partly destroyed already. To solve this problem, all the node destructors must call a common
+ // destroy method.
+
+ void destroy();
+
+private:
+ void init();
+
+ QSGNode *m_parent;
+ NodeType m_type;
+ QList<QSGNode *> m_children;
+
+ Flags m_nodeFlags;
+ DirtyFlags m_flags;
+
+ void *m_reserved;
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QSGNode::DirtyFlags);
+Q_DECLARE_OPERATORS_FOR_FLAGS(QSGNode::Flags);
+
+class Q_DECLARATIVE_EXPORT QSGBasicGeometryNode : public QSGNode
+{
+public:
+// enum UsagePattern {
+// Static,
+// Dynamic,
+// Stream
+// };
+// void setUsagePattern(UsagePattern pattern);
+// UsagePattern usagePattern() const { return m_pattern; }
+
+ ~QSGBasicGeometryNode();
+
+ void setGeometry(QSGGeometry *geometry);
+ const QSGGeometry *geometry() const { return m_geometry; }
+ QSGGeometry *geometry() { return m_geometry; }
+
+ const QMatrix4x4 *matrix() const { return m_matrix; }
+ const QSGClipNode *clipList() const { return m_clip_list; }
+
+protected:
+ QSGBasicGeometryNode(NodeType type);
+
+private:
+ friend class QSGNodeUpdater;
+ QSGGeometry *m_geometry;
+
+ int m_reserved_start_index;
+ int m_reserved_end_index;
+
+ const QMatrix4x4 *m_matrix;
+ const QSGClipNode *m_clip_list;
+
+// UsagePattern m_pattern;
+};
+
+class QSGMaterial;
+
+class Q_DECLARATIVE_EXPORT QSGGeometryNode : public QSGBasicGeometryNode
+{
+public:
+ QSGGeometryNode();
+ ~QSGGeometryNode();
+
+ void setMaterial(QSGMaterial *material);
+ QSGMaterial *material() const { return m_material; }
+
+ void setOpaqueMaterial(QSGMaterial *material);
+ QSGMaterial *opaqueMaterial() const { return m_opaque_material; }
+
+ QSGMaterial *activeMaterial() const;
+
+ void setRenderOrder(int order);
+ int renderOrder() const { return m_render_order; }
+
+ void setInheritedOpacity(qreal opacity);
+ qreal inheritedOpacity() const { return m_opacity; }
+
+private:
+ friend class QSGNodeUpdater;
+
+ int m_render_order;
+ QSGMaterial *m_material;
+ QSGMaterial *m_opaque_material;
+
+ qreal m_opacity;
+};
+
+class Q_DECLARATIVE_EXPORT QSGClipNode : public QSGBasicGeometryNode
+{
+public:
+ QSGClipNode();
+ ~QSGClipNode();
+
+ void setIsRectangular(bool rectHint);
+ bool isRectangular() const { return m_is_rectangular; }
+
+ void setClipRect(const QRectF &);
+ QRectF clipRect() const { return m_clip_rect; }
+
+private:
+ uint m_is_rectangular : 1;
+ uint m_reserved : 31;
+
+ QRectF m_clip_rect;
+};
+
+
+class Q_DECLARATIVE_EXPORT QSGTransformNode : public QSGNode
+{
+public:
+ QSGTransformNode();
+ ~QSGTransformNode();
+
+ void setMatrix(const QMatrix4x4 &matrix);
+ const QMatrix4x4 &matrix() const { return m_matrix; }
+
+ void setCombinedMatrix(const QMatrix4x4 &matrix);
+ const QMatrix4x4 &combinedMatrix() const { return m_combined_matrix; }
+
+private:
+ QMatrix4x4 m_matrix;
+ QMatrix4x4 m_combined_matrix;
+};
+
+
+class Q_DECLARATIVE_EXPORT QSGRootNode : public QSGNode
+{
+public:
+ QSGRootNode();
+ ~QSGRootNode();
+
+private:
+ void notifyNodeChange(QSGNode *node, DirtyFlags flags);
+
+ friend class QSGRenderer;
+ friend class QSGNode;
+ friend class QSGGeometryNode;
+
+ QList<QSGRenderer *> m_renderers;
+};
+
+
+class Q_DECLARATIVE_EXPORT QSGOpacityNode : public QSGNode
+{
+public:
+ QSGOpacityNode();
+ ~QSGOpacityNode();
+
+ void setOpacity(qreal opacity);
+ qreal opacity() const { return m_opacity; }
+
+ void setCombinedOpacity(qreal opacity);
+ qreal combinedOpacity() const { return m_combined_opacity; }
+
+ bool isSubtreeBlocked() const;
+
+private:
+ qreal m_opacity;
+ qreal m_combined_opacity;
+};
+
+class Q_DECLARATIVE_EXPORT QSGNodeVisitor {
+public:
+ virtual ~QSGNodeVisitor();
+
+protected:
+ virtual void enterTransformNode(QSGTransformNode *) {}
+ virtual void leaveTransformNode(QSGTransformNode *) {}
+ virtual void enterClipNode(QSGClipNode *) {}
+ virtual void leaveClipNode(QSGClipNode *) {}
+ virtual void enterGeometryNode(QSGGeometryNode *) {}
+ virtual void leaveGeometryNode(QSGGeometryNode *) {}
+ virtual void enterOpacityNode(QSGOpacityNode *) {}
+ virtual void leaveOpacityNode(QSGOpacityNode *) {}
+ virtual void visitNode(QSGNode *n);
+ virtual void visitChildren(QSGNode *n);
+};
+
+#ifndef QT_NO_DEBUG_STREAM
+Q_DECLARATIVE_EXPORT QDebug operator<<(QDebug, const QSGNode *n);
+Q_DECLARATIVE_EXPORT QDebug operator<<(QDebug, const QSGGeometryNode *n);
+Q_DECLARATIVE_EXPORT QDebug operator<<(QDebug, const QSGTransformNode *n);
+Q_DECLARATIVE_EXPORT QDebug operator<<(QDebug, const QSGOpacityNode *n);
+Q_DECLARATIVE_EXPORT QDebug operator<<(QDebug, const QSGRootNode *n);
+
+class QSGNodeDumper : public QSGNodeVisitor {
+
+public:
+ static void dump(QSGNode *n);
+
+ QSGNodeDumper() : m_indent(0) {}
+ void visitNode(QSGNode *n);
+ void visitChildren(QSGNode *n);
+
+private:
+ int m_indent;
+};
+
+#endif
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // NODE_H
diff --git a/src/declarative/scenegraph/coreapi/qsgnodeupdater.cpp b/src/declarative/scenegraph/coreapi/qsgnodeupdater.cpp
new file mode 100644
index 0000000000..6eff011e85
--- /dev/null
+++ b/src/declarative/scenegraph/coreapi/qsgnodeupdater.cpp
@@ -0,0 +1,243 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgnodeupdater_p.h"
+
+QT_BEGIN_NAMESPACE
+
+// #define QSG_UPDATER_DEBUG
+
+QSGNodeUpdater::QSGNodeUpdater()
+ : m_current_clip(0)
+ , m_force_update(0)
+{
+ m_opacity_stack.push(1);
+}
+
+void QSGNodeUpdater::updateStates(QSGNode *n)
+{
+ m_current_clip = 0;
+ m_force_update = 0;
+
+ Q_ASSERT(m_opacity_stack.size() == 1); // The one we added in the constructr...
+ // Q_ASSERT(m_matrix_stack.isEmpty()); ### no such function?
+ Q_ASSERT(m_combined_matrix_stack.isEmpty());
+
+ visitNode(n);
+}
+
+/*!
+ \fn void QSGNodeUpdater::setToplevelOpacity(qreal opacity)
+
+ Sets the toplevel opacity that will be multiplied with the
+
+ The default opacity is 1. Any other value will cause artifacts, and is
+ primarily useful for debug purposes.
+
+ The changing the value during an update pass will have undefined results
+ */
+
+/*!
+ \fn qreal QSGNodeUpdater::toplevelOpacity() const
+
+ Returns the toplevel opacity for the node updater. The default
+ value is 1.
+ */
+
+
+/*!
+ Returns true if \a node is has something that blocks it in the chain from
+ \a node to \a root doing a full state update pass.
+
+ This function does not process dirty states, simply does a simple traversion
+ up to the top.
+
+ The function assumes that \a root exists in the parent chain of \a node.
+ */
+
+bool QSGNodeUpdater::isNodeBlocked(QSGNode *node, QSGNode *root) const
+{
+ qreal opacity = 1;
+ while (node != root) {
+ if (node->type() == QSGNode::OpacityNodeType) {
+ opacity *= static_cast<QSGOpacityNode *>(node)->opacity();
+ if (opacity < 0.001)
+ return true;
+ }
+ node = node->parent();
+
+ Q_ASSERT_X(node, "QSGNodeUpdater::isNodeBlocked", "node is not in the subtree of root");
+ }
+
+ return false;
+}
+
+
+void QSGNodeUpdater::enterTransformNode(QSGTransformNode *t)
+{
+ if (t->dirtyFlags() & QSGNode::DirtyMatrix)
+ ++m_force_update;
+
+#ifdef QSG_UPDATER_DEBUG
+ qDebug() << "enter transform:" << t << "force=" << m_force_update;
+#endif
+
+ if (!t->matrix().isIdentity()) {
+ m_combined_matrix_stack.push(&t->combinedMatrix());
+
+ m_matrix_stack.push();
+ m_matrix_stack *= t->matrix();
+ }
+
+ t->setCombinedMatrix(m_matrix_stack.top());
+}
+
+
+void QSGNodeUpdater::leaveTransformNode(QSGTransformNode *t)
+{
+#ifdef QSG_UPDATER_DEBUG
+ qDebug() << "leave transform:" << t;
+#endif
+
+ if (t->dirtyFlags() & QSGNode::DirtyMatrix)
+ --m_force_update;
+
+ if (!t->matrix().isIdentity()) {
+ m_matrix_stack.pop();
+ m_combined_matrix_stack.pop();
+ }
+
+}
+
+
+void QSGNodeUpdater::enterClipNode(QSGClipNode *c)
+{
+#ifdef QSG_UPDATER_DEBUG
+ qDebug() << "enter clip:" << c;
+#endif
+
+ if (c->dirtyFlags() & QSGNode::DirtyClipList) {
+ ++m_force_update;
+ }
+
+ c->m_matrix = m_combined_matrix_stack.isEmpty() ? 0 : m_combined_matrix_stack.top();
+ c->m_clip_list = m_current_clip;
+ m_current_clip = c;
+}
+
+
+void QSGNodeUpdater::leaveClipNode(QSGClipNode *c)
+{
+#ifdef QSG_UPDATER_DEBUG
+ qDebug() << "leave clip:" << c;
+#endif
+
+ if (c->dirtyFlags() & QSGNode::DirtyClipList) {
+ --m_force_update;
+ }
+
+ m_current_clip = c->m_clip_list;
+}
+
+
+void QSGNodeUpdater::enterGeometryNode(QSGGeometryNode *g)
+{
+#ifdef QSG_UPDATER_DEBUG
+ qDebug() << "enter geometry:" << g;
+#endif
+
+ g->m_matrix = m_combined_matrix_stack.isEmpty() ? 0 : m_combined_matrix_stack.top();
+ g->m_clip_list = m_current_clip;
+ g->setInheritedOpacity(m_opacity_stack.top());
+}
+
+void QSGNodeUpdater::enterOpacityNode(QSGOpacityNode *o)
+{
+ if (o->dirtyFlags() & QSGNode::DirtyOpacity)
+ ++m_force_update;
+
+ qreal opacity = m_opacity_stack.top() * o->opacity();
+ o->setCombinedOpacity(opacity);
+ m_opacity_stack.push(opacity);
+
+#ifdef QSG_UPDATER_DEBUG
+ qDebug() << "enter opacity" << o;
+#endif
+}
+
+void QSGNodeUpdater::leaveOpacityNode(QSGOpacityNode *o)
+{
+#ifdef QSG_UPDATER_DEBUG
+ qDebug() << "leave opacity" << o;
+#endif
+ if (o->flags() & QSGNode::DirtyOpacity)
+ --m_force_update;
+
+ m_opacity_stack.pop();
+}
+
+void QSGNodeUpdater::visitChildren(QSGNode *n)
+{
+ if (!n->isSubtreeBlocked())
+ QSGNodeVisitor::visitChildren(n);
+}
+
+void QSGNodeUpdater::visitNode(QSGNode *n)
+{
+#ifdef QSG_UPDATER_DEBUG
+ qDebug() << "enter:" << n;
+#endif
+
+ if (n->dirtyFlags() || m_force_update) {
+ bool forceUpdate = n->dirtyFlags() & (QSGNode::DirtyNodeAdded | QSGNode::DirtyForceUpdate);
+ if (forceUpdate)
+ ++m_force_update;
+
+ QSGNodeVisitor::visitNode(n);
+
+ if (forceUpdate)
+ --m_force_update;
+
+ n->clearDirty();
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/scenegraph/coreapi/qsgnodeupdater_p.h b/src/declarative/scenegraph/coreapi/qsgnodeupdater_p.h
new file mode 100644
index 0000000000..518cf9eff9
--- /dev/null
+++ b/src/declarative/scenegraph/coreapi/qsgnodeupdater_p.h
@@ -0,0 +1,87 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef NODEUPDATER_P_H
+#define NODEUPDATER_P_H
+
+#include "qsgnode.h"
+#include "qsgmatrix4x4stack.h"
+#include <qstack.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q_DECLARATIVE_EXPORT QSGNodeUpdater : public QSGNodeVisitor
+{
+public:
+ QSGNodeUpdater();
+
+ virtual void updateStates(QSGNode *n);
+ virtual bool isNodeBlocked(QSGNode *n, QSGNode *root) const;
+
+ void setToplevelOpacity(qreal alpha) { m_opacity_stack.top() = alpha; }
+ qreal toplevelOpacity() const { return m_opacity_stack.top(); }
+
+protected:
+ void enterTransformNode(QSGTransformNode *);
+ void leaveTransformNode(QSGTransformNode *);
+ void enterClipNode(QSGClipNode *c);
+ void leaveClipNode(QSGClipNode *c);
+ void enterOpacityNode(QSGOpacityNode *o);
+ void leaveOpacityNode(QSGOpacityNode *o);
+ void enterGeometryNode(QSGGeometryNode *);
+
+ void visitNode(QSGNode *n);
+ void visitChildren(QSGNode *n);
+
+
+ QSGMatrix4x4Stack m_matrix_stack;
+ QStack<const QMatrix4x4 *> m_combined_matrix_stack;
+ QStack<qreal> m_opacity_stack;
+ const QSGClipNode *m_current_clip;
+
+ int m_force_update;
+
+ qreal m_toplevel_alpha;
+};
+
+QT_END_NAMESPACE
+
+#endif // NODEUPDATER_P_H
diff --git a/src/declarative/scenegraph/coreapi/qsgrenderer.cpp b/src/declarative/scenegraph/coreapi/qsgrenderer.cpp
new file mode 100644
index 0000000000..e267e3d8b8
--- /dev/null
+++ b/src/declarative/scenegraph/coreapi/qsgrenderer.cpp
@@ -0,0 +1,544 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgrenderer_p.h"
+#include "qsgnode.h"
+#include "qsgmaterial.h"
+#include "qsgnodeupdater_p.h"
+
+#include "private/qsgadaptationlayer_p.h"
+
+#include <QGLShaderProgram>
+#include <qglframebufferobject.h>
+#include <QtGui/qapplication.h>
+
+#include <qdatetime.h>
+
+QT_BEGIN_NAMESPACE
+
+//#define RENDERER_DEBUG
+//#define QT_GL_NO_SCISSOR_TEST
+
+// #define QSG_RENDERER_TIMING
+#ifdef QSG_RENDERER_TIMING
+static QTime frameTimer;
+static int preprocessTime;
+static int updatePassTime;
+static int frameNumber = 0;
+#endif
+
+void Bindable::clear(QSGRenderer::ClearMode mode) const
+{
+ GLuint bits = 0;
+ if (mode & QSGRenderer::ClearColorBuffer) bits |= GL_COLOR_BUFFER_BIT;
+ if (mode & QSGRenderer::ClearDepthBuffer) bits |= GL_DEPTH_BUFFER_BIT;
+ if (mode & QSGRenderer::ClearStencilBuffer) bits |= GL_STENCIL_BUFFER_BIT;
+ glClear(bits);
+}
+
+// Reactivate the color buffer after switching to the stencil.
+void Bindable::reactivate() const
+{
+ glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+}
+
+BindableFbo::BindableFbo(QGLFramebufferObject *fbo) : m_fbo(fbo)
+{
+}
+
+
+void BindableFbo::bind() const
+{
+ m_fbo->bind();
+}
+
+/*!
+ \class QSGRenderer
+ \brief The renderer class is the abstract baseclass use for rendering the
+ QML scene graph.
+
+ The renderer is not tied to any particular surface. It expects a context to
+ be current and will render into that surface according to how the device rect,
+ viewport rect and projection transformation are set up.
+
+ Rendering is a sequence of steps initiated by calling renderScene(). This will
+ effectively draw the scene graph starting at the root node. The QSGNode::preprocess()
+ function will be called for all the nodes in the graph, followed by an update
+ pass which updates all matrices, opacity, clip states and similar in the graph.
+ Because the update pass is called after preprocess, it is safe to modify the graph
+ during preprocess. To run a custom update pass over the graph, install a custom
+ QSGNodeUpdater using setNodeUpdater(). Once all the graphs dirty states are updated,
+ the virtual render() function is called.
+
+ The render() function is implemented by QSGRenderer subclasses to render the graph
+ in the most optimal way for a given hardware.
+
+ The renderer can make use of stencil, depth and color buffers in addition to the
+ scissor rect.
+
+ \internal
+ */
+
+
+QSGRenderer::QSGRenderer(QSGContext *context)
+ : QObject()
+ , m_clear_color(Qt::transparent)
+ , m_clear_mode(ClearColorBuffer | ClearDepthBuffer)
+ , m_render_opacity(1)
+ , m_context(context)
+ , m_root_node(0)
+ , m_node_updater(0)
+ , m_bindable(0)
+ , m_changed_emitted(false)
+ , m_mirrored(false)
+ , m_is_rendering(false)
+{
+ initializeGLFunctions();
+}
+
+
+QSGRenderer::~QSGRenderer()
+{
+ setRootNode(0);
+ delete m_node_updater;
+}
+
+/*!
+ Returns the scene graph context for this renderer.
+
+ \internal
+ */
+
+QSGContext *QSGRenderer::context()
+{
+ return m_context;
+}
+
+
+
+
+/*!
+ Returns the node updater that this renderer uses to update states in the
+ scene graph.
+
+ If no updater is specified a default one is constructed.
+ */
+
+QSGNodeUpdater *QSGRenderer::nodeUpdater() const
+{
+ if (!m_node_updater)
+ const_cast<QSGRenderer *>(this)->m_node_updater = new QSGNodeUpdater();
+ return m_node_updater;
+}
+
+
+/*!
+ Sets the node updater that this renderer uses to update states in the
+ scene graph.
+
+ This will delete and override any existing node updater
+ */
+void QSGRenderer::setNodeUpdater(QSGNodeUpdater *updater)
+{
+ if (m_node_updater)
+ delete m_node_updater;
+ m_node_updater = updater;
+}
+
+
+void QSGRenderer::setRootNode(QSGRootNode *node)
+{
+ if (m_root_node == node)
+ return;
+ if (m_root_node) {
+ m_root_node->m_renderers.removeOne(this);
+ nodeChanged(m_root_node, QSGNode::DirtyNodeRemoved);
+ }
+ m_root_node = node;
+ if (m_root_node) {
+ Q_ASSERT(!m_root_node->m_renderers.contains(this));
+ m_root_node->m_renderers << this;
+ nodeChanged(m_root_node, QSGNode::DirtyNodeAdded);
+ }
+}
+
+
+void QSGRenderer::renderScene()
+{
+ class B : public Bindable
+ {
+ public:
+ B() : m_ctx(const_cast<QGLContext *>(QGLContext::currentContext())) { }
+ void bind() const { QGLFramebufferObject::bindDefault(); }
+ private:
+ QGLContext *m_ctx;
+ } b;
+ renderScene(b);
+}
+
+void QSGRenderer::renderScene(const Bindable &bindable)
+{
+ if (!m_root_node)
+ return;
+
+ m_is_rendering = true;
+#ifdef QSG_RENDERER_TIMING
+ frameTimer.start();
+#endif
+
+ m_bindable = &bindable;
+ preprocess();
+
+ bindable.bind();
+#ifdef QSG_RENDERER_TIMING
+ int bindTime = frameTimer.elapsed();
+#endif
+
+ render();
+#ifdef QSG_RENDERER_TIMING
+ int renderTime = frameTimer.elapsed();
+#endif
+
+ glDisable(GL_SCISSOR_TEST);
+ m_is_rendering = false;
+ m_changed_emitted = false;
+ m_bindable = 0;
+
+#ifdef QSG_RENDERER_TIMING
+ printf(" - Breakdown of frametime: preprocess=%d, updates=%d, binding=%d, render=%d, total=%d\n",
+ preprocessTime,
+ updatePassTime - preprocessTime,
+ bindTime - updatePassTime,
+ renderTime - bindTime,
+ renderTime);
+#endif
+}
+
+void QSGRenderer::setProjectMatrixToDeviceRect()
+{
+ setProjectMatrixToRect(m_device_rect);
+}
+
+void QSGRenderer::setProjectMatrixToRect(const QRectF &rect)
+{
+ QMatrix4x4 matrix;
+ matrix.ortho(rect.x(),
+ rect.x() + rect.width(),
+ rect.y() + rect.height(),
+ rect.y(),
+ qreal(0.01),
+ -1);
+ setProjectMatrix(matrix);
+}
+
+void QSGRenderer::setProjectMatrix(const QMatrix4x4 &matrix)
+{
+ m_projection_matrix = matrix;
+ // Mirrored relative to the usual Qt coordinate system with origin in the top left corner.
+ m_mirrored = matrix(0, 0) * matrix(1, 1) - matrix(0, 1) * matrix(1, 0) > 0;
+}
+
+void QSGRenderer::setClearColor(const QColor &color)
+{
+ m_clear_color = color;
+}
+
+void QSGRenderer::nodeChanged(QSGNode *node, QSGNode::DirtyFlags flags)
+{
+ Q_UNUSED(node);
+ Q_UNUSED(flags);
+
+ if (flags & QSGNode::DirtyNodeAdded)
+ addNodesToPreprocess(node);
+ if (flags & QSGNode::DirtyNodeRemoved)
+ removeNodesToPreprocess(node);
+
+ if (!m_changed_emitted && !m_is_rendering) {
+ // Premature overoptimization to avoid excessive signal emissions
+ m_changed_emitted = true;
+ emit sceneGraphChanged();
+ }
+}
+
+void QSGRenderer::materialChanged(QSGGeometryNode *, QSGMaterial *, QSGMaterial *)
+{
+}
+
+void QSGRenderer::preprocess()
+{
+ Q_ASSERT(m_root_node);
+
+ // We need to take a copy here, in case any of the preprocess calls deletes a node that
+ // is in the preprocess list and thus, changes the m_nodes_to_preprocess behind our backs
+ // For the default case, when this does not happen, the cost is neglishible.
+ QSet<QSGNode *> items = m_nodes_to_preprocess;
+
+ for (QSet<QSGNode *>::const_iterator it = items.constBegin();
+ it != items.constEnd(); ++it) {
+ QSGNode *n = *it;
+ if (!nodeUpdater()->isNodeBlocked(n, m_root_node)) {
+ n->preprocess();
+ }
+ }
+
+#ifdef QSG_RENDERER_TIMING
+ preprocessTime = frameTimer.elapsed();
+#endif
+
+ nodeUpdater()->setToplevelOpacity(context()->renderAlpha());
+ nodeUpdater()->updateStates(m_root_node);
+
+#ifdef QSG_RENDERER_TIMING
+ updatePassTime = frameTimer.elapsed();
+#endif
+
+}
+
+void QSGRenderer::addNodesToPreprocess(QSGNode *node)
+{
+ for (int i = 0; i < node->childCount(); ++i)
+ addNodesToPreprocess(node->childAtIndex(i));
+ if (node->flags() & QSGNode::UsePreprocess)
+ m_nodes_to_preprocess.insert(node);
+}
+
+void QSGRenderer::removeNodesToPreprocess(QSGNode *node)
+{
+ for (int i = 0; i < node->childCount(); ++i)
+ removeNodesToPreprocess(node->childAtIndex(i));
+ if (node->flags() & QSGNode::UsePreprocess)
+ m_nodes_to_preprocess.remove(node);
+}
+
+
+/*!
+ Convenience function to set up the stencil buffer for clipping based on \a clip.
+
+ If the clip is a pixel aligned rectangle, this function will use glScissor instead
+ of stencil.
+ */
+
+QSGRenderer::ClipType QSGRenderer::updateStencilClip(const QSGClipNode *clip)
+{
+ if (!clip) {
+ glDisable(GL_STENCIL_TEST);
+ glDisable(GL_SCISSOR_TEST);
+ return NoClip;
+ }
+
+ bool stencilEnabled = false;
+ bool scissorEnabled = false;
+
+ glDisable(GL_SCISSOR_TEST);
+
+ int clipDepth = 0;
+ QRect clipRect;
+ while (clip) {
+ QMatrix4x4 matrix = m_projectionMatrix.top();
+ if (clip->matrix())
+ matrix *= *clip->matrix();
+
+ const QMatrix4x4 &m = matrix;
+
+ // TODO: Check for multisampling and pixel grid alignment.
+ bool canUseScissor = clip->isRectangular()
+ && qFuzzyIsNull(m(0, 1)) && qFuzzyIsNull(m(0, 2))
+ && qFuzzyIsNull(m(1, 0)) && qFuzzyIsNull(m(1, 2));
+
+ if (canUseScissor) {
+ QRectF bbox = clip->clipRect();
+ qreal invW = 1 / m(3, 3);
+ qreal fx1 = (bbox.left() * m(0, 0) + m(0, 3)) * invW;
+ qreal fy1 = (bbox.bottom() * m(1, 1) + m(1, 3)) * invW;
+ qreal fx2 = (bbox.right() * m(0, 0) + m(0, 3)) * invW;
+ qreal fy2 = (bbox.top() * m(1, 1) + m(1, 3)) * invW;
+
+ GLint ix1 = qRound((fx1 + 1) * m_device_rect.width() * qreal(0.5));
+ GLint iy1 = qRound((fy1 + 1) * m_device_rect.height() * qreal(0.5));
+ GLint ix2 = qRound((fx2 + 1) * m_device_rect.width() * qreal(0.5));
+ GLint iy2 = qRound((fy2 + 1) * m_device_rect.height() * qreal(0.5));
+
+ if (!scissorEnabled) {
+ clipRect = QRect(ix1, iy1, ix2 - ix1, iy2 - iy1);
+ glEnable(GL_SCISSOR_TEST);
+ scissorEnabled = true;
+ } else {
+ clipRect &= QRect(ix1, iy1, ix2 - ix1, iy2 - iy1);
+ }
+
+ clipRect = clipRect.normalized();
+ glScissor(clipRect.x(), clipRect.y(), clipRect.width(), clipRect.height());
+ } else {
+ if (!stencilEnabled) {
+ if (!m_clip_program.isLinked()) {
+ m_clip_program.addShaderFromSourceCode(QGLShader::Vertex,
+ "attribute highp vec4 vCoord; \n"
+ "uniform highp mat4 matrix; \n"
+ "void main() { \n"
+ " gl_Position = matrix * vCoord; \n"
+ "}");
+ m_clip_program.addShaderFromSourceCode(QGLShader::Fragment,
+ "void main() { \n"
+ " gl_FragColor = vec4(0.81, 0.83, 0.12, 1.0); \n" // Trolltech green ftw!
+ "}");
+ m_clip_program.bindAttributeLocation("vCoord", 0);
+ m_clip_program.link();
+ m_clip_matrix_id = m_clip_program.uniformLocation("matrix");
+ }
+
+ glStencilMask(0xff); // write mask
+ glClearStencil(0);
+ glClear(GL_STENCIL_BUFFER_BIT);
+ glEnable(GL_STENCIL_TEST);
+ glDisable(GL_DEPTH_TEST);
+ glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
+ glDepthMask(GL_FALSE);
+
+ m_clip_program.bind();
+ m_clip_program.enableAttributeArray(0);
+
+ stencilEnabled = true;
+ }
+
+ glStencilFunc(GL_EQUAL, clipDepth, 0xff); // stencil test, ref, test mask
+ glStencilOp(GL_KEEP, GL_KEEP, GL_INCR); // stencil fail, z fail, z pass
+
+ const QSGGeometry *geometry = clip->geometry();
+ Q_ASSERT(geometry->attributeCount() > 0);
+ const QSGGeometry::Attribute *a = geometry->attributes();
+
+ glVertexAttribPointer(0, a->tupleSize, a->type, GL_FALSE, geometry->stride(), geometry->vertexData());
+
+ m_clip_program.setUniformValue(m_clip_matrix_id, m);
+ draw(clip);
+
+ ++clipDepth;
+ }
+
+ clip = clip->clipList();
+ }
+
+ if (stencilEnabled) {
+ m_clip_program.disableAttributeArray(0);
+ glEnable(GL_DEPTH_TEST);
+ glStencilFunc(GL_EQUAL, clipDepth, 0xff); // stencil test, ref, test mask
+ glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); // stencil fail, z fail, z pass
+ glStencilMask(0); // write mask
+ bindable()->reactivate();
+ //glDepthMask(GL_TRUE); // must be reset correctly by caller.
+ } else {
+ glDisable(GL_STENCIL_TEST);
+ }
+
+ if (!scissorEnabled)
+ glDisable(GL_SCISSOR_TEST);
+
+ return stencilEnabled ? StencilClip : ScissorClip;
+}
+
+
+/*!
+ Issues the GL draw call for \a geometryNode.
+
+ The function assumes that attributes have been bound and set up prior
+ to making this call.
+
+ \internal
+ */
+
+void QSGRenderer::draw(const QSGBasicGeometryNode *node)
+{
+ const QSGGeometry *g = node->geometry();
+ if (g->indexCount()) {
+ glDrawElements(g->drawingMode(), g->indexCount(), g->indexType(), g->indexData());
+ } else {
+ glDrawArrays(g->drawingMode(), 0, g->vertexCount());
+ }
+}
+
+
+static inline int size_of_type(GLenum type)
+{
+ static int sizes[] = {
+ sizeof(char),
+ sizeof(unsigned char),
+ sizeof(short),
+ sizeof(unsigned short),
+ sizeof(int),
+ sizeof(unsigned int),
+ sizeof(float),
+ 2,
+ 3,
+ 4,
+ sizeof(double)
+ };
+ return sizes[type - GL_BYTE];
+}
+
+/*!
+ Convenience function to set up and bind the vertex data in \a g to the
+ required attribute positions defined in \a material.
+
+ \internal
+ */
+
+void QSGRenderer::bindGeometry(QSGMaterialShader *material, const QSGGeometry *g)
+{
+ char const *const *attrNames = material->attributeNames();
+ int offset = 0;
+ for (int j = 0; attrNames[j]; ++j) {
+ if (!*attrNames[j])
+ continue;
+ Q_ASSERT_X(j < g->attributeCount(), "QSGRenderer::bindGeometry()", "Geometry lacks attribute required by material");
+ const QSGGeometry::Attribute &a = g->attributes()[j];
+ Q_ASSERT_X(j == a.position, "QSGRenderer::bindGeometry()", "Geometry does not have continuous attribute positions");
+#if defined(QT_OPENGL_ES_2)
+ GLboolean normalize = a.type != GL_FLOAT;
+#else
+ GLboolean normalize = a.type != GL_FLOAT && a.type != GL_DOUBLE;
+#endif
+ glVertexAttribPointer(a.position, a.tupleSize, a.type, normalize, g->stride(), (char *) g->vertexData() + offset);
+ offset += a.tupleSize * size_of_type(a.type);
+ }
+}
+
+
+QT_END_NAMESPACE
diff --git a/src/declarative/scenegraph/coreapi/qsgrenderer_p.h b/src/declarative/scenegraph/coreapi/qsgrenderer_p.h
new file mode 100644
index 0000000000..272df8082c
--- /dev/null
+++ b/src/declarative/scenegraph/coreapi/qsgrenderer_p.h
@@ -0,0 +1,219 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef RENDERER_H
+#define RENDERER_H
+
+#include <qset.h>
+#include <qhash.h>
+
+#include "qsgmatrix4x4stack.h"
+
+#include <qglfunctions.h>
+#include <qglshaderprogram.h>
+
+#include "qsgnode.h"
+#include "qsgmaterial.h"
+#include "qsgtexture.h"
+
+#include <private/qsgcontext_p.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QSGMaterialShader;
+struct QSGMaterialType;
+class QGLFramebufferObject;
+class TextureReference;
+class Bindable;
+class QSGNodeUpdater;
+
+
+class Q_DECLARATIVE_EXPORT QSGRenderer : public QObject, public QGLFunctions
+{
+ Q_OBJECT
+public:
+ enum ClipType
+ {
+ NoClip,
+ ScissorClip,
+ StencilClip
+ };
+
+ enum ClearModeBit
+ {
+ ClearColorBuffer = 0x0001,
+ ClearDepthBuffer = 0x0002,
+ ClearStencilBuffer = 0x0004
+ };
+ Q_DECLARE_FLAGS(ClearMode, ClearModeBit)
+
+ QSGRenderer(QSGContext *context);
+ virtual ~QSGRenderer();
+
+ void setRootNode(QSGRootNode *node);
+ QSGRootNode *rootNode() const { return m_root_node; }
+
+ void setDeviceRect(const QRect &rect) { m_device_rect = rect; }
+ inline void setDeviceRect(const QSize &size) { setDeviceRect(QRect(QPoint(), size)); }
+ QRect deviceRect() const { return m_device_rect; }
+
+ void setViewportRect(const QRect &rect) { m_viewport_rect = rect; }
+ inline void setViewportRect(const QSize &size) { setViewportRect(QRect(QPoint(), size)); }
+ QRect viewportRect() const { return m_viewport_rect; }
+
+ QSGMatrix4x4Stack &projectionMatrix() { return m_projectionMatrix; }
+ QSGMatrix4x4Stack &modelViewMatrix() { return m_modelViewMatrix; }
+ QMatrix4x4 combinedMatrix() const { return m_projectionMatrix.top() * m_modelViewMatrix.top(); }
+
+ void setProjectMatrixToDeviceRect();
+ void setProjectMatrixToRect(const QRectF &rect);
+ void setProjectMatrix(const QMatrix4x4 &matrix);
+ QMatrix4x4 projectMatrix() const { return m_projection_matrix; }
+ bool isMirrored() const { return m_mirrored; }
+
+ qreal renderOpacity() const { return m_render_opacity; }
+
+ void setClearColor(const QColor &color);
+ QColor clearColor() const { return m_clear_color; }
+
+ const QGLContext *glContext() const { Q_ASSERT(m_context); return m_context->glContext(); }
+
+ QSGContext *context();
+
+ void renderScene();
+ void renderScene(const Bindable &bindable);
+ virtual void nodeChanged(QSGNode *node, QSGNode::DirtyFlags flags);
+ virtual void materialChanged(QSGGeometryNode *node, QSGMaterial *from, QSGMaterial *to);
+
+ QSGNodeUpdater *nodeUpdater() const;
+ void setNodeUpdater(QSGNodeUpdater *updater);
+
+ inline QSGMaterialShader::RenderState state(QSGMaterialShader::RenderState::DirtyStates dirty) const;
+
+ void setClearMode(ClearMode mode) { m_clear_mode = mode; }
+ ClearMode clearMode() const { return m_clear_mode; }
+
+signals:
+ void sceneGraphChanged(); // Add, remove, ChangeFlags changes...
+
+protected:
+ void draw(const QSGBasicGeometryNode *geometry);
+ void bindGeometry(QSGMaterialShader *material, const QSGGeometry *g);
+
+ virtual void render() = 0;
+ QSGRenderer::ClipType updateStencilClip(const QSGClipNode *clip);
+
+ const Bindable *bindable() const { return m_bindable; }
+
+ virtual void preprocess();
+
+ void addNodesToPreprocess(QSGNode *node);
+ void removeNodesToPreprocess(QSGNode *node);
+
+
+ QColor m_clear_color;
+ ClearMode m_clear_mode;
+ QSGMatrix4x4Stack m_projectionMatrix;
+ QSGMatrix4x4Stack m_modelViewMatrix;
+ qreal m_render_opacity;
+
+ QSGContext *m_context;
+
+private:
+ QSGRootNode *m_root_node;
+ QSGNodeUpdater *m_node_updater;
+
+ QRect m_device_rect;
+ QRect m_viewport_rect;
+
+ QSet<QSGNode *> m_nodes_to_preprocess;
+
+ QMatrix4x4 m_projection_matrix;
+ QGLShaderProgram m_clip_program;
+ int m_clip_matrix_id;
+
+ const Bindable *m_bindable;
+
+ bool m_changed_emitted : 1;
+ bool m_mirrored : 1;
+ bool m_is_rendering : 1;
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QSGRenderer::ClearMode)
+
+class Q_DECLARATIVE_EXPORT Bindable
+{
+public:
+ virtual ~Bindable() { }
+ virtual void bind() const = 0;
+ virtual void clear(QSGRenderer::ClearMode mode) const;
+ virtual void reactivate() const;
+};
+
+class BindableFbo : public Bindable
+{
+public:
+ BindableFbo(QGLFramebufferObject *fbo);
+ virtual void bind() const;
+private:
+ QGLFramebufferObject *m_fbo;
+};
+
+
+
+QSGMaterialShader::RenderState QSGRenderer::state(QSGMaterialShader::RenderState::DirtyStates dirty) const
+{
+ QSGMaterialShader::RenderState s;
+ s.m_dirty = dirty;
+ s.m_data = this;
+ return s;
+}
+
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // RENDERER_H
diff --git a/src/declarative/scenegraph/qsgadaptationlayer.cpp b/src/declarative/scenegraph/qsgadaptationlayer.cpp
new file mode 100644
index 0000000000..81fac6a1a8
--- /dev/null
+++ b/src/declarative/scenegraph/qsgadaptationlayer.cpp
@@ -0,0 +1,42 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgadaptationlayer_p.h"
diff --git a/src/declarative/scenegraph/qsgadaptationlayer_p.h b/src/declarative/scenegraph/qsgadaptationlayer_p.h
new file mode 100644
index 0000000000..e0748de837
--- /dev/null
+++ b/src/declarative/scenegraph/qsgadaptationlayer_p.h
@@ -0,0 +1,124 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef ADAPTATIONINTERFACES_H
+#define ADAPTATIONINTERFACES_H
+
+#include "qsgnode.h"
+#include "qsgtexture.h"
+
+#include <QtCore/qobject.h>
+#include <QtCore/qrect.h>
+#include <QtGui/qcolor.h>
+#include <QtCore/qsharedpointer.h>
+#include <QtGui/qglyphrun.h>
+#include <QtCore/qurl.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QSGNode;
+class QImage;
+class TextureReference;
+
+// TODO: Rename from XInterface to AbstractX.
+class Q_DECLARATIVE_EXPORT QSGRectangleNode : public QSGGeometryNode
+{
+public:
+ virtual void setRect(const QRectF &rect) = 0;
+ virtual void setColor(const QColor &color) = 0;
+ virtual void setPenColor(const QColor &color) = 0;
+ virtual void setPenWidth(qreal width) = 0;
+ virtual void setGradientStops(const QGradientStops &stops) = 0;
+ virtual void setRadius(qreal radius) = 0;
+ virtual void setAligned(bool aligned) = 0;
+
+ virtual void update() = 0;
+};
+
+
+class Q_DECLARATIVE_EXPORT QSGImageNode : public QSGGeometryNode
+{
+public:
+ virtual void setTargetRect(const QRectF &rect) = 0;
+ virtual void setSourceRect(const QRectF &rect) = 0;
+ virtual void setTexture(QSGTexture *texture) = 0;
+
+ virtual void setMipmapFiltering(QSGTexture::Filtering filtering) = 0;
+ virtual void setFiltering(QSGTexture::Filtering filtering) = 0;
+ virtual void setHorizontalWrapMode(QSGTexture::WrapMode wrapMode) = 0;
+ virtual void setVerticalWrapMode(QSGTexture::WrapMode wrapMode) = 0;
+
+ virtual void update() = 0;
+};
+
+
+class Q_DECLARATIVE_EXPORT QSGGlyphNode : public QSGGeometryNode
+{
+public:
+ enum AntialiasingMode
+ {
+ GrayAntialiasing,
+ SubPixelAntialiasing
+ };
+
+ virtual void setGlyphs(const QPointF &position, const QGlyphRun &glyphs) = 0;
+ virtual void setColor(const QColor &color) = 0;
+ virtual QPointF baseLine() const = 0;
+
+ virtual QRectF boundingRect() const { return m_bounding_rect; }
+ virtual void setBoundingRect(const QRectF &bounds) { m_bounding_rect = bounds; }
+
+ virtual void setPreferredAntialiasingMode(AntialiasingMode) = 0;
+
+protected:
+ QRectF m_bounding_rect;
+};
+
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/declarative/scenegraph/qsgcontext.cpp b/src/declarative/scenegraph/qsgcontext.cpp
new file mode 100644
index 0000000000..e36d432e40
--- /dev/null
+++ b/src/declarative/scenegraph/qsgcontext.cpp
@@ -0,0 +1,449 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <private/qsgcontext_p.h>
+#include <private/qsgrenderer_p.h>
+#include "qsgnode.h"
+
+#include <private/qsgdefaultrenderer_p.h>
+
+#include <private/qsgdefaultrectanglenode_p.h>
+#include <private/qsgdefaultimagenode_p.h>
+#include <private/qsgdefaultglyphnode_p.h>
+#include <private/qsgdistancefieldglyphnode_p.h>
+#include <private/qsgdistancefieldglyphcache_p.h>
+
+#include <private/qsgtexture_p.h>
+#include <qsgengine.h>
+
+#include <QApplication>
+#include <QGLContext>
+
+#include <private/qobject_p.h>
+#include <qmutex.h>
+
+DEFINE_BOOL_CONFIG_OPTION(qmlFlashMode, QML_FLASH_MODE)
+DEFINE_BOOL_CONFIG_OPTION(qmlTranslucentMode, QML_TRANSLUCENT_MODE)
+
+/*!
+ Comments about this class from Gunnar:
+
+ The QSGContext class is right now two things.. The first is the
+ adaptation layer and central storage ground for all the things
+ in the scene graph, like textures and materials. This part really
+ belongs inside the scene graph coreapi.
+
+ The other part is the QML adaptation classes, like how to implement
+ rectangle nodes. This is not part of the scene graph core API, but
+ more part of the QML adaptation of scene graph.
+
+ If we ever move the scene graph core API into its own thing, this class
+ needs to be split in two. Right now its one because we're lazy when it comes
+ to defining plugin interfaces..
+
+ */
+
+
+QT_BEGIN_NAMESPACE
+
+class QSGContextPrivate : public QObjectPrivate
+{
+public:
+ QSGContextPrivate()
+ : rootNode(0)
+ , renderer(0)
+ , gl(0)
+ , flashMode(qmlFlashMode())
+ {
+ renderAlpha = qmlTranslucentMode() ? 0.5 : 1;
+ }
+
+ ~QSGContextPrivate()
+ {
+ }
+
+ QSGRootNode *rootNode;
+ QSGRenderer *renderer;
+
+ QGLContext *gl;
+
+ QSGEngine engine;
+
+ QHash<QSGMaterialType *, QSGMaterialShader *> materials;
+
+ QMutex textureMutex;
+ QList<QSGTexture *> texturesToClean;
+
+ bool flashMode;
+ float renderAlpha;
+};
+
+
+/*!
+ \class QSGContext
+
+ \brief The QSGContext holds the scene graph entry points for one QML engine.
+
+ The context is not ready for use until it has a QGLContext. Once that happens,
+ the scene graph population can start.
+
+ \internal
+ */
+
+QSGContext::QSGContext(QObject *parent) :
+ QObject(*(new QSGContextPrivate), parent)
+{
+ Q_D(QSGContext);
+ d->engine.setContext(this);
+}
+
+
+QSGContext::~QSGContext()
+{
+ Q_D(QSGContext);
+ delete d->renderer;
+ delete d->rootNode;
+ cleanupTextures();
+ qDeleteAll(d->materials.values());
+}
+
+/*!
+ Returns the scene graph engine for this context.
+
+ The main purpose of the QSGEngine is to serve as a public API
+ to the QSGContext.
+
+ */
+QSGEngine *QSGContext::engine() const
+{
+ return const_cast<QSGEngine *>(&d_func()->engine);
+}
+
+/*!
+ Schedules the texture to be cleaned up on the rendering thread
+ at a later time.
+
+ The texture can be considered as deleted after this function has
+ been called.
+ */
+void QSGContext::scheduleTextureForCleanup(QSGTexture *texture)
+{
+ Q_D(QSGContext);
+ d->textureMutex.lock();
+ Q_ASSERT(!d->texturesToClean.contains(texture));
+ d->texturesToClean << texture;
+ d->textureMutex.unlock();
+}
+
+
+
+/*!
+ Deletes all textures that have been scheduled for cleanup
+ */
+void QSGContext::cleanupTextures()
+{
+ Q_D(QSGContext);
+ d->textureMutex.lock();
+ qDeleteAll(d->texturesToClean);
+ d->texturesToClean.clear();
+ d->textureMutex.unlock();
+}
+
+/*!
+ Returns the renderer. The renderer instance is created through the adaptation layer.
+ */
+QSGRenderer *QSGContext::renderer() const
+{
+ Q_D(const QSGContext);
+ return d->renderer;
+}
+
+
+/*!
+ Returns the root node. The root node instance is only created once the scene graph
+ context becomes ready.
+ */
+QSGRootNode *QSGContext::rootNode() const
+{
+ Q_D(const QSGContext);
+ return d->rootNode;
+}
+
+
+QGLContext *QSGContext::glContext() const
+{
+ Q_D(const QSGContext);
+ return d->gl;
+}
+
+/*!
+ Initializes the scene graph context with the GL context \a context. This also
+ emits the ready() signal so that the QML graph can start building scene graph nodes.
+ */
+void QSGContext::initialize(QGLContext *context)
+{
+ Q_D(QSGContext);
+
+ Q_ASSERT(!d->gl);
+
+ d->gl = context;
+
+ d->renderer = createRenderer();
+ d->renderer->setClearColor(Qt::white);
+
+ d->rootNode = new QSGRootNode();
+ d->renderer->setRootNode(d->rootNode);
+
+ emit ready();
+}
+
+
+/*!
+ Returns if the scene graph context is ready or not, meaning that it has a valid
+ GL context.
+ */
+bool QSGContext::isReady() const
+{
+ Q_D(const QSGContext);
+ return d->gl;
+}
+
+
+void QSGContext::renderNextFrame()
+{
+ Q_D(QSGContext);
+
+ emit d->engine.beforeRendering();
+
+ cleanupTextures();
+ d->renderer->renderScene();
+
+ emit d->engine.afterRendering();
+
+}
+
+/*!
+ Factory function for scene graph backends of the Rectangle element.
+ */
+QSGRectangleNode *QSGContext::createRectangleNode()
+{
+ return new QSGDefaultRectangleNode(this);
+}
+
+/*!
+ Factory function for scene graph backends of the Image element.
+ */
+QSGImageNode *QSGContext::createImageNode()
+{
+ return new QSGDefaultImageNode;
+}
+
+/*!
+ Factory function for scene graph backends of the Text elements;
+ */
+QSGGlyphNode *QSGContext::createGlyphNode()
+{
+ if (QSGDistanceFieldGlyphCache::distanceFieldEnabled()) {
+ QSGGlyphNode *node = new QSGDistanceFieldGlyphNode;
+ if (qApp->arguments().contains(QLatin1String("--subpixel-antialiasing")))
+ node->setPreferredAntialiasingMode(QSGGlyphNode::SubPixelAntialiasing);
+ return node;
+ } else {
+ return new QSGDefaultGlyphNode;
+ }
+}
+
+/*!
+ Factory function for the scene graph renderers.
+
+ The renderers are used for the toplevel renderer and once for every
+ QSGShaderEffectSource used in the QML scene.
+ */
+QSGRenderer *QSGContext::createRenderer()
+{
+ QMLRenderer *renderer = new QMLRenderer(this);
+ if (qApp->arguments().contains(QLatin1String("--opaque-front-to-back"))) {
+ printf("QSGContext: Sorting opaque nodes front to back...\n");
+ renderer->setSortFrontToBackEnabled(true);
+ }
+ return renderer;
+}
+
+
+
+/*!
+ Return true if the image provider supports direct decoding of images,
+ straight into textures without going through a QImage first.
+
+ If the implementation returns true from this function, the decodeImageToTexture() function
+ will be called to read data from a QIODevice, rather than QML decoding
+ the image using QImageReader and passing the result to setImage().
+
+ \warning This function will be called from outside the GUI and rendering threads
+ and must not make use of OpenGL.
+ */
+
+bool QSGContext::canDecodeImageToTexture() const
+{
+ return true;
+}
+
+
+
+/*!
+ Decode the data in \a dev directly to a texture provider of \a requestSize size.
+ The size of the decoded data should be written to \a impsize.
+
+ If the implementation fails to decode the image data, it should return 0. The
+ image data will then be decoded normally.
+
+ \warning This function will be called from outside the GUI and renderer threads
+ and must not make use of GL calls.
+ */
+
+QSGTexture *QSGContext::decodeImageToTexture(QIODevice *dev,
+ QSize *size,
+ const QSize &requestSize)
+{
+ Q_UNUSED(dev);
+ Q_UNUSED(size);
+ Q_UNUSED(requestSize);
+ return 0;
+}
+
+
+
+/*!
+ Factory function for texture objects.
+
+ If \a image is a valid image, the QSGTexture::setImage function
+ will be called with \a image as argument.
+ */
+
+QSGTexture *QSGContext::createTexture(const QImage &image) const
+{
+ QSGPlainTexture *t = new QSGPlainTexture();
+ if (!image.isNull())
+ t->setImage(image);
+ return t;
+}
+
+
+
+/*!
+ Returns a material shader for the given material.
+ */
+
+QSGMaterialShader *QSGContext::prepareMaterial(QSGMaterial *material)
+{
+ Q_D(QSGContext);
+ QSGMaterialType *type = material->type();
+ QSGMaterialShader *shader = d->materials.value(type);
+ if (shader)
+ return shader;
+
+ shader = material->createShader();
+ shader->compile();
+ shader->initialize();
+ d->materials[type] = shader;
+
+ return shader;
+}
+
+
+
+/*!
+ Sets weither the scene graph should render with flashing update rectangles or not
+ */
+
+void QSGContext::setFlashModeEnabled(bool enabled)
+{
+ d_func()->flashMode = enabled;
+}
+
+
+/*!
+ Returns true if the scene graph should be rendered with flashing update rectangles
+ */
+bool QSGContext::isFlashModeEnabled() const
+{
+ return d_func()->flashMode;
+}
+
+
+/*!
+ Sets the toplevel opacity for rendering. This value will be multiplied into all
+ drawing calls where possible.
+
+ The default value is 1. Any other value will cause artifacts and is primarily
+ useful for debugging.
+ */
+void QSGContext::setRenderAlpha(qreal renderAlpha)
+{
+ d_func()->renderAlpha = renderAlpha;
+}
+
+
+/*!
+ Returns the toplevel opacity used for rendering.
+
+ The default value is 1.
+
+ \sa setRenderAlpha()
+ */
+qreal QSGContext::renderAlpha() const
+{
+ return d_func()->renderAlpha;
+}
+
+
+
+/*!
+ Creates a new animation driver.
+ */
+
+QAnimationDriver *QSGContext::createAnimationDriver(QObject *parent)
+{
+ return new QAnimationDriver(parent);
+}
+
+
+QT_END_NAMESPACE
diff --git a/src/declarative/scenegraph/qsgcontext_p.h b/src/declarative/scenegraph/qsgcontext_p.h
new file mode 100644
index 0000000000..1344ac705d
--- /dev/null
+++ b/src/declarative/scenegraph/qsgcontext_p.h
@@ -0,0 +1,126 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGCONTEXT_H
+#define QSGCONTEXT_H
+
+#include <QObject>
+#include <qabstractanimation.h>
+
+#include "qsgnode.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QSGContextPrivate;
+class QSGRectangleNode;
+class QSGImageNode;
+class QSGGlyphNode;
+class QSGRenderer;
+
+class QSGTexture;
+class QSGMaterial;
+class QSGMaterialShader;
+class QSGEngine;
+
+class QGLContext;
+
+class Q_DECLARATIVE_EXPORT QSGContext : public QObject
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QSGContext)
+
+public:
+ explicit QSGContext(QObject *parent = 0);
+ ~QSGContext();
+
+ virtual void initialize(QGLContext *context);
+
+ QSGRenderer *renderer() const;
+
+ void setRootNode(QSGRootNode *node);
+ QSGRootNode *rootNode() const;
+
+ QSGEngine *engine() const;
+ QGLContext *glContext() const;
+
+ bool isReady() const;
+
+ QSGMaterialShader *prepareMaterial(QSGMaterial *material);
+
+ virtual void renderNextFrame();
+
+ virtual QSGRectangleNode *createRectangleNode();
+ virtual QSGImageNode *createImageNode();
+ virtual QSGGlyphNode *createGlyphNode();
+ virtual QSGRenderer *createRenderer();
+
+ virtual bool canDecodeImageToTexture() const;
+ virtual QSGTexture *decodeImageToTexture(QIODevice *dev,
+ QSize *size,
+ const QSize &requestSize);
+ virtual QSGTexture *createTexture(const QImage &image = QImage()) const;
+
+ static QSGContext *createDefaultContext();
+
+ void scheduleTextureForCleanup(QSGTexture *texture);
+ void cleanupTextures();
+
+ void setFlashModeEnabled(bool enabled);
+ bool isFlashModeEnabled() const;
+
+ void setRenderAlpha(qreal renderAlpha);
+ qreal renderAlpha() const;
+
+ virtual QAnimationDriver *createAnimationDriver(QObject *parent);
+
+signals:
+ void ready();
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QSGCONTEXT_H
diff --git a/src/declarative/scenegraph/qsgcontextplugin.cpp b/src/declarative/scenegraph/qsgcontextplugin.cpp
new file mode 100644
index 0000000000..287db68fa3
--- /dev/null
+++ b/src/declarative/scenegraph/qsgcontextplugin.cpp
@@ -0,0 +1,104 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgcontextplugin_p.h"
+#include <private/qsgcontext_p.h>
+#include <QtGui/qapplication.h>
+#include <QtCore/private/qfactoryloader_p.h>
+#include <QtCore/qlibraryinfo.h>
+
+QT_BEGIN_NAMESPACE
+
+QSGContextPlugin::QSGContextPlugin(QObject *parent)
+ : QObject(parent)
+{
+}
+
+QSGContextPlugin::~QSGContextPlugin()
+{
+}
+
+#if !defined (QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS)
+Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, loader,
+ (QSGContextFactoryInterface_iid, QLatin1String("/scenegraph")))
+#endif
+
+/*!
+ \fn QSGContext *QSGContext::createDefaultContext()
+
+ Creates a default scene graph context for the current hardware.
+ This may load a device-specific plugin.
+*/
+QSGContext *QSGContext::createDefaultContext()
+{
+ const QStringList args = QApplication::arguments();
+ QString device;
+ for (int index = 0; index < args.count(); ++index) {
+ if (args.at(index).startsWith(QLatin1String("--device="))) {
+ device = args.at(index).mid(9);
+ break;
+ }
+ }
+ if (device.isEmpty())
+ device = QString::fromLocal8Bit(qgetenv("QMLSCENE_DEVICE"));
+ if (device.isEmpty())
+ return new QSGContext();
+
+#if !defined (QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS)
+ if (QSGContextFactoryInterface *factory
+ = qobject_cast<QSGContextFactoryInterface*>
+ (loader()->instance(device))) {
+ QSGContext *context = factory->create(device);
+ if (context)
+ return context;
+ }
+#ifndef QT_NO_DEBUG
+ qWarning("Could not create scene graph context for device '%s'"
+ " - check that plugins are installed correctly in %s",
+ qPrintable(device),
+ qPrintable(QLibraryInfo::location(QLibraryInfo::PluginsPath)));
+#endif
+#endif // QT_NO_LIBRARY || QT_NO_SETTINGS
+
+ return new QSGContext();
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/scenegraph/qsgcontextplugin_p.h b/src/declarative/scenegraph/qsgcontextplugin_p.h
new file mode 100644
index 0000000000..e36bc13a9b
--- /dev/null
+++ b/src/declarative/scenegraph/qsgcontextplugin_p.h
@@ -0,0 +1,81 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGCONTEXTPLUGIN_H
+#define QSGCONTEXTPLUGIN_H
+
+#include <QtCore/qplugin.h>
+#include <QtCore/qfactoryinterface.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QSGContext;
+
+struct Q_DECLARATIVE_EXPORT QSGContextFactoryInterface : public QFactoryInterface
+{
+ virtual QSGContext *create(const QString &key) const = 0;
+};
+
+#define QSGContextFactoryInterface_iid \
+ "com.trolltech.Qt.QSGContextFactoryInterface"
+Q_DECLARE_INTERFACE(QSGContextFactoryInterface, QSGContextFactoryInterface_iid)
+
+class Q_DECLARATIVE_EXPORT QSGContextPlugin : public QObject, public QSGContextFactoryInterface
+{
+ Q_OBJECT
+ Q_INTERFACES(QSGContextFactoryInterface:QFactoryInterface)
+public:
+ explicit QSGContextPlugin(QObject *parent = 0);
+ virtual ~QSGContextPlugin();
+
+ virtual QStringList keys() const = 0;
+ virtual QSGContext *create(const QString &key) const = 0;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QSGCONTEXTPLUGIN_H
diff --git a/src/declarative/scenegraph/qsgdefaultglyphnode.cpp b/src/declarative/scenegraph/qsgdefaultglyphnode.cpp
new file mode 100644
index 0000000000..a5a28a334e
--- /dev/null
+++ b/src/declarative/scenegraph/qsgdefaultglyphnode.cpp
@@ -0,0 +1,95 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgdefaultglyphnode_p.h"
+#include "qsgdefaultglyphnode_p_p.h"
+
+#include <qglshaderprogram.h>
+#include <private/qfont_p.h>
+
+QT_BEGIN_NAMESPACE
+
+QSGDefaultGlyphNode::QSGDefaultGlyphNode()
+ : m_material(0)
+ , m_geometry(QSGGeometry::defaultAttributes_TexturedPoint2D(), 0)
+{
+ m_geometry.setDrawingMode(GL_TRIANGLES);
+ setGeometry(&m_geometry);
+}
+
+QSGDefaultGlyphNode::~QSGDefaultGlyphNode()
+{
+ delete m_material;
+}
+
+void QSGDefaultGlyphNode::setColor(const QColor &color)
+{
+ m_color = color;
+ if (m_material != 0) {
+ m_material->setColor(color);
+ setMaterial(m_material); // Indicate the material state has changed
+ }
+}
+
+void QSGDefaultGlyphNode::setGlyphs(const QPointF &position, const QGlyphRun &glyphs)
+{
+ if (m_material != 0)
+ delete m_material;
+
+ QRawFont font = glyphs.rawFont();
+ m_material = new QSGTextMaskMaterial(font);
+ m_material->setColor(m_color);
+
+ QRectF boundingRect;
+ m_material->populate(position, glyphs.glyphIndexes(), glyphs.positions(), geometry(),
+ &boundingRect, &m_baseLine);
+
+ setMaterial(m_material);
+ setBoundingRect(boundingRect);
+
+ markDirty(DirtyGeometry);
+
+#ifdef QML_RUNTIME_TESTING
+ description = QLatin1String("glyphs");
+#endif
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/scenegraph/qsgdefaultglyphnode_p.cpp b/src/declarative/scenegraph/qsgdefaultglyphnode_p.cpp
new file mode 100644
index 0000000000..4b51dfc5d4
--- /dev/null
+++ b/src/declarative/scenegraph/qsgdefaultglyphnode_p.cpp
@@ -0,0 +1,313 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgdefaultglyphnode_p_p.h"
+
+#include <qglshaderprogram.h>
+
+#include <private/qtextureglyphcache_gl_p.h>
+#include <private/qfontengine_p.h>
+#include <private/qglextensions_p.h>
+
+#include <private/qsgtexture_p.h>
+
+#include <private/qrawfont_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QSGTextMaskMaterialData : public QSGMaterialShader
+{
+public:
+ QSGTextMaskMaterialData();
+
+ virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect);
+ virtual char const *const *attributeNames() const;
+private:
+ virtual void initialize();
+ virtual const char *vertexShader() const;
+ virtual const char *fragmentShader() const;
+
+ int m_matrix_id;
+ int m_color_id;
+ int m_textureScale_id;
+};
+
+const char *QSGTextMaskMaterialData::vertexShader() const {
+ return
+ "uniform highp mat4 matrix; \n"
+ "uniform highp vec2 textureScale; \n"
+ "attribute highp vec4 vCoord; \n"
+ "attribute highp vec2 tCoord; \n"
+ "varying highp vec2 sampleCoord; \n"
+ "void main() { \n"
+ " sampleCoord = tCoord * textureScale; \n"
+ " gl_Position = matrix * vCoord; \n"
+ "}";
+}
+
+const char *QSGTextMaskMaterialData::fragmentShader() const {
+ return
+ "varying highp vec2 sampleCoord; \n"
+ "uniform sampler2D texture; \n"
+ "uniform lowp vec4 color; \n"
+ "void main() { \n"
+ " gl_FragColor = color * texture2D(texture, sampleCoord).a; \n"
+ "}";
+}
+
+char const *const *QSGTextMaskMaterialData::attributeNames() const
+{
+ static char const *const attr[] = { "vCoord", "tCoord", 0 };
+ return attr;
+}
+
+QSGTextMaskMaterialData::QSGTextMaskMaterialData()
+{
+}
+
+void QSGTextMaskMaterialData::initialize()
+{
+ m_matrix_id = program()->uniformLocation("matrix");
+ m_color_id = program()->uniformLocation("color");
+ m_textureScale_id = program()->uniformLocation("textureScale");
+}
+
+void QSGTextMaskMaterialData::updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect)
+{
+ Q_ASSERT(oldEffect == 0 || newEffect->type() == oldEffect->type());
+ QSGTextMaskMaterial *material = static_cast<QSGTextMaskMaterial *>(newEffect);
+ QSGTextMaskMaterial *oldMaterial = static_cast<QSGTextMaskMaterial *>(oldEffect);
+
+ if (oldMaterial == 0 || material->color() != oldMaterial->color() || state.isOpacityDirty()) {
+ QVector4D color(material->color().redF(), material->color().greenF(),
+ material->color().blueF(), material->color().alphaF());
+ color *= state.opacity();
+ program()->setUniformValue(m_color_id, color);
+ }
+
+ bool updated = material->ensureUpToDate();
+ Q_ASSERT(material->texture());
+
+ Q_ASSERT(oldMaterial == 0 || oldMaterial->texture());
+ if (updated
+ || oldMaterial == 0
+ || oldMaterial->texture()->textureId() != material->texture()->textureId()) {
+ program()->setUniformValue(m_textureScale_id, QVector2D(1.0 / material->cacheTextureWidth(),
+ 1.0 / material->cacheTextureHeight()));
+ glBindTexture(GL_TEXTURE_2D, material->texture()->textureId());
+
+ // Set the mag/min filters to be linear. We only need to do this when the texture
+ // has been recreated.
+ if (updated) {
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ }
+ }
+
+ if (state.isMatrixDirty())
+ program()->setUniformValue(m_matrix_id, state.combinedMatrix());
+}
+
+QSGTextMaskMaterial::QSGTextMaskMaterial(const QRawFont &font)
+ : m_texture(0), m_glyphCache(), m_font(font)
+{
+ init();
+}
+
+QSGTextMaskMaterial::~QSGTextMaskMaterial()
+{
+}
+
+void QSGTextMaskMaterial::init()
+{
+ Q_ASSERT(m_font.isValid());
+
+ QFontEngineGlyphCache::Type type = QFontEngineGlyphCache::Raster_A8;
+ setFlag(Blending, true);
+
+ QGLContext *ctx = const_cast<QGLContext *>(QGLContext::currentContext());
+ Q_ASSERT(ctx != 0);
+
+ QRawFontPrivate *fontD = QRawFontPrivate::get(m_font);
+ if (fontD->fontEngine != 0) {
+ m_glyphCache = fontD->fontEngine->glyphCache(ctx, type, QTransform());
+ if (!m_glyphCache || m_glyphCache->cacheType() != type) {
+ m_glyphCache = new QGLTextureGlyphCache(ctx, type, QTransform());
+ fontD->fontEngine->setGlyphCache(ctx, m_glyphCache.data());
+ }
+ }
+
+#if !defined(QT_OPENGL_ES_2)
+ bool success = qt_resolve_version_2_0_functions(ctx)
+ && qt_resolve_buffer_extensions(ctx);
+ Q_ASSERT(success);
+ Q_UNUSED(success);
+#endif
+}
+
+void QSGTextMaskMaterial::populate(const QPointF &p,
+ const QVector<quint32> &glyphIndexes,
+ const QVector<QPointF> &glyphPositions,
+ QSGGeometry *geometry,
+ QRectF *boundingRect,
+ QPointF *baseLine)
+{
+ Q_ASSERT(m_font.isValid());
+ QVector<QFixedPoint> fixedPointPositions;
+ for (int i=0; i<glyphPositions.size(); ++i)
+ fixedPointPositions.append(QFixedPoint::fromPointF(glyphPositions.at(i)));
+
+ QTextureGlyphCache *cache = glyphCache();
+
+ QRawFontPrivate *fontD = QRawFontPrivate::get(m_font);
+ cache->populate(fontD->fontEngine, glyphIndexes.size(), glyphIndexes.constData(),
+ fixedPointPositions.data());
+ cache->fillInPendingGlyphs();
+
+ int margin = cache->glyphMargin();
+
+ Q_ASSERT(geometry->indexType() == GL_UNSIGNED_SHORT);
+ geometry->allocate(glyphIndexes.size() * 4, glyphIndexes.size() * 6);
+ QVector4D *vp = (QVector4D *)geometry->vertexDataAsTexturedPoint2D();
+ Q_ASSERT(geometry->stride() == sizeof(QVector4D));
+ ushort *ip = geometry->indexDataAsUShort();
+
+ QPointF position(p.x(), p.y() - m_font.ascent());
+ bool supportsSubPixelPositions = fontD->fontEngine->supportsSubPixelPositions();
+ for (int i=0; i<glyphIndexes.size(); ++i) {
+ QFixed subPixelPosition;
+ if (supportsSubPixelPositions)
+ subPixelPosition = cache->subPixelPositionForX(QFixed::fromReal(glyphPositions.at(i).x()));
+
+ QTextureGlyphCache::GlyphAndSubPixelPosition glyph(glyphIndexes.at(i), subPixelPosition);
+ const QTextureGlyphCache::Coord &c = cache->coords.value(glyph);
+
+ QPointF glyphPosition = glyphPositions.at(i) + position;
+ int x = qRound(glyphPosition.x()) + c.baseLineX - margin;
+ int y = qRound(glyphPosition.y()) - c.baseLineY - margin;
+
+ *boundingRect |= QRectF(x + margin, y + margin, c.w, c.h);
+
+ float cx1 = x;
+ float cx2 = x + c.w;
+ float cy1 = y;
+ float cy2 = y + c.h;
+
+ float tx1 = c.x;
+ float tx2 = (c.x + c.w);
+ float ty1 = c.y;
+ float ty2 = (c.y + c.h);
+
+ if (baseLine->isNull())
+ *baseLine = glyphPosition;
+
+ vp[4 * i + 0] = QVector4D(cx1, cy1, tx1, ty1);
+ vp[4 * i + 1] = QVector4D(cx2, cy1, tx2, ty1);
+ vp[4 * i + 2] = QVector4D(cx1, cy2, tx1, ty2);
+ vp[4 * i + 3] = QVector4D(cx2, cy2, tx2, ty2);
+
+ int o = i * 4;
+ ip[6 * i + 0] = o + 0;
+ ip[6 * i + 1] = o + 2;
+ ip[6 * i + 2] = o + 3;
+ ip[6 * i + 3] = o + 3;
+ ip[6 * i + 4] = o + 1;
+ ip[6 * i + 5] = o + 0;
+ }
+}
+
+QSGMaterialType *QSGTextMaskMaterial::type() const
+{
+ static QSGMaterialType type;
+ return &type;
+}
+
+QGLTextureGlyphCache *QSGTextMaskMaterial::glyphCache() const
+{
+ return static_cast<QGLTextureGlyphCache*>(m_glyphCache.data());
+}
+
+QSGMaterialShader *QSGTextMaskMaterial::createShader() const
+{
+ return new QSGTextMaskMaterialData;
+}
+
+int QSGTextMaskMaterial::compare(const QSGMaterial *o) const
+{
+ Q_ASSERT(o && type() == o->type());
+ const QSGTextMaskMaterial *other = static_cast<const QSGTextMaskMaterial *>(o);
+ if (m_glyphCache != other->m_glyphCache)
+ return m_glyphCache - other->m_glyphCache;
+ QRgb c1 = m_color.rgba();
+ QRgb c2 = other->m_color.rgba();
+ return int(c2 < c1) - int(c1 < c2);
+}
+
+bool QSGTextMaskMaterial::ensureUpToDate()
+{
+ QSize glyphCacheSize(glyphCache()->width(), glyphCache()->height());
+ if (glyphCacheSize != m_size) {
+ if (m_texture)
+ delete m_texture;
+ m_texture = new QSGPlainTexture();
+ m_texture->setTextureId(glyphCache()->texture());
+ m_texture->setTextureSize(QSize(glyphCache()->width(), glyphCache()->height()));
+ m_texture->setOwnsTexture(false);
+
+ m_size = glyphCacheSize;
+
+ return true;
+ } else {
+ return false;
+ }
+}
+
+int QSGTextMaskMaterial::cacheTextureWidth() const
+{
+ return glyphCache()->width();
+}
+
+int QSGTextMaskMaterial::cacheTextureHeight() const
+{
+ return glyphCache()->height();
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/scenegraph/qsgdefaultglyphnode_p.h b/src/declarative/scenegraph/qsgdefaultglyphnode_p.h
new file mode 100644
index 0000000000..1f1319781c
--- /dev/null
+++ b/src/declarative/scenegraph/qsgdefaultglyphnode_p.h
@@ -0,0 +1,83 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef DEFAULT_GLYPHNODE_H
+#define DEFAULT_GLYPHNODE_H
+
+#include <private/qsgadaptationlayer_p.h>
+#include <qsgnode.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QGlyphs;
+class QSGTextMaskMaterial;
+class QSGDefaultGlyphNode: public QSGGlyphNode
+{
+public:
+ QSGDefaultGlyphNode();
+ ~QSGDefaultGlyphNode();
+
+ virtual QPointF baseLine() const { return m_baseLine; }
+ virtual void setGlyphs(const QPointF &position, const QGlyphRun &glyphs);
+ virtual void setColor(const QColor &color);
+
+ virtual void setPreferredAntialiasingMode(AntialiasingMode) { }
+
+private:
+ QGlyphRun m_glyphs;
+ QPointF m_position;
+ QColor m_color;
+
+ QPointF m_baseLine;
+ QSGTextMaskMaterial *m_material;
+
+ QSGGeometry m_geometry;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // DEFAULT_GLYPHNODE_H
diff --git a/src/declarative/scenegraph/qsgdefaultglyphnode_p_p.h b/src/declarative/scenegraph/qsgdefaultglyphnode_p_p.h
new file mode 100644
index 0000000000..b5f0d70020
--- /dev/null
+++ b/src/declarative/scenegraph/qsgdefaultglyphnode_p_p.h
@@ -0,0 +1,95 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef TEXTMASKMATERIAL_H
+#define TEXTMASKMATERIAL_H
+
+#include <qsgmaterial.h>
+#include <qsgtexture.h>
+#include <qsggeometry.h>
+#include <qshareddata.h>
+#include <private/qsgtexture_p.h>
+#include <qrawfont.h>
+
+QT_BEGIN_NAMESPACE
+
+class QFontEngineGlyphCache;
+class QGLTextureGlyphCache;
+class QFontEngine;
+class Geometry;
+class QSGTextMaskMaterial: public QSGMaterial
+{
+public:
+ QSGTextMaskMaterial(const QRawFont &font);
+ ~QSGTextMaskMaterial();
+
+ virtual QSGMaterialType *type() const;
+ virtual QSGMaterialShader *createShader() const;
+ virtual int compare(const QSGMaterial *other) const;
+
+ void setColor(const QColor &color) { m_color = color; }
+ const QColor &color() const { return m_color; }
+
+ QSGTexture *texture() const { return m_texture; }
+
+ int cacheTextureWidth() const;
+ int cacheTextureHeight() const;
+
+ bool ensureUpToDate();
+
+ QGLTextureGlyphCache *glyphCache() const;
+ void populate(const QPointF &position,
+ const QVector<quint32> &glyphIndexes, const QVector<QPointF> &glyphPositions,
+ QSGGeometry *geometry, QRectF *boundingRect, QPointF *baseLine);
+
+private:
+ void init();
+
+ QSGPlainTexture *m_texture;
+ QExplicitlySharedDataPointer<QFontEngineGlyphCache> m_glyphCache;
+ QRawFont m_font;
+ QColor m_color;
+ QSize m_size;
+};
+
+QT_END_NAMESPACE
+
+#endif // TEXTMASKMATERIAL_H
diff --git a/src/declarative/scenegraph/qsgdefaultimagenode.cpp b/src/declarative/scenegraph/qsgdefaultimagenode.cpp
new file mode 100644
index 0000000000..972a4cba1e
--- /dev/null
+++ b/src/declarative/scenegraph/qsgdefaultimagenode.cpp
@@ -0,0 +1,288 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgdefaultimagenode_p.h"
+
+#include <private/qsgtextureprovider_p.h>
+
+#include <QtCore/qvarlengtharray.h>
+#include <QtCore/qmath.h>
+#include <QtOpenGL/qglfunctions.h>
+
+QT_BEGIN_NAMESPACE
+
+QSGDefaultImageNode::QSGDefaultImageNode()
+ : m_sourceRect(0, 0, 1, 1)
+ , m_dirtyGeometry(false)
+ , m_geometry(QSGGeometry::defaultAttributes_TexturedPoint2D(), 4)
+{
+ setMaterial(&m_materialO);
+ setOpaqueMaterial(&m_material);
+ setGeometry(&m_geometry);
+
+#ifdef QML_RUNTIME_TESTING
+ description = QLatin1String("image");
+#endif
+}
+
+void QSGDefaultImageNode::setTargetRect(const QRectF &rect)
+{
+ if (rect == m_targetRect)
+ return;
+ m_targetRect = rect;
+ m_dirtyGeometry = true;
+}
+
+void QSGDefaultImageNode::setSourceRect(const QRectF &rect)
+{
+ if (rect == m_sourceRect)
+ return;
+ m_sourceRect = rect;
+ m_dirtyGeometry = true;
+}
+
+
+void QSGDefaultImageNode::setFiltering(QSGTexture::Filtering filtering)
+{
+ if (m_material.filtering() == filtering)
+ return;
+
+ m_material.setFiltering(filtering);
+ m_materialO.setFiltering(filtering);
+ markDirty(DirtyMaterial);
+}
+
+
+void QSGDefaultImageNode::setMipmapFiltering(QSGTexture::Filtering filtering)
+{
+ if (m_material.mipmapFiltering() == filtering)
+ return;
+
+ m_material.setMipmapFiltering(filtering);
+ m_materialO.setMipmapFiltering(filtering);
+ markDirty(DirtyMaterial);
+}
+
+void QSGDefaultImageNode::setVerticalWrapMode(QSGTexture::WrapMode wrapMode)
+{
+ if (m_material.verticalWrapMode() == wrapMode)
+ return;
+
+ m_material.setVerticalWrapMode(wrapMode);
+ m_materialO.setVerticalWrapMode(wrapMode);
+ markDirty(DirtyMaterial);
+}
+
+void QSGDefaultImageNode::setHorizontalWrapMode(QSGTexture::WrapMode wrapMode)
+{
+ if (m_material.horizontalWrapMode() == wrapMode)
+ return;
+
+ m_material.setHorizontalWrapMode(wrapMode);
+ m_materialO.setHorizontalWrapMode(wrapMode);
+ markDirty(DirtyMaterial);
+}
+
+
+void QSGDefaultImageNode::setTexture(QSGTexture *texture)
+{
+ if (texture == m_material.texture())
+ return;
+
+ m_material.setTexture(texture);
+ m_materialO.setTexture(texture);
+ // Texture cleanup
+// if (!texture.isNull())
+// m_material.setBlending(texture->hasAlphaChannel());
+ markDirty(DirtyMaterial);
+
+ // Because the texture can be a different part of the atlas, we need to update it...
+ m_dirtyGeometry = true;
+}
+
+void QSGDefaultImageNode::update()
+{
+ if (m_dirtyGeometry)
+ updateGeometry();
+}
+
+void QSGDefaultImageNode::preprocess()
+{
+ bool doDirty = false;
+ QSGDynamicTexture *t = qobject_cast<QSGDynamicTexture *>(m_material.texture());
+ if (t) {
+ doDirty = t->updateTexture();
+ updateGeometry();
+ }
+// ### texture cleanup
+// bool alpha = m_material.blending();
+// if (!m_material->texture().isNull() && alpha != m_material.texture()->hasAlphaChannel()) {
+// m_material.setBlending(!alpha);
+// doDirty = true;
+// }
+
+ if (doDirty)
+ markDirty(DirtyMaterial);
+}
+
+inline static bool isPowerOfTwo(int x)
+{
+ // Assumption: x >= 1
+ return x == (x & -x);
+}
+
+namespace {
+ struct X { float x, tx; };
+ struct Y { float y, ty; };
+}
+
+void QSGDefaultImageNode::updateGeometry()
+{
+ const QSGTexture *t = m_material.texture();
+ if (!t) {
+ m_geometry.allocate(4);
+ m_geometry.setDrawingMode(GL_TRIANGLE_STRIP);
+ QSGGeometry::updateTexturedRectGeometry(&m_geometry, QRectF(), QRectF());
+ } else {
+ QRectF textureRect = t->textureSubRect();
+
+ bool isSubRect = textureRect != QRectF(0, 0, 1, 1);
+ const int ceilRight = qCeil(m_sourceRect.right());
+ const int floorLeft = qFloor(m_sourceRect.left());
+ const int ceilBottom = qCeil(m_sourceRect.bottom());
+ const int floorTop = qFloor(m_sourceRect.top());
+ const int hCells = ceilRight - floorLeft;
+ const int vCells = ceilBottom - floorTop;
+ bool isRepeating = hCells > 1 || vCells > 1;
+
+#ifdef QT_OPENGL_ES_2
+ const QGLContext *ctx = QGLContext::currentContext();
+ bool npotSupported = ctx->functions()->hasOpenGLFeature(QGLFunctions::NPOTTextures);
+
+ QSize size = t->textureSize();
+ bool isNpot = !isPowerOfTwo(size.width()) || !isPowerOfTwo(size.height());
+
+ if (isRepeating && (isSubRect || (isNpot && !npotSupported))) {
+#else
+ if (isRepeating && isSubRect) {
+#endif
+ m_geometry.allocate(hCells * vCells * 4, hCells * vCells * 6);
+ m_geometry.setDrawingMode(GL_TRIANGLES);
+ QVarLengthArray<X, 32> xData(2 * hCells);
+ QVarLengthArray<Y, 32> yData(2 * vCells);
+ X *xs = xData.data();
+ Y *ys = yData.data();
+
+ xs->x = m_targetRect.left();
+ xs->tx = textureRect.x() + (m_sourceRect.left() - floorLeft) * textureRect.width();
+ ++xs;
+ ys->y = m_targetRect.top();
+ ys->ty = textureRect.y() + (m_sourceRect.top() - floorTop) * textureRect.height();
+ ++ys;
+
+ float a, b;
+ b = m_targetRect.width() / m_sourceRect.width();
+ a = m_targetRect.x() - m_sourceRect.x() * b;
+ for (int i = floorLeft + 1; i <= ceilRight - 1; ++i) {
+ xs[0].x = xs[1].x = a + b * i;
+ xs[0].tx = 1;
+ xs[1].tx = 0;
+ xs += 2;
+ }
+ b = m_targetRect.height() / m_sourceRect.height();
+ a = m_targetRect.y() - m_sourceRect.y() * b;
+ for (int i = floorTop + 1; i <= ceilBottom - 1; ++i) {
+ ys[0].y = ys[1].y = a + b * i;
+ ys[0].ty = 1;
+ ys[1].ty = 0;
+ ys += 2;
+ }
+
+ xs->x = m_targetRect.right();
+ xs->tx = textureRect.x() + (m_sourceRect.right() - ceilRight + 1) * textureRect.width();
+
+ ys->y = m_targetRect.bottom();
+ ys->ty = textureRect.y() + (m_sourceRect.bottom() - ceilBottom + 1) * textureRect.height();
+
+ QSGGeometry::TexturedPoint2D *vertices = m_geometry.vertexDataAsTexturedPoint2D();
+ ys = yData.data();
+ for (int j = 0; j < vCells; ++j, ys += 2) {
+ xs = xData.data();
+ for (int i = 0; i < hCells; ++i, xs += 2) {
+ vertices[0].x = vertices[2].x = xs[0].x;
+ vertices[0].tx = vertices[2].tx = xs[0].tx;
+ vertices[1].x = vertices[3].x = xs[1].x;
+ vertices[1].tx = vertices[3].tx = xs[1].tx;
+
+ vertices[0].y = vertices[1].y = ys[0].y;
+ vertices[0].ty = vertices[1].ty = ys[0].ty;
+ vertices[2].y = vertices[3].y = ys[1].y;
+ vertices[2].ty = vertices[3].ty = ys[1].ty;
+
+ vertices += 4;
+ }
+ }
+
+ quint16 *indices = m_geometry.indexDataAsUShort();
+ for (int i = 0; i < 4 * vCells * hCells; i += 4) {
+ *indices++ = i;
+ *indices++ = i + 2;
+ *indices++ = i + 3;
+ *indices++ = i + 3;
+ *indices++ = i + 1;
+ *indices++ = i;
+ }
+ } else {
+ QRectF sr(textureRect.x() + m_sourceRect.x() * textureRect.width(),
+ textureRect.y() + m_sourceRect.y() * textureRect.height(),
+ m_sourceRect.width() * textureRect.width(),
+ m_sourceRect.height() * textureRect.height());
+
+ m_geometry.allocate(4);
+ m_geometry.setDrawingMode(GL_TRIANGLE_STRIP);
+ QSGGeometry::updateTexturedRectGeometry(&m_geometry, m_targetRect, sr);
+ }
+ }
+ markDirty(DirtyGeometry);
+ m_dirtyGeometry = false;
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/scenegraph/qsgdefaultimagenode_p.h b/src/declarative/scenegraph/qsgdefaultimagenode_p.h
new file mode 100644
index 0000000000..36ae51ba4a
--- /dev/null
+++ b/src/declarative/scenegraph/qsgdefaultimagenode_p.h
@@ -0,0 +1,90 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#ifndef DEFAULT_PIXMAPNODE_H
+#define DEFAULT_PIXMAPNODE_H
+
+#include <private/qsgadaptationlayer_p.h>
+
+#include "qsgtexturematerial.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QSGDefaultImageNode : public QSGImageNode
+{
+public:
+ QSGDefaultImageNode();
+ virtual void setTargetRect(const QRectF &rect);
+ virtual void setSourceRect(const QRectF &rect);
+ virtual void setTexture(QSGTexture *t);
+ virtual void update();
+
+ virtual void setMipmapFiltering(QSGTexture::Filtering filtering);
+ virtual void setFiltering(QSGTexture::Filtering filtering);
+ virtual void setHorizontalWrapMode(QSGTexture::WrapMode wrapMode);
+ virtual void setVerticalWrapMode(QSGTexture::WrapMode wrapMode);
+
+ virtual void preprocess();
+
+private:
+ void updateGeometry();
+
+ QRectF m_targetRect;
+ QRectF m_sourceRect;
+
+ QSGOpaqueTextureMaterial m_material;
+ QSGTextureMaterial m_materialO;
+
+ uint m_dirtyGeometry : 1;
+
+ QSGGeometry m_geometry;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/declarative/scenegraph/qsgdefaultrectanglenode.cpp b/src/declarative/scenegraph/qsgdefaultrectanglenode.cpp
new file mode 100644
index 0000000000..34a6db4f78
--- /dev/null
+++ b/src/declarative/scenegraph/qsgdefaultrectanglenode.cpp
@@ -0,0 +1,548 @@
+
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+
+#include "qsgdefaultrectanglenode_p.h"
+
+#include <private/qsgvertexcolormaterial_p.h>
+#include "qsgtexturematerial.h"
+
+#include <private/qsgcontext_p.h>
+
+#include <QtCore/qmath.h>
+#include <QtCore/qvarlengtharray.h>
+
+QT_BEGIN_NAMESPACE
+
+QSGDefaultRectangleNode::QSGDefaultRectangleNode(QSGContext *context)
+ : m_border(0)
+ , m_radius(0)
+ , m_pen_width(0)
+ , m_aligned(true)
+ , m_gradient_is_opaque(true)
+ , m_dirty_geometry(false)
+ , m_default_geometry(QSGGeometry::defaultAttributes_Point2D(), 4)
+ , m_context(context)
+{
+ setGeometry(&m_default_geometry);
+ setMaterial(&m_fill_material);
+ m_border_material.setColor(QColor(0, 0, 0));
+
+ m_material_type = TypeFlat;
+
+#ifdef QML_RUNTIME_TESTING
+ description = QLatin1String("rectangle");
+#endif
+}
+
+QSGDefaultRectangleNode::~QSGDefaultRectangleNode()
+{
+ switch (m_material_type) {
+ case TypeFlat:
+ break;
+ case TypeVertexGradient:
+ delete material();
+ break;
+ }
+ delete m_border;
+}
+
+QSGGeometryNode *QSGDefaultRectangleNode::border()
+{
+ if (!m_border) {
+ m_border = new QSGGeometryNode;
+ m_border->setMaterial(&m_border_material);
+ QSGGeometry *geometry = new QSGGeometry(QSGGeometry::defaultAttributes_Point2D(), 0);
+ m_border->setGeometry(geometry);
+ m_border->setFlag(QSGNode::OwnsGeometry);
+ }
+ return m_border;
+}
+
+void QSGDefaultRectangleNode::setRect(const QRectF &rect)
+{
+ if (rect == m_rect)
+ return;
+ m_rect = rect;
+ m_dirty_geometry = true;
+}
+
+void QSGDefaultRectangleNode::setColor(const QColor &color)
+{
+ if (color == m_fill_material.color())
+ return;
+ if (m_gradient_stops.isEmpty()) {
+ Q_ASSERT(m_material_type == TypeFlat);
+ m_fill_material.setColor(color);
+ setMaterial(&m_fill_material); // Indicate that the material state has changed.
+ }
+}
+
+void QSGDefaultRectangleNode::setPenColor(const QColor &color)
+{
+ if (color == m_border_material.color())
+ return;
+ m_border_material.setColor(color);
+ border()->setMaterial(&m_border_material); // Indicate that the material state has changed.
+}
+
+void QSGDefaultRectangleNode::setPenWidth(qreal width)
+{
+ if (width == m_pen_width)
+ return;
+ m_pen_width = width;
+ QSGNode *b = border();
+ if (m_pen_width <= 0 && b->parent())
+ removeChildNode(b);
+ else if (m_pen_width > 0 && !b->parent())
+ appendChildNode(b);
+ m_dirty_geometry = true;
+}
+
+
+void QSGDefaultRectangleNode::setGradientStops(const QGradientStops &stops)
+{
+ if (stops.constData() == m_gradient_stops.constData())
+ return;
+
+ m_gradient_stops = stops;
+
+ m_gradient_is_opaque = true;
+ for (int i = 0; i < stops.size(); ++i)
+ m_gradient_is_opaque &= stops.at(i).second.alpha() == 0xff;
+
+ if (stops.isEmpty()) {
+ // No gradient specified, use flat color.
+ if (m_material_type != TypeFlat) {
+
+ delete material();
+ delete opaqueMaterial();
+ setOpaqueMaterial(0);
+
+ setMaterial(&m_fill_material);
+ m_material_type = TypeFlat;
+
+ setGeometry(&m_default_geometry);
+ setFlag(OwnsGeometry, false);
+ }
+ } else {
+ if (m_material_type == TypeFlat) {
+ QSGVertexColorMaterial *material = new QSGVertexColorMaterial;
+ setMaterial(material);
+ m_material_type = TypeVertexGradient;
+ QSGGeometry *g = new QSGGeometry(QSGGeometry::defaultAttributes_ColoredPoint2D(), 0);
+ setGeometry(g);
+ setFlag(OwnsGeometry);
+ }
+ static_cast<QSGVertexColorMaterial *>(material())->setColorsAreOpaque(m_gradient_is_opaque);
+ }
+
+ m_dirty_geometry = true;
+}
+
+void QSGDefaultRectangleNode::setRadius(qreal radius)
+{
+ if (radius == m_radius)
+ return;
+ m_radius = radius;
+ m_dirty_geometry = true;
+}
+
+void QSGDefaultRectangleNode::setAligned(bool aligned)
+{
+ if (aligned == m_aligned)
+ return;
+ m_aligned = aligned;
+ m_dirty_geometry = true;
+}
+
+void QSGDefaultRectangleNode::update()
+{
+ if (m_dirty_geometry) {
+ updateGeometry();
+ m_dirty_geometry = false;
+ }
+}
+
+struct Color4ub
+{
+ unsigned char r, g, b, a;
+};
+
+Color4ub operator *(Color4ub c, float t) { c.a *= t; c.r *= t; c.g *= t; c.b *= t; return c; }
+Color4ub operator +(Color4ub a, Color4ub b) { a.a += b.a; a.r += b.r; a.g += b.g; a.b += b.b; return a; }
+
+static inline Color4ub colorToColor4ub(const QColor &c)
+{
+ Color4ub color = { c.redF() * c.alphaF() * 255,
+ c.greenF() * c.alphaF() * 255,
+ c.blueF() * c.alphaF() * 255,
+ c.alphaF() * 255
+ };
+ return color;
+}
+
+struct Vertex
+{
+ QVector2D position;
+};
+
+struct ColorVertex
+{
+ QVector2D position;
+ Color4ub color;
+};
+
+void QSGDefaultRectangleNode::updateGeometry()
+{
+ qreal penWidth = m_aligned ? qreal(qRound(m_pen_width)) : m_pen_width;
+
+ // fast path for the simple case...
+ if ((penWidth == 0 || m_border_material.color().alpha() == 0)
+ && m_radius == 0
+ && m_material_type == TypeFlat) {
+ QSGGeometry::updateRectGeometry(&m_default_geometry, m_rect);
+ return;
+ }
+
+ QSGGeometry *fill = geometry();
+
+ // Check that the vertex type matches the material.
+ Q_ASSERT(m_material_type != TypeFlat || fill->stride() == sizeof(Vertex));
+ Q_ASSERT(m_material_type != TypeVertexGradient || fill->stride() == sizeof(ColorVertex));
+
+ QSGGeometry *borderGeometry = 0;
+ if (m_border) {
+ borderGeometry = border()->geometry();
+ Q_ASSERT(borderGeometry->stride() == sizeof(Vertex));
+ }
+
+ int fillVertexCount = 0;
+
+ // Preallocate arrays for a rectangle with 18 segments per corner and 3 gradient stops.
+ uchar *fillVertices = 0;
+ Vertex *borderVertices = 0;
+
+ Color4ub fillColor = colorToColor4ub(m_fill_material.color());
+ const QGradientStops &stops = m_gradient_stops;
+
+ if (m_radius > 0) {
+ // Rounded corners.
+
+ // Radius should never exceeds half of the width or half of the height
+ qreal radius = qMin(qMin(m_rect.width() * qreal(0.5), m_rect.height() * qreal(0.5)), m_radius);
+ QRectF innerRect = m_rect;
+ innerRect.adjust(radius, radius, -radius, -radius);
+ if (m_aligned && (int(penWidth) & 1)) {
+ // Pen width is odd, so add the offset as documented.
+ innerRect.moveLeft(innerRect.left() + qreal(0.5));
+ innerRect.moveTop(innerRect.top() + qreal(0.5));
+ }
+
+ qreal innerRadius = radius - penWidth * qreal(0.5);
+ qreal outerRadius = radius + penWidth * qreal(0.5);
+
+ // Number of segments per corner, approximately one per 3 pixels.
+ int segments = qBound(3, qCeil(outerRadius * (M_PI / 6)), 18);
+
+ /*
+
+ --+-__
+ | segment
+ | _+
+ --+-__ _- \
+ -+ segment
+ --------+ \ <- gradient line
+ +-----+
+ | |
+
+ */
+
+ int nextGradientStop = 0;
+ qreal gradientPos = (radius - innerRadius) / (innerRect.height() + 2 * radius);
+ while (nextGradientStop < stops.size() && stops.at(nextGradientStop).first <= gradientPos)
+ ++nextGradientStop;
+ int lastGradientStop = stops.size() - 1;
+ qreal lastGradientPos = (innerRect.height() + radius + innerRadius) / (innerRect.height() + 2 * radius);
+ while (lastGradientStop >= nextGradientStop && stops.at(lastGradientStop).first >= lastGradientPos)
+ --lastGradientStop;
+
+ int borderVertexHead = 0;
+ int borderVertexTail = 0;
+ if (penWidth) {
+ // The reason I add extra vertices where the gradient lines intersect the border is
+ // to avoid pixel sized gaps between the fill and the border caused by floating point
+ // inaccuracies.
+ borderGeometry->allocate((segments + 1) * 2 * 4 + (lastGradientStop - nextGradientStop + 1) * 4 + 2);
+ borderVertexHead = borderVertexTail = (borderGeometry->vertexCount() >> 1) - 1;
+ borderVertices = (Vertex *)borderGeometry->vertexData();
+ }
+
+ fill->allocate((segments + 1) * 4 + (lastGradientStop - nextGradientStop + 1) * 2);
+ fillVertices = (uchar *)fill->vertexData();
+
+ qreal py = 0; // previous inner y-coordinate.
+ qreal plx = 0; // previous inner left x-coordinate.
+ qreal prx = 0; // previous inner right x-coordinate.
+
+ qreal angle = qreal(0.5) * M_PI / qreal(segments);
+ qreal cosStep = qFastCos(angle);
+ qreal sinStep = qFastSin(angle);
+
+ for (int part = 0; part < 2; ++part) {
+ qreal c = 1 - part;
+ qreal s = part;
+ for (int i = 0; i <= segments; ++i) {
+ qreal y = (part ? innerRect.bottom() : innerRect.top()) - innerRadius * c; // current inner y-coordinate.
+ qreal lx = innerRect.left() - innerRadius * s; // current inner left x-coordinate.
+ qreal rx = innerRect.right() + innerRadius * s; // current inner right x-coordinate.
+ qreal Y = (part ? innerRect.bottom() : innerRect.top()) - outerRadius * c; // current outer y-coordinate.
+ qreal lX = innerRect.left() - outerRadius * s; // current outer left x-coordinate.
+ qreal rX = innerRect.right() + outerRadius * s; // current outer right x-coordinate.
+ gradientPos = ((part ? innerRect.height() : 0) + radius - innerRadius * c) / (innerRect.height() + 2 * radius);
+
+ while (nextGradientStop <= lastGradientStop && stops.at(nextGradientStop).first <= gradientPos) {
+ // Insert vertices at gradient stops.
+ qreal gy = (innerRect.top() - radius) + stops.at(nextGradientStop).first * (innerRect.height() + 2 * radius);
+ Q_ASSERT(fillVertexCount >= 2);
+ qreal t = (gy - py) / (y - py);
+ qreal glx = plx * (1 - t) + t * lx;
+ qreal grx = prx * (1 - t) + t * rx;
+
+ if (penWidth) {
+ const Vertex &first = borderVertices[borderVertexHead];
+ borderVertices[--borderVertexHead].position = QVector2D(glx, gy);
+ borderVertices[--borderVertexHead] = first;
+
+ const Vertex &last = borderVertices[borderVertexTail - 2];
+ borderVertices[borderVertexTail++] = last;
+ borderVertices[borderVertexTail++].position = QVector2D(grx, gy);
+ }
+
+ ColorVertex *vertices = (ColorVertex *)fillVertices;
+
+ fillColor = colorToColor4ub(stops.at(nextGradientStop).second);
+ vertices[fillVertexCount].position = QVector2D(grx, gy);
+ vertices[fillVertexCount].color = fillColor;
+ ++fillVertexCount;
+ vertices[fillVertexCount].position = QVector2D(glx, gy);
+ vertices[fillVertexCount].color = fillColor;
+ ++fillVertexCount;
+
+ ++nextGradientStop;
+ }
+
+ if (penWidth) {
+ borderVertices[--borderVertexHead].position = QVector2D(lx, y);
+ borderVertices[--borderVertexHead].position = QVector2D(lX, Y);
+ borderVertices[borderVertexTail++].position = QVector2D(rX, Y);
+ borderVertices[borderVertexTail++].position = QVector2D(rx, y);
+ }
+
+ if (stops.isEmpty()) {
+ Q_ASSERT(m_material_type == TypeFlat);
+ Vertex *vertices = (Vertex *)fillVertices;
+ vertices[fillVertexCount++].position = QVector2D(rx, y);
+ vertices[fillVertexCount++].position = QVector2D(lx, y);
+ } else {
+ if (nextGradientStop == 0) {
+ fillColor = colorToColor4ub(stops.at(0).second);
+ } else if (nextGradientStop == stops.size()) {
+ fillColor = colorToColor4ub(stops.last().second);
+ } else {
+ const QGradientStop &prev = stops.at(nextGradientStop - 1);
+ const QGradientStop &next = stops.at(nextGradientStop);
+ qreal t = (gradientPos - prev.first) / (next.first - prev.first);
+ fillColor = (colorToColor4ub(prev.second) * (1 - t) + colorToColor4ub(next.second) * t);
+ }
+
+ ColorVertex *vertices = (ColorVertex *)fillVertices;
+ vertices[fillVertexCount].position = QVector2D(rx, y);
+ vertices[fillVertexCount].color = fillColor;
+ ++fillVertexCount;
+ vertices[fillVertexCount].position = QVector2D(lx, y);
+ vertices[fillVertexCount].color = fillColor;
+ ++fillVertexCount;
+ }
+ py = y;
+ plx = lx;
+ prx = rx;
+
+ // Rotate
+ qreal tmp = c;
+ c = c * cosStep - s * sinStep;
+ s = s * cosStep + tmp * sinStep;
+ }
+ }
+
+ if (penWidth) {
+ // Close border.
+ const Vertex &first = borderVertices[borderVertexHead];
+ const Vertex &second = borderVertices[borderVertexHead + 1];
+ borderVertices[borderVertexTail++] = first;
+ borderVertices[borderVertexTail++] = second;
+
+ Q_ASSERT(borderVertexHead == 0 && borderVertexTail == borderGeometry->vertexCount());
+ }
+ Q_ASSERT(fillVertexCount == fill->vertexCount());
+
+ } else {
+
+ // Straight corners.
+ QRectF innerRect = m_rect;
+ QRectF outerRect = m_rect;
+
+ qreal halfPenWidth = 0;
+ if (penWidth) {
+ if (m_aligned && (int(penWidth) & 1)) {
+ // Pen width is odd, so add the offset as documented.
+ innerRect.moveLeft(innerRect.left() + qreal(0.5));
+ innerRect.moveTop(innerRect.top() + qreal(0.5));
+ outerRect = innerRect;
+ }
+ halfPenWidth = penWidth * qreal(0.5);
+ innerRect.adjust(halfPenWidth, halfPenWidth, -halfPenWidth, -halfPenWidth);
+ outerRect.adjust(-halfPenWidth, -halfPenWidth, halfPenWidth, halfPenWidth);
+ }
+
+ int nextGradientStop = 0;
+ qreal gradientPos = halfPenWidth / m_rect.height();
+ while (nextGradientStop < stops.size() && stops.at(nextGradientStop).first <= gradientPos)
+ ++nextGradientStop;
+ int lastGradientStop = stops.size() - 1;
+ qreal lastGradientPos = (m_rect.height() - halfPenWidth) / m_rect.height();
+ while (lastGradientStop >= nextGradientStop && stops.at(lastGradientStop).first >= lastGradientPos)
+ --lastGradientStop;
+
+ int borderVertexCount = 0;
+ if (penWidth) {
+ borderGeometry->allocate((1 + lastGradientStop - nextGradientStop) * 4 + 10);
+ borderVertices = (Vertex *)borderGeometry->vertexData();
+ }
+ fill->allocate((3 + lastGradientStop - nextGradientStop) * 2);
+ fillVertices = (uchar *)fill->vertexData();
+
+ QVarLengthArray<qreal, 16> ys(3 + lastGradientStop - nextGradientStop);
+ int yCount = 0;
+
+ for (int part = 0; part < 2; ++part) {
+ qreal y = (part ? innerRect.bottom() : innerRect.top());
+ gradientPos = (y - innerRect.top() + halfPenWidth) / m_rect.height();
+
+ while (nextGradientStop <= lastGradientStop && stops.at(nextGradientStop).first <= gradientPos) {
+ // Insert vertices at gradient stops.
+ qreal gy = (innerRect.top() - halfPenWidth) + stops.at(nextGradientStop).first * m_rect.height();
+ Q_ASSERT(fillVertexCount >= 2);
+
+ ColorVertex *vertices = (ColorVertex *)fillVertices;
+
+ fillColor = colorToColor4ub(stops.at(nextGradientStop).second);
+ vertices[fillVertexCount].position = QVector2D(innerRect.right(), gy);
+ vertices[fillVertexCount].color = fillColor;
+ ++fillVertexCount;
+ vertices[fillVertexCount].position = QVector2D(innerRect.left(), gy);
+ vertices[fillVertexCount].color = fillColor;
+ ++fillVertexCount;
+
+ ys[yCount++] = gy;
+
+ ++nextGradientStop;
+ }
+
+ if (stops.isEmpty()) {
+ Q_ASSERT(m_material_type == TypeFlat);
+ Vertex *vertices = (Vertex *)fillVertices;
+ vertices[fillVertexCount++].position = QVector2D(innerRect.right(), y);
+ vertices[fillVertexCount++].position = QVector2D(innerRect.left(), y);
+ } else {
+ if (nextGradientStop == 0) {
+ fillColor = colorToColor4ub(stops.at(0).second);
+ } else if (nextGradientStop == stops.size()) {
+ fillColor = colorToColor4ub(stops.last().second);
+ } else {
+ const QGradientStop &prev = stops.at(nextGradientStop - 1);
+ const QGradientStop &next = stops.at(nextGradientStop);
+ qreal t = (gradientPos - prev.first) / (next.first - prev.first);
+ fillColor = (colorToColor4ub(prev.second) * (1 - t) + colorToColor4ub(next.second) * t);
+ }
+
+ ColorVertex *vertices = (ColorVertex *)fillVertices;
+ vertices[fillVertexCount].position = QVector2D(innerRect.right(), y);
+ vertices[fillVertexCount].color = fillColor;
+ ++fillVertexCount;
+ vertices[fillVertexCount].position = QVector2D(innerRect.left(), y);
+ vertices[fillVertexCount].color = fillColor;
+ ++fillVertexCount;
+ }
+
+ ys[yCount++] = y;
+ }
+
+ if (penWidth) {
+ borderVertices[borderVertexCount++].position = QVector2D(outerRect.right(), outerRect.top());
+ borderVertices[borderVertexCount++].position = QVector2D(innerRect.right(), ys[0]);
+ for (int i = 1; i < fillVertexCount / 2; ++i) {
+ borderVertices[borderVertexCount++].position = QVector2D(outerRect.right(), outerRect.bottom());
+ borderVertices[borderVertexCount++].position = QVector2D(innerRect.right(), ys[i]);
+ }
+
+ borderVertices[borderVertexCount++].position = QVector2D(outerRect.left(), outerRect.bottom());
+ borderVertices[borderVertexCount++].position = QVector2D(innerRect.left(), ys[fillVertexCount / 2 - 1]);
+ for (int i = fillVertexCount / 2 - 2; i >= 0; --i) {
+ borderVertices[borderVertexCount++].position = QVector2D(outerRect.left(), outerRect.top());
+ borderVertices[borderVertexCount++].position = QVector2D(innerRect.left(), ys[i]);
+ }
+
+ borderVertices[borderVertexCount++].position = QVector2D(outerRect.right(), outerRect.top());
+ borderVertices[borderVertexCount++].position = QVector2D(innerRect.right(), innerRect.top());
+
+ Q_ASSERT(borderVertexCount == borderGeometry->vertexCount());
+ }
+ Q_ASSERT(fillVertexCount == fill->vertexCount());
+ }
+
+ markDirty(DirtyGeometry);
+}
+
+
+QT_END_NAMESPACE
diff --git a/src/declarative/scenegraph/qsgdefaultrectanglenode_p.h b/src/declarative/scenegraph/qsgdefaultrectanglenode_p.h
new file mode 100644
index 0000000000..cd337b6748
--- /dev/null
+++ b/src/declarative/scenegraph/qsgdefaultrectanglenode_p.h
@@ -0,0 +1,108 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#ifndef DEFAULT_RECTANGLENODE_H
+#define DEFAULT_RECTANGLENODE_H
+
+#include <private/qsgadaptationlayer_p.h>
+
+#include "qsgflatcolormaterial.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QSGMaterial;
+class QSGContext;
+
+class QSGDefaultRectangleNode : public QSGRectangleNode
+{
+public:
+ QSGDefaultRectangleNode(QSGContext *context);
+ ~QSGDefaultRectangleNode();
+
+ virtual void setRect(const QRectF &rect);
+ virtual void setColor(const QColor &color);
+ virtual void setPenColor(const QColor &color);
+ virtual void setPenWidth(qreal width);
+ virtual void setGradientStops(const QGradientStops &stops);
+ virtual void setRadius(qreal radius);
+ virtual void setAligned(bool aligned);
+ virtual void update();
+
+private:
+ enum {
+ TypeFlat,
+ TypeVertexGradient
+ };
+ QSGGeometryNode *border();
+
+ void updateGeometry();
+ void updateGradientTexture();
+
+ QSGGeometryNode *m_border;
+ QSGFlatColorMaterial m_border_material;
+ QSGFlatColorMaterial m_fill_material;
+
+ QRectF m_rect;
+ QGradientStops m_gradient_stops;
+ qreal m_radius;
+ qreal m_pen_width;
+
+ uint m_aligned : 1;
+ uint m_gradient_is_opaque : 1;
+ uint m_dirty_geometry : 1;
+
+ uint m_material_type : 2; // Only goes up to 3
+
+ QSGGeometry m_default_geometry;
+
+ QSGContext *m_context;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/declarative/scenegraph/qsgdistancefieldglyphcache.cpp b/src/declarative/scenegraph/qsgdistancefieldglyphcache.cpp
new file mode 100644
index 0000000000..50c946a849
--- /dev/null
+++ b/src/declarative/scenegraph/qsgdistancefieldglyphcache.cpp
@@ -0,0 +1,952 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgdistancefieldglyphcache_p.h"
+
+#include <qmath.h>
+#include <private/qtriangulator_p.h>
+#include <private/qdeclarativeglobal_p.h>
+#include <qglshaderprogram.h>
+#include <private/qglengineshadersource_p.h>
+#include <private/qsgcontext_p.h>
+#include <private/qrawfont_p.h>
+#include <qglfunctions.h>
+#include <qglyphrun.h>
+#include <qrawfont.h>
+
+QT_BEGIN_NAMESPACE
+
+#define QT_DISTANCEFIELD_DEFAULT_BASEFONTSIZE 54
+#define QT_DISTANCEFIELD_DEFAULT_TILESIZE 64
+#define QT_DISTANCEFIELD_DEFAULT_SCALE 16
+#define QT_DISTANCEFIELD_DEFAULT_RADIUS 80
+#define QT_DISTANCEFIELD_HIGHGLYPHCOUNT 2000
+
+#define QT_DISTANCEFIELD_BASEFONTSIZE \
+ (m_textureData->doubleGlyphResolution ? QT_DISTANCEFIELD_DEFAULT_BASEFONTSIZE * 2 : \
+ QT_DISTANCEFIELD_DEFAULT_BASEFONTSIZE)
+#define QT_DISTANCEFIELD_TILESIZE \
+ (m_textureData->doubleGlyphResolution ? QT_DISTANCEFIELD_DEFAULT_TILESIZE * 2 : \
+ QT_DISTANCEFIELD_DEFAULT_TILESIZE)
+#define QT_DISTANCEFIELD_SCALE \
+ (m_textureData->doubleGlyphResolution ? QT_DISTANCEFIELD_DEFAULT_SCALE / 2 : \
+ QT_DISTANCEFIELD_DEFAULT_SCALE)
+#define QT_DISTANCEFIELD_RADIUS \
+ (m_textureData->doubleGlyphResolution ? QT_DISTANCEFIELD_DEFAULT_RADIUS / 2 : \
+ QT_DISTANCEFIELD_DEFAULT_RADIUS)
+
+static inline int qt_next_power_of_two(int v)
+{
+ v--;
+ v |= v >> 1;
+ v |= v >> 2;
+ v |= v >> 4;
+ v |= v >> 8;
+ v |= v >> 16;
+ ++v;
+ return v;
+}
+
+struct DFPoint
+{
+ float x, y;
+};
+
+struct DFVertex
+{
+ DFPoint p;
+ float d;
+};
+
+static void drawRectangle(float *bits, int width, int height, const DFVertex *v1, const DFVertex *v2, const DFVertex *v3, const DFVertex *v4)
+{
+ float minY = qMin(qMin(v1->p.y, v2->p.y), qMin(v3->p.y, v4->p.y));
+ if (v2->p.y == minY) {
+ const DFVertex *tmp = v1;
+ v1 = v2;
+ v2 = v3;
+ v3 = v4;
+ v4 = tmp;
+ } else if (v3->p.y == minY) {
+ const DFVertex *tmp1 = v1;
+ const DFVertex *tmp2 = v2;
+ v1 = v3;
+ v2 = v4;
+ v3 = tmp1;
+ v4 = tmp2;
+ } else if (v4->p.y == minY) {
+ const DFVertex *tmp = v4;
+ v4 = v3;
+ v3 = v2;
+ v2 = v1;
+ v1 = tmp;
+ }
+
+ /*
+ v1
+ / \
+ v4 v2
+ \ /
+ v3
+ */
+
+ int fromY = qMax(0, qCeil(v1->p.y));
+ int midY1 = qMin(height, qCeil(qMin(v2->p.y, v4->p.y)));
+ int midY2 = qMin(height, qCeil(qMax(v2->p.y, v4->p.y)));
+ int toY = qMin(height, qCeil(v3->p.y));
+
+ if (toY <= fromY)
+ return;
+
+ bits += width * fromY;
+ int y = fromY;
+
+ float leftDx = (v4->p.x - v1->p.x) / (v4->p.y - v1->p.y);
+ float leftDd = (v4->d - v1->d) / (v4->p.y - v1->p.y);
+ float leftX = v1->p.x + (fromY - v1->p.y) * leftDx;
+ float leftD = v1->d + (fromY - v1->p.y) * leftDd;
+
+ float rightDx = (v2->p.x - v1->p.x) / (v2->p.y - v1->p.y);
+ float rightDd = (v2->d - v1->d) / (v2->p.y - v1->p.y);
+ float rightX = v1->p.x + (fromY - v1->p.y) * rightDx;
+ float rightD = v1->d + (fromY - v1->p.y) * rightDd;
+
+ float dd = ((v2->d - v1->d) * (v3->p.y - v1->p.y) - (v2->p.y - v1->p.y) * (v3->d - v1->d))
+ / ((v2->p.x - v1->p.x) * (v3->p.y - v1->p.y) - (v2->p.y - v1->p.y) * (v3->p.x - v1->p.x));
+
+ for (; y < midY1; ++y, leftX += leftDx, leftD += leftDd, rightX += rightDx, rightD += rightDd, bits += width) {
+ int fromX = qMax(0, qCeil(leftX));
+ int toX = qMin(width, qCeil(rightX));
+ if (toX <= fromX)
+ continue;
+ float d = leftD + (fromX - leftX) * dd;
+ for (int x = fromX; x < toX; ++x, d += dd) {
+ if (abs(d) < abs(bits[x]))
+ bits[x] = d;
+ }
+ }
+
+ if (midY1 == toY)
+ return;
+
+ if (v2->p.y > v4->p.y) {
+ // Long right edge.
+ leftDx = (v3->p.x - v4->p.x) / (v3->p.y - v4->p.y);
+ leftDd = (v3->d - v4->d) / (v3->p.y - v4->p.y);
+ leftX = v4->p.x + (midY1 - v4->p.y) * leftDx;
+ leftD = v4->d + (midY1 - v4->p.y) * leftDd;
+ } else {
+ // Long left edge.
+ rightDx = (v3->p.x - v2->p.x) / (v3->p.y - v2->p.y);
+ rightDd = (v3->d - v2->d) / (v3->p.y - v2->p.y);
+ rightX = v2->p.x + (midY1 - v2->p.y) * rightDx;
+ rightD = v2->d + (midY1 - v2->p.y) * rightDd;
+ }
+
+ for (; y < midY2; ++y, leftX += leftDx, leftD += leftDd, rightX += rightDx, rightD += rightDd, bits += width) {
+ int fromX = qMax(0, qCeil(leftX));
+ int toX = qMin(width, qCeil(rightX));
+ if (toX <= fromX)
+ continue;
+ float d = leftD + (fromX - leftX) * dd;
+ for (int x = fromX; x < toX; ++x, d += dd) {
+ if (abs(d) < abs(bits[x]))
+ bits[x] = d;
+ }
+ }
+
+ if (midY2 == toY)
+ return;
+
+ if (v2->p.y > v4->p.y) {
+ // Long left edge.
+ rightDx = (v3->p.x - v2->p.x) / (v3->p.y - v2->p.y);
+ rightDd = (v3->d - v2->d) / (v3->p.y - v2->p.y);
+ rightX = v2->p.x + (midY2 - v2->p.y) * rightDx;
+ rightD = v2->d + (midY2 - v2->p.y) * rightDd;
+ } else {
+ // Long right edge.
+ leftDx = (v3->p.x - v4->p.x) / (v3->p.y - v4->p.y);
+ leftDd = (v3->d - v4->d) / (v3->p.y - v4->p.y);
+ leftX = v4->p.x + (midY2 - v4->p.y) * leftDx;
+ leftD = v4->d + (midY2 - v4->p.y) * leftDd;
+ }
+
+ for (; y < toY; ++y, leftX += leftDx, leftD += leftDd, rightX += rightDx, rightD += rightDd, bits += width) {
+ int fromX = qMax(0, qCeil(leftX));
+ int toX = qMin(width, qCeil(rightX));
+ if (toX <= fromX)
+ continue;
+ float d = leftD + (fromX - leftX) * dd;
+ for (int x = fromX; x < toX; ++x, d += dd) {
+ if (abs(d) < abs(bits[x]))
+ bits[x] = d;
+ }
+ }
+}
+
+static void drawTriangle(float *bits, int width, int height, const DFVertex *v1, const DFVertex *v2, const DFVertex *v3)
+{
+ float minY = qMin(qMin(v1->p.y, v2->p.y), v3->p.y);
+ if (v2->p.y == minY) {
+ const DFVertex *tmp = v1;
+ v1 = v2;
+ v2 = v3;
+ v3 = tmp;
+ } else if (v3->p.y == minY) {
+ const DFVertex *tmp = v3;
+ v3 = v2;
+ v2 = v1;
+ v1 = tmp;
+ }
+
+ /*
+ v1
+ / \
+ v3--v2
+ */
+
+ int fromY = qMax(0, qCeil(v1->p.y));
+ int midY = qMin(height, qCeil(qMin(v2->p.y, v3->p.y)));
+ int toY = qMin(height, qCeil(qMax(v2->p.y, v3->p.y)));
+
+ if (toY <= fromY)
+ return;
+
+ float leftDx = (v3->p.x - v1->p.x) / (v3->p.y - v1->p.y);
+ float leftDd = (v3->d - v1->d) / (v3->p.y - v1->p.y);
+ float leftX = v1->p.x + (fromY - v1->p.y) * leftDx;
+ float leftD = v1->d + (fromY - v1->p.y) * leftDd;
+
+ float rightDx = (v2->p.x - v1->p.x) / (v2->p.y - v1->p.y);
+ float rightDd = (v2->d - v1->d) / (v2->p.y - v1->p.y);
+ float rightX = v1->p.x + (fromY - v1->p.y) * rightDx;
+ float rightD = v1->d + (fromY - v1->p.y) * rightDd;
+
+ float dd = ((v2->d - v1->d) * (v3->p.y - v1->p.y) - (v2->p.y - v1->p.y) * (v3->d - v1->d))
+ / ((v2->p.x - v1->p.x) * (v3->p.y - v1->p.y) - (v2->p.y - v1->p.y) * (v3->p.x - v1->p.x));
+
+ bits += width * fromY;
+ int y = fromY;
+ for (; y < midY; ++y, leftX += leftDx, leftD += leftDd, rightX += rightDx, rightD += rightDd, bits += width) {
+ int fromX = qMax(0, qCeil(leftX));
+ int toX = qMin(width, qCeil(rightX));
+ if (toX <= fromX)
+ continue;
+ float d = leftD + (fromX - leftX) * dd;
+ for (int x = fromX; x < toX; ++x, d += dd) {
+ if (abs(d) < abs(bits[x]))
+ bits[x] = d;
+ }
+ }
+
+ if (midY == toY)
+ return;
+
+ if (v2->p.y > v3->p.y) {
+ // Long right edge.
+ leftDx = (v2->p.x - v3->p.x) / (v2->p.y - v3->p.y);
+ leftDd = (v2->d - v3->d) / (v2->p.y - v3->p.y);
+ leftX = v3->p.x + (midY - v3->p.y) * leftDx;
+ leftD = v3->d + (midY - v3->p.y) * leftDd;
+ } else {
+ // Long left edge.
+ rightDx = (v3->p.x - v2->p.x) / (v3->p.y - v2->p.y);
+ rightDd = (v3->d - v2->d) / (v3->p.y - v2->p.y);
+ rightX = v2->p.x + (midY - v2->p.y) * rightDx;
+ rightD = v2->d + (midY - v2->p.y) * rightDd;
+ }
+
+ for (; y < toY; ++y, leftX += leftDx, leftD += leftDd, rightX += rightDx, rightD += rightDd, bits += width) {
+ int fromX = qMax(0, qCeil(leftX));
+ int toX = qMin(width, qCeil(rightX));
+ if (toX <= fromX)
+ continue;
+ float d = leftD + (fromX - leftX) * dd;
+ for (int x = fromX; x < toX; ++x, d += dd) {
+ if (abs(d) < abs(bits[x]))
+ bits[x] = d;
+ }
+ }
+}
+
+static QImage makeDistanceField(int imgSize, const QPainterPath &path, int dfScale, float offs)
+{
+ QImage image(imgSize, imgSize, QImage::Format_ARGB32_Premultiplied);
+
+ if (path.isEmpty()) {
+ image.fill(0);
+ return image;
+ }
+
+ QPolylineSet polys = qPolyline(path);
+
+ union Pacific {
+ float value;
+ QRgb color;
+ };
+ Pacific interior;
+ Pacific exterior;
+ interior.value = 127;
+ exterior.value = -127;
+
+ image.fill(exterior.color);
+
+ QPainter p(&image);
+ p.setCompositionMode(QPainter::CompositionMode_Source);
+ p.translate(offs, offs);
+ p.scale(1 / qreal(dfScale), 1 / qreal(dfScale));
+ p.fillPath(path, QColor::fromRgba(interior.color));
+ p.end();
+
+ float *bits = (float *)image.bits();
+ const float angleStep = 15 * 3.141592653589793238f / 180;
+ const DFPoint rotation = { cos(angleStep), sin(angleStep) };
+
+ bool isShortData = polys.indices.type() == QVertexIndexVector::UnsignedShort;
+ const void *indices = polys.indices.data();
+ int index = 0;
+ QVector<DFPoint> normals;
+ QVector<DFVertex> vertices;
+ normals.reserve(polys.vertices.count());
+ vertices.reserve(polys.vertices.count());
+
+ while (index < polys.indices.size()) {
+ normals.clear();
+ vertices.clear();
+
+ // Find end of polygon.
+ int end = index;
+ if (isShortData) {
+ while (((quint16 *)indices)[end] != quint16(-1))
+ ++end;
+ } else {
+ while (((quint32 *)indices)[end] != quint32(-1))
+ ++end;
+ }
+
+ // Calculate vertex normals.
+ for (int next = index, prev = end - 1; next < end; prev = next++) {
+ quint32 fromVertexIndex = isShortData ? (quint32)((quint16 *)indices)[prev] : ((quint32 *)indices)[prev];
+ quint32 toVertexIndex = isShortData ? (quint32)((quint16 *)indices)[next] : ((quint32 *)indices)[next];
+ const qreal *from = &polys.vertices.at(fromVertexIndex * 2);
+ const qreal *to = &polys.vertices.at(toVertexIndex * 2);
+ DFPoint n;
+ n.x = float(to[1] - from[1]);
+ n.y = float(from[0] - to[0]);
+ if (n.x == 0 && n.y == 0)
+ continue;
+ float scale = offs / sqrt(n.x * n.x + n.y * n.y);
+ n.x *= scale;
+ n.y *= scale;
+ normals.append(n);
+
+ DFVertex v;
+ v.p.x = float(to[0] / dfScale) + offs - 0.5f;
+ v.p.y = float(to[1] / dfScale) + offs - 0.5f;
+ v.d = 0.0f;
+ vertices.append(v);
+ }
+
+ QVector<bool> isConvex(normals.count());
+ for (int next = 0, prev = normals.count() - 1; next < normals.count(); prev = next++)
+ isConvex[prev] = (normals.at(prev).x * normals.at(next).y - normals.at(prev).y * normals.at(next).x > 0);
+
+ // Draw quads.
+ for (int next = 0, prev = normals.count() - 1; next < normals.count(); prev = next++) {
+ DFPoint n = normals.at(next);
+ DFVertex intPrev = vertices.at(prev);
+ DFVertex extPrev = vertices.at(prev);
+ DFVertex intNext = vertices.at(next);
+ DFVertex extNext = vertices.at(next);
+
+ extPrev.p.x += n.x;
+ extPrev.p.y += n.y;
+ intPrev.p.x -= n.x;
+ intPrev.p.y -= n.y;
+ extNext.p.x += n.x;
+ extNext.p.y += n.y;
+ intNext.p.x -= n.x;
+ intNext.p.y -= n.y;
+ extPrev.d = 127;
+ extNext.d = 127;
+ intPrev.d = -127;
+ intNext.d = -127;
+
+ drawRectangle(bits, image.width(), image.height(),
+ &vertices.at(prev), &extPrev, &extNext, &vertices.at(next));
+
+ drawRectangle(bits, image.width(), image.height(),
+ &intPrev, &vertices.at(prev), &vertices.at(next), &intNext);
+
+ if (isConvex.at(prev)) {
+ DFVertex v = extPrev;
+ for (;;) {
+ DFPoint rn = { n.x * rotation.x + n.y * rotation.y,
+ n.y * rotation.x - n.x * rotation.y };
+ n = rn;
+ if (n.x * normals.at(prev).y - n.y * normals.at(prev).x >= -0.001) {
+ v.p.x = vertices.at(prev).p.x + normals.at(prev).x;
+ v.p.y = vertices.at(prev).p.y + normals.at(prev).y;
+ drawTriangle(bits, image.width(), image.height(), &vertices.at(prev), &v, &extPrev);
+ break;
+ }
+
+ v.p.x = vertices.at(prev).p.x + n.x;
+ v.p.y = vertices.at(prev).p.y + n.y;
+ drawTriangle(bits, image.width(), image.height(), &vertices.at(prev), &v, &extPrev);
+ extPrev = v;
+ }
+ } else {
+ DFVertex v = intPrev;
+ for (;;) {
+ DFPoint rn = { n.x * rotation.x - n.y * rotation.y,
+ n.y * rotation.x + n.x * rotation.y };
+ n = rn;
+ if (n.x * normals.at(prev).y - n.y * normals.at(prev).x <= 0.001) {
+ v.p.x = vertices.at(prev).p.x - normals.at(prev).x;
+ v.p.y = vertices.at(prev).p.y - normals.at(prev).y;
+ drawTriangle(bits, image.width(), image.height(), &vertices.at(prev), &intPrev, &v);
+ break;
+ }
+
+ v.p.x = vertices.at(prev).p.x - n.x;
+ v.p.y = vertices.at(prev).p.y - n.y;
+ drawTriangle(bits, image.width(), image.height(), &vertices.at(prev), &intPrev, &v);
+ intPrev = v;
+ }
+ }
+ }
+ index = end + 1;
+ }
+
+ for (int y = 0; y < image.height(); ++y) {
+ QRgb *iLine = (QRgb *)image.scanLine(y);
+ float *fLine = (float *)iLine;
+ for (int x = 0; x < image.width(); ++x)
+ iLine[x] = QRgb(fLine[x] + 127.5) << 24;
+ }
+
+ return image;
+}
+
+static void convert_to_Format_Alpha(QImage *image)
+{
+ const int width = image->width();
+ const int height = image->height();
+ uchar *data = image->bits();
+
+ for (int i = 0; i < height; ++i) {
+ uchar *o = data + i * width;
+ for (int x = 0; x < width; ++x)
+ o[x] = (uchar)qAlpha(image->pixel(x, i));
+ }
+}
+
+static bool fontHasNarrowOutlines(const QRawFont &f)
+{
+ QRawFont font = f;
+ font.setPixelSize(QT_DISTANCEFIELD_DEFAULT_BASEFONTSIZE);
+ Q_ASSERT(font.isValid());
+
+ QVector<quint32> glyphIndices = font.glyphIndexesForString(QLatin1String("O"));
+ if (glyphIndices.size() < 1)
+ return false;
+
+ QImage im = font.alphaMapForGlyph(glyphIndices.at(0), QRawFont::PixelAntialiasing);
+ if (im.isNull())
+ return false;
+
+ int minHThick = 999;
+ int minVThick = 999;
+
+ int thick = 0;
+ bool in = false;
+ int y = (im.height() + 1) / 2;
+ for (int x = 0; x < im.width(); ++x) {
+ int a = qAlpha(im.pixel(x, y));
+ if (a > 127) {
+ in = true;
+ ++thick;
+ } else if (in) {
+ in = false;
+ minHThick = qMin(minHThick, thick);
+ thick = 0;
+ }
+ }
+
+ thick = 0;
+ in = false;
+ int x = (im.width() + 1) / 2;
+ for (int y = 0; y < im.height(); ++y) {
+ int a = qAlpha(im.pixel(x, y));
+ if (a > 127) {
+ in = true;
+ ++thick;
+ } else if (in) {
+ in = false;
+ minVThick = qMin(minVThick, thick);
+ thick = 0;
+ }
+ }
+
+ return minHThick == 1 || minVThick == 1;
+}
+
+DEFINE_BOOL_CONFIG_OPTION(disableDistanceField, QML_DISABLE_DISTANCEFIELD)
+
+QHash<QPair<const QGLContext *, QFontEngine *>, QSGDistanceFieldGlyphCache *> QSGDistanceFieldGlyphCache::m_caches;
+QHash<QFontEngine *, QGLContextGroupResource<QSGDistanceFieldGlyphCache::DistanceFieldTextureData> > QSGDistanceFieldGlyphCache::m_textures_data;
+
+QSGDistanceFieldGlyphCache *QSGDistanceFieldGlyphCache::get(const QGLContext *ctx, const QRawFont &font)
+{
+ QRawFontPrivate *fontD = QRawFontPrivate::get(font);
+ QPair<const QGLContext *, QFontEngine *> key(ctx, fontD->fontEngine);
+ QHash<QPair<const QGLContext *, QFontEngine *>, QSGDistanceFieldGlyphCache *>::iterator atlas = m_caches.find(key);
+ if (atlas == m_caches.end())
+ atlas = m_caches.insert(key, new QSGDistanceFieldGlyphCache(ctx, font));
+
+ return atlas.value();
+}
+
+QSGDistanceFieldGlyphCache::DistanceFieldTextureData *QSGDistanceFieldGlyphCache::textureData()
+{
+ return m_textures_data[QRawFontPrivate::get(m_font)->fontEngine].value(ctx);
+}
+
+QSGDistanceFieldGlyphCache::QSGDistanceFieldGlyphCache(const QGLContext *c, const QRawFont &font)
+ : QObject()
+ , m_maxTextureSize(0)
+ , ctx(c)
+ , m_blitProgram(0)
+{
+ Q_ASSERT(font.isValid());
+ m_font = font;
+
+ m_textureData = textureData();
+
+ QRawFontPrivate *fontD = QRawFontPrivate::get(m_font);
+ m_glyphCount = fontD->fontEngine->glyphCount();
+
+ m_textureData->doubleGlyphResolution = fontHasNarrowOutlines(font) && m_glyphCount < QT_DISTANCEFIELD_HIGHGLYPHCOUNT;
+
+ m_referenceFont = m_font;
+ m_referenceFont.setPixelSize(QT_DISTANCEFIELD_BASEFONTSIZE);
+ Q_ASSERT(m_referenceFont.isValid());
+
+ m_vertexCoordinateArray[0] = -1.0f;
+ m_vertexCoordinateArray[1] = -1.0f;
+ m_vertexCoordinateArray[2] = 1.0f;
+ m_vertexCoordinateArray[3] = -1.0f;
+ m_vertexCoordinateArray[4] = 1.0f;
+ m_vertexCoordinateArray[5] = 1.0f;
+ m_vertexCoordinateArray[6] = -1.0f;
+ m_vertexCoordinateArray[7] = 1.0f;
+
+ m_textureCoordinateArray[0] = 0.0f;
+ m_textureCoordinateArray[1] = 0.0f;
+ m_textureCoordinateArray[2] = 1.0f;
+ m_textureCoordinateArray[3] = 0.0f;
+ m_textureCoordinateArray[4] = 1.0f;
+ m_textureCoordinateArray[5] = 1.0f;
+ m_textureCoordinateArray[6] = 0.0f;
+ m_textureCoordinateArray[7] = 1.0f;
+
+ connect(QGLSignalProxy::instance(), SIGNAL(aboutToDestroyContext(const QGLContext*)),
+ this, SLOT(onContextDestroyed(const QGLContext*)));
+}
+
+QSGDistanceFieldGlyphCache::~QSGDistanceFieldGlyphCache()
+{
+ delete m_blitProgram;
+}
+
+void QSGDistanceFieldGlyphCache::onContextDestroyed(const QGLContext *context)
+{
+ if (context != ctx)
+ return;
+
+ QRawFontPrivate *fontD = QRawFontPrivate::get(m_font);
+ QPair<const QGLContext *, QFontEngine *> key(context, fontD->fontEngine);
+ m_caches.remove(key);
+ deleteLater();
+}
+
+GLuint QSGDistanceFieldGlyphCache::texture()
+{
+ return m_textureData->texture;
+}
+
+QSize QSGDistanceFieldGlyphCache::textureSize() const
+{
+ return m_textureData->size;
+}
+
+int QSGDistanceFieldGlyphCache::maxTextureSize() const
+{
+ if (!m_maxTextureSize)
+ glGetIntegerv(GL_MAX_TEXTURE_SIZE, &m_maxTextureSize);
+ return m_maxTextureSize;
+}
+
+QSGDistanceFieldGlyphCache::Metrics QSGDistanceFieldGlyphCache::glyphMetrics(glyph_t glyph)
+{
+ QHash<glyph_t, Metrics>::iterator metric = m_metrics.find(glyph);
+ if (metric == m_metrics.end()) {
+ QPainterPath path = m_font.pathForGlyph(glyph);
+ QRectF br = path.boundingRect();
+
+ Metrics m;
+ m.width = br.width();
+ m.height = br.height();
+ m.baselineX = br.x();
+ m.baselineY = -br.y();
+
+ metric = m_metrics.insert(glyph, m);
+ }
+
+ return metric.value();
+}
+
+QSGDistanceFieldGlyphCache::TexCoord QSGDistanceFieldGlyphCache::glyphTexCoord(glyph_t glyph)
+{
+ return m_textureData->texCoords.value(glyph);
+}
+
+QImage QSGDistanceFieldGlyphCache::renderDistanceFieldGlyph(glyph_t glyph) const
+{
+ QRawFont renderFont = m_font;
+ renderFont.setPixelSize(QT_DISTANCEFIELD_BASEFONTSIZE * QT_DISTANCEFIELD_SCALE);
+
+ QPainterPath path = renderFont.pathForGlyph(glyph);
+ path.translate(-path.boundingRect().topLeft());
+ path.setFillRule(Qt::WindingFill);
+
+ QImage im = makeDistanceField(QT_DISTANCEFIELD_TILESIZE,
+ path,
+ QT_DISTANCEFIELD_SCALE,
+ QT_DISTANCEFIELD_RADIUS / qreal(QT_DISTANCEFIELD_SCALE));
+ return im;
+}
+
+qreal QSGDistanceFieldGlyphCache::fontScale() const
+{
+ return qreal(m_font.pixelSize()) / QT_DISTANCEFIELD_BASEFONTSIZE;
+}
+
+int QSGDistanceFieldGlyphCache::distanceFieldRadius() const
+{
+ return QT_DISTANCEFIELD_DEFAULT_RADIUS / QT_DISTANCEFIELD_SCALE;
+}
+
+void QSGDistanceFieldGlyphCache::populate(int count, const glyph_t *glyphs)
+{
+ // Avoid useless and costly glyph re-generation
+ if (cacheIsFull() && !m_textureData->unusedGlyphs.isEmpty()) {
+ for (int i = 0; i < count; ++i) {
+ glyph_t glyphIndex = glyphs[i];
+ if (m_textureData->texCoords.contains(glyphIndex) && m_textureData->unusedGlyphs.contains(glyphIndex))
+ m_textureData->unusedGlyphs.remove(glyphIndex);
+ }
+ }
+
+ for (int i = 0; i < count; ++i) {
+ glyph_t glyphIndex = glyphs[i];
+ if ((int) glyphIndex >= glyphCount()) {
+ qWarning("Warning: distance-field glyph is not available with index %d", glyphIndex);
+ continue;
+ }
+
+ if (++m_textureData->glyphRefCount[glyphIndex] == 1)
+ m_textureData->unusedGlyphs.remove(glyphIndex);
+
+ if (m_textureData->texCoords.contains(glyphIndex)
+ || (cacheIsFull() && m_textureData->unusedGlyphs.isEmpty()))
+ continue;
+
+ QPainterPath path = m_referenceFont.pathForGlyph(glyphIndex);
+ if (path.isEmpty()) {
+ m_textureData->texCoords.insert(glyphIndex, TexCoord());
+ continue;
+ }
+ QRectF br = path.boundingRect();
+
+ TexCoord c;
+ c.xMargin = QT_DISTANCEFIELD_RADIUS / qreal(QT_DISTANCEFIELD_SCALE);
+ c.yMargin = QT_DISTANCEFIELD_RADIUS / qreal(QT_DISTANCEFIELD_SCALE);
+ c.x = m_textureData->currX;
+ c.y = m_textureData->currY;
+ c.width = br.width();
+ c.height = br.height();
+
+ if (!cacheIsFull()) {
+ m_textureData->currX += QT_DISTANCEFIELD_TILESIZE;
+ if (m_textureData->currX >= maxTextureSize()) {
+ m_textureData->currX = 0;
+ m_textureData->currY += QT_DISTANCEFIELD_TILESIZE;
+ }
+ } else {
+ // Recycle glyphs
+ if (!m_textureData->unusedGlyphs.isEmpty()) {
+ glyph_t unusedGlyph = *m_textureData->unusedGlyphs.constBegin();
+ TexCoord unusedCoord = glyphTexCoord(unusedGlyph);
+ c.x = unusedCoord.x;
+ c.y = unusedCoord.y;
+ m_textureData->unusedGlyphs.remove(unusedGlyph);
+ m_textureData->texCoords.remove(unusedGlyph);
+ }
+ }
+
+ if (c.y < maxTextureSize()) {
+ m_textureData->texCoords.insert(glyphIndex, c);
+ m_textureData->pendingGlyphs.add(glyphIndex);
+ }
+ }
+}
+
+void QSGDistanceFieldGlyphCache::derefGlyphs(int count, const glyph_t *glyphs)
+{
+ for (int i = 0; i < count; ++i)
+ if (--m_textureData->glyphRefCount[glyphs[i]] == 0 && !glyphTexCoord(glyphs[i]).isNull())
+ m_textureData->unusedGlyphs.insert(glyphs[i]);
+}
+
+void QSGDistanceFieldGlyphCache::createTexture(int width, int height)
+{
+ if (ctx->d_ptr->workaround_brokenFBOReadBack && m_textureData->image.isNull())
+ m_textureData->image = QImage(width, height, QImage::Format_ARGB32_Premultiplied);
+
+ while (glGetError() != GL_NO_ERROR) { }
+
+ glGenTextures(1, &m_textureData->texture);
+ glBindTexture(GL_TEXTURE_2D, m_textureData->texture);
+
+ QVarLengthArray<uchar> data(width * height);
+ for (int i = 0; i < data.size(); ++i)
+ data[i] = 0;
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, width, height, 0, GL_ALPHA, GL_UNSIGNED_BYTE, &data[0]);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+ m_textureData->size = QSize(width, height);
+
+ GLuint error = glGetError();
+ if (error != GL_NO_ERROR) {
+ glBindTexture(GL_TEXTURE_2D, 0);
+ glDeleteTextures(1, &m_textureData->texture);
+ m_textureData->texture = 0;
+ }
+
+}
+
+void QSGDistanceFieldGlyphCache::resizeTexture(int width, int height)
+{
+ int oldWidth = m_textureData->size.width();
+ int oldHeight = m_textureData->size.height();
+ if (width == oldWidth && height == oldHeight)
+ return;
+
+ GLuint oldTexture = m_textureData->texture;
+ createTexture(width, height);
+
+ if (!oldTexture)
+ return;
+
+ if (ctx->d_ptr->workaround_brokenFBOReadBack) {
+ m_textureData->image = m_textureData->image.copy(0, 0, width, height);
+ QImage copy = m_textureData->image.copy(0, 0, oldWidth, oldHeight);
+ convert_to_Format_Alpha(&copy);
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, oldWidth, oldHeight, GL_ALPHA, GL_UNSIGNED_BYTE, copy.constBits());
+ glDeleteTextures(1, &oldTexture);
+ return;
+ }
+
+ if (!m_textureData->fbo)
+ ctx->functions()->glGenFramebuffers(1, &m_textureData->fbo);
+ ctx->functions()->glBindFramebuffer(GL_FRAMEBUFFER_EXT, m_textureData->fbo);
+
+ GLuint tmp_texture;
+ glGenTextures(1, &tmp_texture);
+ glBindTexture(GL_TEXTURE_2D, tmp_texture);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, oldWidth, oldHeight, 0,
+ GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ glBindTexture(GL_TEXTURE_2D, 0);
+ ctx->functions()->glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
+ GL_TEXTURE_2D, tmp_texture, 0);
+
+ ctx->functions()->glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, oldTexture);
+
+ // save current render states
+ GLboolean stencilTestEnabled;
+ GLboolean depthTestEnabled;
+ GLboolean scissorTestEnabled;
+ GLboolean blendEnabled;
+ GLint viewport[4];
+ glGetBooleanv(GL_STENCIL_TEST, &stencilTestEnabled);
+ glGetBooleanv(GL_DEPTH_TEST, &depthTestEnabled);
+ glGetBooleanv(GL_SCISSOR_TEST, &scissorTestEnabled);
+ glGetBooleanv(GL_BLEND, &blendEnabled);
+ glGetIntegerv(GL_VIEWPORT, &viewport[0]);
+
+ glDisable(GL_STENCIL_TEST);
+ glDisable(GL_DEPTH_TEST);
+ glDisable(GL_SCISSOR_TEST);
+ glDisable(GL_BLEND);
+
+ glViewport(0, 0, oldWidth, oldHeight);
+
+ if (m_blitProgram == 0) {
+ m_blitProgram = new QGLShaderProgram;
+
+ {
+ QString source;
+ source.append(QLatin1String(qglslMainWithTexCoordsVertexShader));
+ source.append(QLatin1String(qglslUntransformedPositionVertexShader));
+
+ QGLShader *vertexShader = new QGLShader(QGLShader::Vertex, m_blitProgram);
+ vertexShader->compileSourceCode(source);
+
+ m_blitProgram->addShader(vertexShader);
+ }
+
+ {
+ QString source;
+ source.append(QLatin1String(qglslMainFragmentShader));
+ source.append(QLatin1String(qglslImageSrcFragmentShader));
+
+ QGLShader *fragmentShader = new QGLShader(QGLShader::Fragment, m_blitProgram);
+ fragmentShader->compileSourceCode(source);
+
+ m_blitProgram->addShader(fragmentShader);
+ }
+
+ m_blitProgram->bindAttributeLocation("vertexCoordsArray", QT_VERTEX_COORDS_ATTR);
+ m_blitProgram->bindAttributeLocation("textureCoordArray", QT_TEXTURE_COORDS_ATTR);
+
+ m_blitProgram->link();
+ }
+
+ ctx->functions()->glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, m_vertexCoordinateArray);
+ ctx->functions()->glVertexAttribPointer(QT_TEXTURE_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, m_textureCoordinateArray);
+
+ m_blitProgram->bind();
+ m_blitProgram->enableAttributeArray(int(QT_VERTEX_COORDS_ATTR));
+ m_blitProgram->enableAttributeArray(int(QT_TEXTURE_COORDS_ATTR));
+ m_blitProgram->disableAttributeArray(int(QT_OPACITY_ATTR));
+ m_blitProgram->setUniformValue("imageTexture", GLuint(0));
+
+ glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+
+ glBindTexture(GL_TEXTURE_2D, m_textureData->texture);
+
+ glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, oldWidth, oldHeight);
+
+ ctx->functions()->glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
+ GL_RENDERBUFFER_EXT, 0);
+ glDeleteTextures(1, &tmp_texture);
+ glDeleteTextures(1, &oldTexture);
+
+ ctx->functions()->glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
+
+ // restore render states
+ if (stencilTestEnabled)
+ glEnable(GL_STENCIL_TEST);
+ if (depthTestEnabled)
+ glEnable(GL_DEPTH_TEST);
+ if (scissorTestEnabled)
+ glEnable(GL_SCISSOR_TEST);
+ if (blendEnabled)
+ glEnable(GL_BLEND);
+ glViewport(viewport[0], viewport[1], viewport[2], viewport[3]);
+}
+
+void QSGDistanceFieldGlyphCache::updateCache()
+{
+ if (m_textureData->pendingGlyphs.isEmpty())
+ return;
+
+ int requiredWidth = m_textureData->currY == 0 ? m_textureData->currX : maxTextureSize();
+ int requiredHeight = qMin(maxTextureSize(), m_textureData->currY + QT_DISTANCEFIELD_TILESIZE);
+
+ resizeTexture((requiredWidth), (requiredHeight));
+ glBindTexture(GL_TEXTURE_2D, m_textureData->texture);
+
+ for (int i = 0; i < m_textureData->pendingGlyphs.size(); ++i) {
+ glyph_t glyphIndex = m_textureData->pendingGlyphs.at(i);
+ QImage glyph = renderDistanceFieldGlyph(glyphIndex);
+ TexCoord c = m_textureData->texCoords.value(glyphIndex);
+
+ if (ctx->d_ptr->workaround_brokenFBOReadBack) {
+ QPainter p(&m_textureData->image);
+ p.setCompositionMode(QPainter::CompositionMode_Source);
+ p.drawImage(c.x, c.y, glyph);
+ p.end();
+ }
+
+ convert_to_Format_Alpha(&glyph);
+ glTexSubImage2D(GL_TEXTURE_2D, 0, c.x, c.y, glyph.width(), glyph.height(), GL_ALPHA, GL_UNSIGNED_BYTE, glyph.constBits());
+ }
+ m_textureData->pendingGlyphs.reset();
+}
+
+bool QSGDistanceFieldGlyphCache::useWorkaroundBrokenFBOReadback() const
+{
+ return ctx->d_ptr->workaround_brokenFBOReadBack;
+}
+
+bool QSGDistanceFieldGlyphCache::distanceFieldEnabled()
+{
+ return !disableDistanceField();
+}
+
+int QSGDistanceFieldGlyphCache::glyphCount() const
+{
+ return m_glyphCount;
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/scenegraph/qsgdistancefieldglyphcache_p.h b/src/declarative/scenegraph/qsgdistancefieldglyphcache_p.h
new file mode 100644
index 0000000000..f7e2d9367e
--- /dev/null
+++ b/src/declarative/scenegraph/qsgdistancefieldglyphcache_p.h
@@ -0,0 +1,160 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef DISTANCEFIELDGLYPHCACHE_H
+#define DISTANCEFIELDGLYPHCACHE_H
+
+#include <qgl.h>
+#include <qrawfont.h>
+#include <private/qgl_p.h>
+#include <private/qfont_p.h>
+#include <private/qfontengine_p.h>
+#include <QtGui/private/qdatabuffer_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QGLShaderProgram;
+
+class Q_DECLARATIVE_EXPORT QSGDistanceFieldGlyphCache : public QObject
+{
+ Q_OBJECT
+public:
+ ~QSGDistanceFieldGlyphCache();
+
+ static QSGDistanceFieldGlyphCache *get(const QGLContext *ctx, const QRawFont &font);
+
+ struct Metrics {
+ qreal width;
+ qreal height;
+ qreal baselineX;
+ qreal baselineY;
+
+ bool isNull() const { return width == 0 || height == 0; }
+ };
+ Metrics glyphMetrics(glyph_t glyph);
+
+ struct TexCoord {
+ qreal x;
+ qreal y;
+ qreal width;
+ qreal height;
+ qreal xMargin;
+ qreal yMargin;
+
+ TexCoord() : x(0), y(0), width(0), height(0), xMargin(0), yMargin(0) { }
+
+ bool isNull() const { return width == 0 || height == 0; }
+ };
+ TexCoord glyphTexCoord(glyph_t glyph);
+
+ GLuint texture();
+ QSize textureSize() const;
+ int maxTextureSize() const;
+ qreal fontScale() const;
+ int distanceFieldRadius() const;
+ QImage renderDistanceFieldGlyph(glyph_t glyph) const;
+
+ int glyphCount() const;
+
+ void populate(int count, const glyph_t *glyphs);
+ void derefGlyphs(int count, const glyph_t *glyphs);
+ void updateCache();
+
+ bool cacheIsFull() const { return m_textureData->currY >= maxTextureSize(); }
+
+ bool useWorkaroundBrokenFBOReadback() const;
+
+ static bool distanceFieldEnabled();
+
+private Q_SLOTS:
+ void onContextDestroyed(const QGLContext *context);
+
+private:
+ QSGDistanceFieldGlyphCache(const QGLContext *c, const QRawFont &font);
+
+ void createTexture(int width, int height);
+ void resizeTexture(int width, int height);
+
+ static QHash<QPair<const QGLContext *, QFontEngine *>, QSGDistanceFieldGlyphCache *> m_caches;
+
+ QRawFont m_font;
+ QRawFont m_referenceFont;
+
+ int m_glyphCount;
+ QHash<glyph_t, Metrics> m_metrics;
+ mutable int m_maxTextureSize;
+
+ struct DistanceFieldTextureData {
+ GLuint texture;
+ GLuint fbo;
+ QSize size;
+ QHash<glyph_t, TexCoord> texCoords;
+ QDataBuffer<glyph_t> pendingGlyphs;
+ QHash<glyph_t, quint32> glyphRefCount;
+ QSet<glyph_t> unusedGlyphs;
+ int currX;
+ int currY;
+ QImage image;
+ bool doubleGlyphResolution;
+
+ DistanceFieldTextureData(const QGLContext *)
+ : texture(0)
+ , fbo(0)
+ , pendingGlyphs(64)
+ , currX(0)
+ , currY(0)
+ , doubleGlyphResolution(false)
+ { }
+ };
+ DistanceFieldTextureData *textureData();
+ DistanceFieldTextureData *m_textureData;
+ static QHash<QFontEngine *, QGLContextGroupResource<DistanceFieldTextureData> > m_textures_data;
+
+ const QGLContext *ctx;
+ QGLShaderProgram *m_blitProgram;
+ GLfloat m_vertexCoordinateArray[8];
+ GLfloat m_textureCoordinateArray[8];
+
+};
+
+QT_END_NAMESPACE
+
+#endif // DISTANCEFIELDGLYPHCACHE_H
diff --git a/src/declarative/scenegraph/qsgdistancefieldglyphnode.cpp b/src/declarative/scenegraph/qsgdistancefieldglyphnode.cpp
new file mode 100644
index 0000000000..d826f7f1e7
--- /dev/null
+++ b/src/declarative/scenegraph/qsgdistancefieldglyphnode.cpp
@@ -0,0 +1,223 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgdistancefieldglyphnode_p.h"
+#include "qsgdistancefieldglyphnode_p_p.h"
+#include "qsgdistancefieldglyphcache_p.h"
+#include <private/qsgcontext_p.h>
+
+QT_BEGIN_NAMESPACE
+
+QSGDistanceFieldGlyphNode::QSGDistanceFieldGlyphNode()
+ : m_material(0)
+ , m_glyph_cache(0)
+ , m_geometry(QSGGeometry::defaultAttributes_TexturedPoint2D(), 0)
+ , m_style(QSGText::Normal)
+ , m_antialiasingMode(GrayAntialiasing)
+{
+ m_geometry.setDrawingMode(GL_TRIANGLES);
+ setGeometry(&m_geometry);
+
+#ifndef QT_OPENGL_ES
+ setPreferredAntialiasingMode(QSGGlyphNode::SubPixelAntialiasing);
+#endif
+}
+
+QSGDistanceFieldGlyphNode::~QSGDistanceFieldGlyphNode()
+{
+ delete m_material;
+ if (m_glyph_cache) {
+ const QVector<quint32> &glyphIndexes = m_glyphs.glyphIndexes();
+ m_glyph_cache->derefGlyphs(glyphIndexes.count(), glyphIndexes.constData());
+ }
+}
+
+void QSGDistanceFieldGlyphNode::setColor(const QColor &color)
+{
+ m_color = color;
+ if (m_material != 0) {
+ m_material->setColor(color);
+ setMaterial(m_material); // Indicate the material state has changed
+ }
+}
+
+void QSGDistanceFieldGlyphNode::setPreferredAntialiasingMode(AntialiasingMode mode)
+{
+ if (mode == m_antialiasingMode)
+ return;
+ m_antialiasingMode = mode;
+ updateMaterial();
+}
+
+void QSGDistanceFieldGlyphNode::setGlyphs(const QPointF &position, const QGlyphRun &glyphs)
+{
+ QRawFont font = glyphs.rawFont();
+ m_position = QPointF(position.x(), position.y() - font.ascent());
+ m_glyphs = glyphs;
+
+ updateFont();
+ updateGeometry();
+ updateMaterial();
+
+#ifdef QML_RUNTIME_TESTING
+ description = QLatin1String("glyphs");
+#endif
+}
+
+void QSGDistanceFieldGlyphNode::setStyle(QSGText::TextStyle style)
+{
+ m_style = style;
+}
+
+void QSGDistanceFieldGlyphNode::setStyleColor(const QColor &color)
+{
+ m_styleColor = color;
+}
+
+void QSGDistanceFieldGlyphNode::updateGeometry()
+{
+ Q_ASSERT(m_glyph_cache);
+
+ QSGGeometry *g = geometry();
+ QRectF boundingRect;
+
+ const QVector<quint32> &glyphIndexes = m_glyphs.glyphIndexes();
+
+ m_glyph_cache->populate(glyphIndexes.count(), glyphIndexes.constData());
+
+ Q_ASSERT(g->indexType() == GL_UNSIGNED_SHORT);
+ g->allocate(glyphIndexes.size() * 4, glyphIndexes.size() * 6);
+ QVector4D *vp = (QVector4D *)g->vertexData();
+ ushort *ip = g->indexDataAsUShort();
+
+ QPointF margins(2, 2);
+ QPointF texMargins = margins / m_glyph_cache->fontScale();
+
+ for (int i = 0; i < glyphIndexes.size(); ++i) {
+ quint32 glyphIndex = glyphIndexes.at(i);
+ QSGDistanceFieldGlyphCache::Metrics metrics = m_glyph_cache->glyphMetrics(glyphIndex);
+ QSGDistanceFieldGlyphCache::TexCoord c = m_glyph_cache->glyphTexCoord(glyphIndex);
+
+ if (!metrics.isNull() && !c.isNull()) {
+ metrics.width += margins.x() * 2;
+ metrics.height += margins.y() * 2;
+ metrics.baselineX -= margins.x();
+ metrics.baselineY += margins.y();
+ c.xMargin -= texMargins.x();
+ c.yMargin -= texMargins.y();
+ c.width += texMargins.x() * 2;
+ c.height += texMargins.y() * 2;
+ }
+
+ QPointF glyphPosition = m_glyphs.positions().at(i) + m_position;
+ qreal x = glyphPosition.x() + metrics.baselineX;
+ qreal y = glyphPosition.y() - metrics.baselineY;
+
+ boundingRect |= QRectF(x, y, metrics.width, metrics.height);
+
+ float cx1 = x;
+ float cx2 = x + metrics.width;
+ float cy1 = y;
+ float cy2 = y + metrics.height;
+
+ float tx1 = c.x + c.xMargin;
+ float tx2 = tx1 + c.width;
+ float ty1 = c.y + c.yMargin;
+ float ty2 = ty1 + c.height;
+
+ if (m_baseLine.isNull())
+ m_baseLine = glyphPosition;
+
+ int vi = i & 1 ? (glyphIndexes.size() + 1) / 2 + i / 2 : i / 2;
+ vp[4 * vi + 0] = QVector4D(cx1, cy1, tx1, ty1);
+ vp[4 * vi + 1] = QVector4D(cx2, cy1, tx2, ty1);
+ vp[4 * vi + 2] = QVector4D(cx1, cy2, tx1, ty2);
+ vp[4 * vi + 3] = QVector4D(cx2, cy2, tx2, ty2);
+
+ int o = i * 4;
+ ip[6 * i + 0] = o + 0;
+ ip[6 * i + 1] = o + 2;
+ ip[6 * i + 2] = o + 3;
+ ip[6 * i + 3] = o + 3;
+ ip[6 * i + 4] = o + 1;
+ ip[6 * i + 5] = o + 0;
+ }
+
+ setBoundingRect(boundingRect);
+ markDirty(DirtyGeometry);
+}
+
+void QSGDistanceFieldGlyphNode::updateFont()
+{
+ m_glyph_cache = QSGDistanceFieldGlyphCache::get(QGLContext::currentContext(), m_glyphs.rawFont());
+}
+
+void QSGDistanceFieldGlyphNode::updateMaterial()
+{
+ delete m_material;
+
+ if (m_style == QSGText::Normal) {
+ if (m_antialiasingMode == SubPixelAntialiasing)
+ m_material = new QSGSubPixelDistanceFieldTextMaterial;
+ else
+ m_material = new QSGDistanceFieldTextMaterial;
+ } else {
+ QSGDistanceFieldStyledTextMaterial *material;
+ if (m_style == QSGText::Outline) {
+ material = new QSGDistanceFieldOutlineTextMaterial;
+ } else {
+ QSGDistanceFieldShiftedStyleTextMaterial *sMaterial = new QSGDistanceFieldShiftedStyleTextMaterial;
+ if (m_style == QSGText::Raised)
+ sMaterial->setShift(QPointF(0.0, 1.0));
+ else
+ sMaterial->setShift(QPointF(0.0, -1.0));
+ material = sMaterial;
+ }
+ material->setStyleColor(m_styleColor);
+ m_material = material;
+ }
+
+ m_material->setGlyphCache(m_glyph_cache);
+ m_material->setColor(m_color);
+ setMaterial(m_material);
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/scenegraph/qsgdistancefieldglyphnode_p.cpp b/src/declarative/scenegraph/qsgdistancefieldglyphnode_p.cpp
new file mode 100644
index 0000000000..a54c7640ce
--- /dev/null
+++ b/src/declarative/scenegraph/qsgdistancefieldglyphnode_p.cpp
@@ -0,0 +1,667 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgdistancefieldglyphnode_p_p.h"
+#include "qsgdistancefieldglyphcache_p.h"
+#include <private/qsgtexture_p.h>
+#include <QtOpenGL/qglfunctions.h>
+#include <qmath.h>
+
+QT_BEGIN_NAMESPACE
+
+class QSGDistanceFieldTextMaterialShader : public QSGMaterialShader
+{
+public:
+ QSGDistanceFieldTextMaterialShader();
+
+ virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect);
+ virtual char const *const *attributeNames() const;
+
+protected:
+ virtual void initialize();
+ virtual const char *vertexShader() const;
+ virtual const char *fragmentShader() const;
+
+ virtual void updateAlphaRange();
+
+ qreal m_fontScale;
+ qreal m_matrixScale;
+
+ int m_matrix_id;
+ int m_textureScale_id;
+ int m_alphaMin_id;
+ int m_alphaMax_id;
+ int m_color_id;
+};
+
+const char *QSGDistanceFieldTextMaterialShader::vertexShader() const {
+ return
+ "uniform highp mat4 matrix; \n"
+ "uniform highp vec2 textureScale; \n"
+ "attribute highp vec4 vCoord; \n"
+ "attribute highp vec2 tCoord; \n"
+ "varying highp vec2 sampleCoord; \n"
+ "void main() { \n"
+ " sampleCoord = tCoord * textureScale; \n"
+ " gl_Position = matrix * vCoord; \n"
+ "}";
+}
+
+const char *QSGDistanceFieldTextMaterialShader::fragmentShader() const {
+ return
+ "varying highp vec2 sampleCoord; \n"
+ "uniform sampler2D texture; \n"
+ "uniform lowp vec4 color; \n"
+ "uniform highp float alphaMin; \n"
+ "uniform highp float alphaMax; \n"
+ "void main() { \n"
+ " gl_FragColor = color * smoothstep(alphaMin, \n"
+ " alphaMax, \n"
+ " texture2D(texture, sampleCoord).a); \n"
+ "}";
+}
+
+char const *const *QSGDistanceFieldTextMaterialShader::attributeNames() const {
+ static char const *const attr[] = { "vCoord", "tCoord", 0 };
+ return attr;
+}
+
+QSGDistanceFieldTextMaterialShader::QSGDistanceFieldTextMaterialShader()
+ : m_fontScale(1.0)
+ , m_matrixScale(1.0)
+{
+}
+
+void QSGDistanceFieldTextMaterialShader::updateAlphaRange()
+{
+ qreal combinedScale = m_fontScale * m_matrixScale;
+ qreal alphaMin = qMax(0.0, 0.5 - 0.07 / combinedScale);
+ qreal alphaMax = qMin(0.5 + 0.07 / combinedScale, 1.0);
+ program()->setUniformValue(m_alphaMin_id, GLfloat(alphaMin));
+ program()->setUniformValue(m_alphaMax_id, GLfloat(alphaMax));
+}
+
+void QSGDistanceFieldTextMaterialShader::initialize()
+{
+ QSGMaterialShader::initialize();
+ m_matrix_id = program()->uniformLocation("matrix");
+ m_textureScale_id = program()->uniformLocation("textureScale");
+ m_color_id = program()->uniformLocation("color");
+ m_alphaMin_id = program()->uniformLocation("alphaMin");
+ m_alphaMax_id = program()->uniformLocation("alphaMax");
+}
+
+void QSGDistanceFieldTextMaterialShader::updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect)
+{
+ Q_ASSERT(oldEffect == 0 || newEffect->type() == oldEffect->type());
+ QSGDistanceFieldTextMaterial *material = static_cast<QSGDistanceFieldTextMaterial *>(newEffect);
+ QSGDistanceFieldTextMaterial *oldMaterial = static_cast<QSGDistanceFieldTextMaterial *>(oldEffect);
+
+ bool updated = material->updateTexture();
+ if (updated && !material->glyphCache()->useWorkaroundBrokenFBOReadback())
+ activate();
+
+ if (oldMaterial == 0
+ || material->color() != oldMaterial->color()
+ || state.isOpacityDirty()) {
+ QVector4D color(material->color().redF(), material->color().greenF(),
+ material->color().blueF(), material->color().alphaF());
+ color *= state.opacity();
+ program()->setUniformValue(m_color_id, color);
+ }
+
+ bool updateRange = false;
+ if (oldMaterial == 0
+ || material->glyphCache()->fontScale() != oldMaterial->glyphCache()->fontScale()) {
+ m_fontScale = material->glyphCache()->fontScale();
+ updateRange = true;
+ }
+ if (state.isMatrixDirty()) {
+ program()->setUniformValue(m_matrix_id, state.combinedMatrix());
+ m_matrixScale = qSqrt(state.modelViewMatrix().determinant());
+ updateRange = true;
+ }
+ if (updateRange)
+ updateAlphaRange();
+
+ Q_ASSERT(material->glyphCache());
+
+ if (updated
+ || oldMaterial == 0
+ || oldMaterial->glyphCache()->texture() != material->glyphCache()->texture()) {
+ program()->setUniformValue(m_textureScale_id, QVector2D(1.0 / material->glyphCache()->textureSize().width(),
+ 1.0 / material->glyphCache()->textureSize().height()));
+ glBindTexture(GL_TEXTURE_2D, material->glyphCache()->texture());
+
+ if (updated) {
+ // Set the mag/min filters to be linear. We only need to do this when the texture
+ // has been recreated.
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ }
+ }
+}
+
+QSGDistanceFieldTextMaterial::QSGDistanceFieldTextMaterial()
+ : m_glyph_cache(0)
+{
+ setFlag(Blending, true);
+}
+
+QSGDistanceFieldTextMaterial::~QSGDistanceFieldTextMaterial()
+{
+}
+
+QSGMaterialType *QSGDistanceFieldTextMaterial::type() const
+{
+ static QSGMaterialType type;
+ return &type;
+}
+
+QSGMaterialShader *QSGDistanceFieldTextMaterial::createShader() const
+{
+ return new QSGDistanceFieldTextMaterialShader;
+}
+
+bool QSGDistanceFieldTextMaterial::updateTexture()
+{
+ m_glyph_cache->updateCache();
+ QSize glyphCacheSize = m_glyph_cache->textureSize();
+ if (glyphCacheSize != m_size) {
+ m_size = glyphCacheSize;
+
+ return true;
+ } else {
+ return false;
+ }
+}
+
+int QSGDistanceFieldTextMaterial::compare(const QSGMaterial *o) const
+{
+ Q_ASSERT(o && type() == o->type());
+ const QSGDistanceFieldTextMaterial *other = static_cast<const QSGDistanceFieldTextMaterial *>(o);
+ if (m_glyph_cache->fontScale() != other->m_glyph_cache->fontScale()) {
+ qreal s1 = m_glyph_cache->fontScale();
+ qreal s2 = other->m_glyph_cache->fontScale();
+ return int(s2 < s1) - int(s1 < s2);
+ }
+ QRgb c1 = m_color.rgba();
+ QRgb c2 = other->m_color.rgba();
+ return int(c2 < c1) - int(c1 < c2);
+}
+
+
+class DistanceFieldStyledTextMaterialShader : public QSGDistanceFieldTextMaterialShader
+{
+public:
+ DistanceFieldStyledTextMaterialShader();
+
+ virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect);
+
+protected:
+ virtual void initialize();
+ virtual const char *fragmentShader() const = 0;
+
+ int m_styleColor_id;
+};
+
+DistanceFieldStyledTextMaterialShader::DistanceFieldStyledTextMaterialShader()
+ : QSGDistanceFieldTextMaterialShader()
+{
+}
+
+void DistanceFieldStyledTextMaterialShader::initialize()
+{
+ QSGDistanceFieldTextMaterialShader::initialize();
+ m_styleColor_id = program()->uniformLocation("styleColor");
+}
+
+void DistanceFieldStyledTextMaterialShader::updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect)
+{
+ QSGDistanceFieldTextMaterialShader::updateState(state, newEffect, oldEffect);
+
+ QSGDistanceFieldStyledTextMaterial *material = static_cast<QSGDistanceFieldStyledTextMaterial *>(newEffect);
+ QSGDistanceFieldStyledTextMaterial *oldMaterial = static_cast<QSGDistanceFieldStyledTextMaterial *>(oldEffect);
+
+ if (oldMaterial == 0
+ || material->styleColor() != oldMaterial->styleColor()
+ || (state.isOpacityDirty())) {
+ QVector4D color(material->styleColor().redF(), material->styleColor().greenF(),
+ material->styleColor().blueF(), material->styleColor().alphaF());
+ color *= state.opacity();
+ program()->setUniformValue(m_styleColor_id, color);
+ }
+}
+
+QSGDistanceFieldStyledTextMaterial::QSGDistanceFieldStyledTextMaterial()
+ : QSGDistanceFieldTextMaterial()
+{
+}
+
+QSGDistanceFieldStyledTextMaterial::~QSGDistanceFieldStyledTextMaterial()
+{
+}
+
+int QSGDistanceFieldStyledTextMaterial::compare(const QSGMaterial *o) const
+{
+ Q_ASSERT(o && type() == o->type());
+ const QSGDistanceFieldStyledTextMaterial *other = static_cast<const QSGDistanceFieldStyledTextMaterial *>(o);
+ if (m_styleColor != other->m_styleColor) {
+ QRgb c1 = m_styleColor.rgba();
+ QRgb c2 = other->m_styleColor.rgba();
+ return int(c2 < c1) - int(c1 < c2);
+ }
+ return QSGDistanceFieldTextMaterial::compare(o);
+}
+
+
+class DistanceFieldOutlineTextMaterialShader : public DistanceFieldStyledTextMaterialShader
+{
+public:
+ DistanceFieldOutlineTextMaterialShader();
+
+ virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect);
+
+protected:
+ virtual void initialize();
+ virtual const char *fragmentShader() const;
+
+ void updateOutlineAlphaRange(int dfRadius);
+
+ int m_outlineAlphaMax0_id;
+ int m_outlineAlphaMax1_id;
+};
+
+const char *DistanceFieldOutlineTextMaterialShader::fragmentShader() const {
+ return
+ "varying highp vec2 sampleCoord; \n"
+ "uniform sampler2D texture; \n"
+ "uniform lowp vec4 color; \n"
+ "uniform lowp vec4 styleColor; \n"
+ "uniform highp float alphaMin; \n"
+ "uniform highp float alphaMax; \n"
+ "uniform highp float outlineAlphaMax0; \n"
+ "uniform highp float outlineAlphaMax1; \n"
+ "void main() { \n"
+ " mediump float d = texture2D(texture, sampleCoord).a; \n"
+ " gl_FragColor = mix(styleColor, color, smoothstep(alphaMin, alphaMax, d)) \n"
+ " * smoothstep(outlineAlphaMax0, outlineAlphaMax1, d); \n"
+ "}";
+}
+
+DistanceFieldOutlineTextMaterialShader::DistanceFieldOutlineTextMaterialShader()
+ : DistanceFieldStyledTextMaterialShader()
+{
+}
+
+void DistanceFieldOutlineTextMaterialShader::initialize()
+{
+ DistanceFieldStyledTextMaterialShader::initialize();
+ m_outlineAlphaMax0_id = program()->uniformLocation("outlineAlphaMax0");
+ m_outlineAlphaMax1_id = program()->uniformLocation("outlineAlphaMax1");
+}
+
+void DistanceFieldOutlineTextMaterialShader::updateOutlineAlphaRange(int dfRadius)
+{
+ qreal outlineLimit = qMax(qreal(0.2), qreal(0.5 - 0.5 / dfRadius / m_fontScale));
+
+ qreal combinedScale = m_fontScale * m_matrixScale;
+ qreal alphaMin = qMax(0.0, 0.5 - 0.07 / combinedScale);
+ qreal styleAlphaMin0 = qMax(0.0, outlineLimit - 0.07 / combinedScale);
+ qreal styleAlphaMin1 = qMin(qreal(outlineLimit + 0.07 / combinedScale), alphaMin);
+ program()->setUniformValue(m_outlineAlphaMax0_id, GLfloat(styleAlphaMin0));
+ program()->setUniformValue(m_outlineAlphaMax1_id, GLfloat(styleAlphaMin1));
+}
+
+void DistanceFieldOutlineTextMaterialShader::updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect)
+{
+ DistanceFieldStyledTextMaterialShader::updateState(state, newEffect, oldEffect);
+
+ QSGDistanceFieldOutlineTextMaterial *material = static_cast<QSGDistanceFieldOutlineTextMaterial *>(newEffect);
+ QSGDistanceFieldOutlineTextMaterial *oldMaterial = static_cast<QSGDistanceFieldOutlineTextMaterial *>(oldEffect);
+
+ if (oldMaterial == 0
+ || material->glyphCache()->fontScale() != oldMaterial->glyphCache()->fontScale()
+ || state.isMatrixDirty())
+ updateOutlineAlphaRange(material->glyphCache()->distanceFieldRadius());
+}
+
+
+QSGDistanceFieldOutlineTextMaterial::QSGDistanceFieldOutlineTextMaterial()
+ : QSGDistanceFieldStyledTextMaterial()
+{
+}
+
+QSGDistanceFieldOutlineTextMaterial::~QSGDistanceFieldOutlineTextMaterial()
+{
+}
+
+QSGMaterialType *QSGDistanceFieldOutlineTextMaterial::type() const
+{
+ static QSGMaterialType type;
+ return &type;
+}
+
+QSGMaterialShader *QSGDistanceFieldOutlineTextMaterial::createShader() const
+{
+ return new DistanceFieldOutlineTextMaterialShader;
+}
+
+
+class DistanceFieldShiftedStyleTextMaterialShader : public DistanceFieldStyledTextMaterialShader
+{
+public:
+ DistanceFieldShiftedStyleTextMaterialShader();
+
+ virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect);
+
+protected:
+ virtual void initialize();
+ virtual const char *vertexShader() const;
+ virtual const char *fragmentShader() const;
+
+ void updateShift(const QSGDistanceFieldGlyphCache *cache, const QPointF& shift);
+
+ int m_shift_id;
+};
+
+DistanceFieldShiftedStyleTextMaterialShader::DistanceFieldShiftedStyleTextMaterialShader()
+ : DistanceFieldStyledTextMaterialShader()
+{
+}
+
+void DistanceFieldShiftedStyleTextMaterialShader::initialize()
+{
+ DistanceFieldStyledTextMaterialShader::initialize();
+ m_shift_id = program()->uniformLocation("shift");
+}
+
+void DistanceFieldShiftedStyleTextMaterialShader::updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect)
+{
+ DistanceFieldStyledTextMaterialShader::updateState(state, newEffect, oldEffect);
+
+ QSGDistanceFieldShiftedStyleTextMaterial *material = static_cast<QSGDistanceFieldShiftedStyleTextMaterial *>(newEffect);
+ QSGDistanceFieldShiftedStyleTextMaterial *oldMaterial = static_cast<QSGDistanceFieldShiftedStyleTextMaterial *>(oldEffect);
+
+ if (oldMaterial == 0
+ || oldMaterial->glyphCache()->fontScale() != material->glyphCache()->fontScale()
+ || oldMaterial->shift() != material->shift()
+ || oldMaterial->glyphCache()->textureSize() != material->glyphCache()->textureSize()) {
+ updateShift(material->glyphCache(), material->shift());
+ }
+}
+
+void DistanceFieldShiftedStyleTextMaterialShader::updateShift(const QSGDistanceFieldGlyphCache *cache, const QPointF &shift)
+{
+ QPointF texel(1.0 / cache->fontScale() * shift.x(),
+ 1.0 / cache->fontScale() * shift.y());
+ program()->setUniformValue(m_shift_id, texel);
+}
+
+const char *DistanceFieldShiftedStyleTextMaterialShader::vertexShader() const
+{
+ return
+ "uniform highp mat4 matrix; \n"
+ "uniform highp vec2 textureScale; \n"
+ "attribute highp vec4 vCoord; \n"
+ "attribute highp vec2 tCoord; \n"
+ "uniform highp vec2 shift; \n"
+ "varying highp vec2 sampleCoord; \n"
+ "varying highp vec2 shiftedSampleCoord; \n"
+ "void main() { \n"
+ " sampleCoord = tCoord * textureScale; \n"
+ " shiftedSampleCoord = (tCoord - shift) * textureScale; \n"
+ " gl_Position = matrix * vCoord; \n"
+ "}";
+}
+
+const char *DistanceFieldShiftedStyleTextMaterialShader::fragmentShader() const {
+ return
+ "varying highp vec2 sampleCoord; \n"
+ "varying highp vec2 shiftedSampleCoord; \n"
+ "uniform sampler2D texture; \n"
+ "uniform lowp vec4 color; \n"
+ "uniform lowp vec4 styleColor; \n"
+ "uniform highp float alphaMin; \n"
+ "uniform highp float alphaMax; \n"
+ "void main() { \n"
+ " highp float a = smoothstep(alphaMin, alphaMax, texture2D(texture, sampleCoord).a);\n"
+ " highp vec4 shifted = styleColor * smoothstep(alphaMin, \n"
+ " alphaMax, \n"
+ " texture2D(texture, shiftedSampleCoord).a); \n"
+ " gl_FragColor = mix(shifted, color, a); \n"
+ "}";
+}
+
+QSGDistanceFieldShiftedStyleTextMaterial::QSGDistanceFieldShiftedStyleTextMaterial()
+ : QSGDistanceFieldStyledTextMaterial()
+{
+}
+
+QSGDistanceFieldShiftedStyleTextMaterial::~QSGDistanceFieldShiftedStyleTextMaterial()
+{
+}
+
+QSGMaterialType *QSGDistanceFieldShiftedStyleTextMaterial::type() const
+{
+ static QSGMaterialType type;
+ return &type;
+}
+
+QSGMaterialShader *QSGDistanceFieldShiftedStyleTextMaterial::createShader() const
+{
+ return new DistanceFieldShiftedStyleTextMaterialShader;
+}
+
+
+class QSGSubPixelDistanceFieldTextMaterialShader : public QSGDistanceFieldTextMaterialShader
+{
+public:
+ virtual void initialize();
+ virtual void activate();
+ virtual void deactivate();
+ virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect);
+
+protected:
+ virtual const char *vertexShader() const;
+ virtual const char *fragmentShader() const;
+
+ void updateAlphaRange();
+
+private:
+ int m_fontScale_id;
+ int m_vecDelta_id;
+};
+
+const char *QSGSubPixelDistanceFieldTextMaterialShader::vertexShader() const {
+ return
+ "uniform highp mat4 matrix; \n"
+ "uniform highp vec2 textureScale; \n"
+ "uniform highp float fontScale; \n"
+ "uniform highp vec4 vecDelta; \n"
+ "attribute highp vec4 vCoord; \n"
+ "attribute highp vec2 tCoord; \n"
+ "varying highp vec2 sampleCoord; \n"
+ "varying highp vec3 sampleFarLeft; \n"
+ "varying highp vec3 sampleNearLeft; \n"
+ "varying highp vec3 sampleNearRight; \n"
+ "varying highp vec3 sampleFarRight; \n"
+ "void main() { \n"
+ " sampleCoord = tCoord * textureScale; \n"
+ " gl_Position = matrix * vCoord; \n"
+ // Calculate neighbour pixel position in item space.
+ " highp vec3 wDelta = gl_Position.w * vecDelta.xyw; \n"
+ " highp vec3 farLeft = vCoord.xyw - 0.667 * wDelta; \n"
+ " highp vec3 nearLeft = vCoord.xyw - 0.333 * wDelta; \n"
+ " highp vec3 nearRight = vCoord.xyw + 0.333 * wDelta; \n"
+ " highp vec3 farRight = vCoord.xyw + 0.667 * wDelta; \n"
+ // Calculate neighbour texture coordinate.
+ " highp vec2 scale = textureScale / fontScale; \n"
+ " highp vec2 base = sampleCoord - scale * vCoord.xy; \n"
+ " sampleFarLeft = vec3(base * farLeft.z + scale * farLeft.xy, farLeft.z); \n"
+ " sampleNearLeft = vec3(base * nearLeft.z + scale * nearLeft.xy, nearLeft.z); \n"
+ " sampleNearRight = vec3(base * nearRight.z + scale * nearRight.xy, nearRight.z); \n"
+ " sampleFarRight = vec3(base * farRight.z + scale * farRight.xy, farRight.z); \n"
+ "}";
+}
+
+const char *QSGSubPixelDistanceFieldTextMaterialShader::fragmentShader() const {
+ return
+ "varying highp vec2 sampleCoord; \n"
+ "varying highp vec3 sampleFarLeft; \n"
+ "varying highp vec3 sampleNearLeft; \n"
+ "varying highp vec3 sampleNearRight; \n"
+ "varying highp vec3 sampleFarRight; \n"
+ "uniform sampler2D texture; \n"
+ "uniform lowp vec4 color; \n"
+ "uniform highp float alphaMin; \n"
+ "uniform highp float alphaMax; \n"
+ "void main() { \n"
+ " highp vec4 n; \n"
+ " n.x = texture2DProj(texture, sampleFarLeft).a; \n"
+ " n.y = texture2DProj(texture, sampleNearLeft).a; \n"
+ " highp float c = texture2D(texture, sampleCoord).a; \n"
+ " n.z = texture2DProj(texture, sampleNearRight).a; \n"
+ " n.w = texture2DProj(texture, sampleFarRight).a; \n"
+#if 0
+ // Blurrier, faster.
+ " n = smoothstep(alphaMin, alphaMax, n); \n"
+ " c = smoothstep(alphaMin, alphaMax, c); \n"
+#else
+ // Sharper, slower.
+ " highp vec2 d = min(abs(n.yw - n.xz) * 2., 0.67); \n"
+ " highp vec2 lo = mix(vec2(alphaMin), vec2(0.5), d); \n"
+ " highp vec2 hi = mix(vec2(alphaMax), vec2(0.5), d); \n"
+ " n = smoothstep(lo.xxyy, hi.xxyy, n); \n"
+ " c = smoothstep(lo.x + lo.y, hi.x + hi.y, 2. * c); \n"
+#endif
+ " gl_FragColor = vec4(0.333 * (n.xyz + n.yzw + c), c) * color.w; \n"
+ "}";
+}
+
+//const char *QSGSubPixelDistanceFieldTextMaterialShader::fragmentShader() const {
+// return
+// "#extension GL_OES_standard_derivatives: enable \n"
+// "varying highp vec2 sampleCoord; \n"
+// "uniform sampler2D texture; \n"
+// "uniform lowp vec4 color; \n"
+// "uniform highp float alphaMin; \n"
+// "uniform highp float alphaMax; \n"
+// "void main() { \n"
+// " highp vec2 delta = dFdx(sampleCoord); \n"
+// " highp vec4 n; \n"
+// " n.x = texture2D(texture, sampleCoord - 0.667 * delta).a; \n"
+// " n.y = texture2D(texture, sampleCoord - 0.333 * delta).a; \n"
+// " highp float c = texture2D(texture, sampleCoord).a; \n"
+// " n.z = texture2D(texture, sampleCoord + 0.333 * delta).a; \n"
+// " n.w = texture2D(texture, sampleCoord + 0.667 * delta).a; \n"
+// " n = smoothstep(alphaMin, alphaMax, n); \n"
+// " c = smoothstep(alphaMin, alphaMax, c); \n"
+// " gl_FragColor = vec4(0.333 * (n.xyz + n.yzw + c), c) * color.w; \n"
+// "}";
+//}
+
+void QSGSubPixelDistanceFieldTextMaterialShader::initialize()
+{
+ QSGDistanceFieldTextMaterialShader::initialize();
+ m_fontScale_id = program()->uniformLocation("fontScale");
+ m_vecDelta_id = program()->uniformLocation("vecDelta");
+}
+
+void QSGSubPixelDistanceFieldTextMaterialShader::activate()
+{
+ QSGDistanceFieldTextMaterialShader::activate();
+ glBlendFunc(GL_CONSTANT_COLOR, GL_ONE_MINUS_SRC_COLOR);
+}
+
+void QSGSubPixelDistanceFieldTextMaterialShader::deactivate()
+{
+ QSGDistanceFieldTextMaterialShader::deactivate();
+ glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+}
+
+void QSGSubPixelDistanceFieldTextMaterialShader::updateAlphaRange()
+{
+ qreal combinedScale = m_fontScale * m_matrixScale;
+ qreal alphaMin = qMax(0.0, 0.5 - 0.05 / combinedScale);
+ qreal alphaMax = qMin(0.5 + 0.05 / combinedScale, 1.0);
+ program()->setUniformValue(m_alphaMin_id, GLfloat(alphaMin));
+ program()->setUniformValue(m_alphaMax_id, GLfloat(alphaMax));
+}
+
+void QSGSubPixelDistanceFieldTextMaterialShader::updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect)
+{
+ Q_ASSERT(oldEffect == 0 || newEffect->type() == oldEffect->type());
+ QSGDistanceFieldTextMaterial *material = static_cast<QSGDistanceFieldTextMaterial *>(newEffect);
+ QSGDistanceFieldTextMaterial *oldMaterial = static_cast<QSGDistanceFieldTextMaterial *>(oldEffect);
+
+ if (oldMaterial == 0 || material->color() != oldMaterial->color()) {
+ QColor c = material->color();
+ state.context()->functions()->glBlendColor(c.redF(), c.greenF(), c.blueF(), 1.0f);
+ }
+
+ if (oldMaterial == 0 || material->glyphCache()->fontScale() != oldMaterial->glyphCache()->fontScale())
+ program()->setUniformValue(m_fontScale_id, GLfloat(material->glyphCache()->fontScale()));
+
+ if (oldMaterial == 0 || state.isMatrixDirty()) {
+ int viewportWidth = state.viewportRect().width();
+ QMatrix4x4 mat = state.combinedMatrix().inverted();
+ program()->setUniformValue(m_vecDelta_id, mat.column(0) * (qreal(2) / viewportWidth));
+ }
+
+ QSGDistanceFieldTextMaterialShader::updateState(state, newEffect, oldEffect);
+}
+
+QSGMaterialType *QSGSubPixelDistanceFieldTextMaterial::type() const
+{
+ static QSGMaterialType type;
+ return &type;
+}
+
+QSGMaterialShader *QSGSubPixelDistanceFieldTextMaterial::createShader() const
+{
+ return new QSGSubPixelDistanceFieldTextMaterialShader;
+}
+
+
+QT_END_NAMESPACE
diff --git a/src/declarative/scenegraph/qsgdistancefieldglyphnode_p.h b/src/declarative/scenegraph/qsgdistancefieldglyphnode_p.h
new file mode 100644
index 0000000000..e97972579c
--- /dev/null
+++ b/src/declarative/scenegraph/qsgdistancefieldglyphnode_p.h
@@ -0,0 +1,93 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef DISTANCEFIELD_GLYPHNODE_H
+#define DISTANCEFIELD_GLYPHNODE_H
+
+#include <private/qsgadaptationlayer_p.h>
+#include "qsgtexture.h"
+#include <qsgtext_p.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QSGDistanceFieldGlyphCache;
+class QSGDistanceFieldTextMaterial;
+class QSGDistanceFieldGlyphNode: public QSGGlyphNode
+{
+public:
+ QSGDistanceFieldGlyphNode();
+ ~QSGDistanceFieldGlyphNode();
+
+ virtual QPointF baseLine() const { return m_baseLine; }
+ virtual void setGlyphs(const QPointF &position, const QGlyphRun &glyphs);
+ virtual void setColor(const QColor &color);
+
+ virtual void setPreferredAntialiasingMode(AntialiasingMode mode);
+
+ void setStyle(QSGText::TextStyle style);
+ void setStyleColor(const QColor &color);
+
+private:
+ void updateGeometry();
+ void updateFont();
+ void updateMaterial();
+
+ QColor m_color;
+ QPointF m_baseLine;
+ QSGDistanceFieldTextMaterial *m_material;
+ QPointF m_position;
+ QGlyphRun m_glyphs;
+ QSGDistanceFieldGlyphCache *m_glyph_cache;
+ QSGGeometry m_geometry;
+ QSGText::TextStyle m_style;
+ QColor m_styleColor;
+ AntialiasingMode m_antialiasingMode;
+};
+
+QT_END_HEADER
+
+QT_END_NAMESPACE
+
+#endif // DISTANCEFIELD_GLYPHNODE_H
diff --git a/src/declarative/scenegraph/qsgdistancefieldglyphnode_p_p.h b/src/declarative/scenegraph/qsgdistancefieldglyphnode_p_p.h
new file mode 100644
index 0000000000..37415e5dae
--- /dev/null
+++ b/src/declarative/scenegraph/qsgdistancefieldglyphnode_p_p.h
@@ -0,0 +1,128 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef DISTANCEFIELDTEXTMATERIAL_H
+#define DISTANCEFIELDTEXTMATERIAL_H
+
+#include <qsgmaterial.h>
+#include "qsgdistancefieldglyphnode_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QSGDistanceFieldGlyphCache;
+
+class QSGDistanceFieldTextMaterial: public QSGMaterial
+{
+public:
+ QSGDistanceFieldTextMaterial();
+ ~QSGDistanceFieldTextMaterial();
+
+ virtual QSGMaterialType *type() const;
+ virtual QSGMaterialShader *createShader() const;
+ virtual int compare(const QSGMaterial *other) const;
+
+ void setColor(const QColor &color) { m_color = color; }
+ const QColor &color() const { return m_color; }
+
+ void setGlyphCache(QSGDistanceFieldGlyphCache *a) { m_glyph_cache = a; }
+ QSGDistanceFieldGlyphCache *glyphCache() const { return m_glyph_cache; }
+
+ bool updateTexture();
+
+protected:
+ QSize m_size;
+ QColor m_color;
+ QSGDistanceFieldGlyphCache *m_glyph_cache;
+};
+
+class QSGDistanceFieldStyledTextMaterial : public QSGDistanceFieldTextMaterial
+{
+public:
+ QSGDistanceFieldStyledTextMaterial();
+ ~QSGDistanceFieldStyledTextMaterial();
+
+ virtual QSGMaterialType *type() const = 0;
+ virtual QSGMaterialShader *createShader() const = 0;
+ virtual int compare(const QSGMaterial *other) const;
+
+ void setStyleColor(const QColor &color) { m_styleColor = color; }
+ const QColor &styleColor() const { return m_styleColor; }
+
+protected:
+ QColor m_styleColor;
+};
+
+class QSGDistanceFieldOutlineTextMaterial : public QSGDistanceFieldStyledTextMaterial
+{
+public:
+ QSGDistanceFieldOutlineTextMaterial();
+ ~QSGDistanceFieldOutlineTextMaterial();
+
+ virtual QSGMaterialType *type() const;
+ virtual QSGMaterialShader *createShader() const;
+};
+
+class QSGDistanceFieldShiftedStyleTextMaterial : public QSGDistanceFieldStyledTextMaterial
+{
+public:
+ QSGDistanceFieldShiftedStyleTextMaterial();
+ ~QSGDistanceFieldShiftedStyleTextMaterial();
+
+ virtual QSGMaterialType *type() const;
+ virtual QSGMaterialShader *createShader() const;
+
+ void setShift(const QPointF &shift) { m_shift = shift; }
+ const QPointF &shift() const { return m_shift; }
+
+protected:
+ QPointF m_shift;
+};
+
+class QSGSubPixelDistanceFieldTextMaterial : public QSGDistanceFieldTextMaterial
+{
+public:
+ virtual QSGMaterialType *type() const;
+ virtual QSGMaterialShader *createShader() const;
+};
+
+QT_END_NAMESPACE
+
+#endif // DISTANCEFIELDTEXTMATERIAL_H
diff --git a/src/declarative/scenegraph/qsgflashnode.cpp b/src/declarative/scenegraph/qsgflashnode.cpp
new file mode 100644
index 0000000000..c2c1919f82
--- /dev/null
+++ b/src/declarative/scenegraph/qsgflashnode.cpp
@@ -0,0 +1,62 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**Ëš
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgflashnode_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QSGFlashNode::QSGFlashNode()
+ : m_counter(1)
+{
+ setFlag(UsePreprocess);
+ setColor(QColor(rand()%56 + 200, rand()%56 + 200, rand()%156 + 100)); // A random, mostly yellow, color
+}
+
+void QSGFlashNode::preprocess()
+{
+ if (m_counter) {
+ --m_counter;
+ } else {
+ delete this;
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/scenegraph/qsgflashnode_p.h b/src/declarative/scenegraph/qsgflashnode_p.h
new file mode 100644
index 0000000000..776ae48f13
--- /dev/null
+++ b/src/declarative/scenegraph/qsgflashnode_p.h
@@ -0,0 +1,69 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**Ëš
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGFLASHNODE_H
+#define QSGFLASHNODE_H
+
+#include <QSGSimpleRectNode>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QSGFlashNode : public QSGSimpleRectNode
+{
+public:
+ QSGFlashNode();
+
+ void preprocess();
+
+private:
+ int m_counter;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QSGFLASHNODE_H
+
diff --git a/src/declarative/scenegraph/scenegraph.pri b/src/declarative/scenegraph/scenegraph.pri
new file mode 100644
index 0000000000..77a93e4811
--- /dev/null
+++ b/src/declarative/scenegraph/scenegraph.pri
@@ -0,0 +1,80 @@
+INCLUDEPATH += $$PWD/coreapi $$PWD/convenience $$PWD/3d
+!contains(QT_CONFIG, egl):DEFINES += QT_NO_EGL
+
+QT += opengl
+
+
+# Core API
+HEADERS += \
+ $$PWD/coreapi/qsgdefaultrenderer_p.h \
+ $$PWD/coreapi/qsggeometry.h \
+ $$PWD/coreapi/qsgmaterial.h \
+ $$PWD/coreapi/qsgmatrix4x4stack.h \
+ $$PWD/coreapi/qsgmatrix4x4stack_p.h \
+ $$PWD/coreapi/qsgnode.h \
+ $$PWD/coreapi/qsgnodeupdater_p.h \
+ $$PWD/coreapi/qsgrenderer_p.h
+SOURCES += \
+ $$PWD/coreapi/qsgdefaultrenderer.cpp \
+ $$PWD/coreapi/qsggeometry.cpp \
+ $$PWD/coreapi/qsgmaterial.cpp \
+ $$PWD/coreapi/qsgmatrix4x4stack.cpp \
+ $$PWD/coreapi/qsgnode.cpp \
+ $$PWD/coreapi/qsgnodeupdater.cpp \
+ $$PWD/coreapi/qsgrenderer.cpp
+
+
+# Util API
+HEADERS += \
+ $$PWD/util/qsgareaallocator_p.h \
+ $$PWD/util/qsgengine.h \
+ $$PWD/util/qsgflatcolormaterial.h \
+ $$PWD/util/qsgsimplerectnode.h \
+ $$PWD/util/qsgsimpletexturenode.h \
+ $$PWD/util/qsgtexturematerial.h \
+ $$PWD/util/qsgtexturematerial_p.h \
+ $$PWD/util/qsgvertexcolormaterial_p.h \
+ $$PWD/util/qsgtexture.h \
+ $$PWD/util/qsgtexture_p.h \
+ $$PWD/util/qsgtextureprovider_p.h \
+ $$PWD/util/qsgpainternode_p.h
+
+SOURCES += \
+ $$PWD/util/qsgareaallocator.cpp \
+ $$PWD/util/qsgengine.cpp \
+ $$PWD/util/qsgflatcolormaterial.cpp \
+ $$PWD/util/qsgsimplerectnode.cpp \
+ $$PWD/util/qsgsimpletexturenode.cpp \
+ $$PWD/util/qsgtexturematerial.cpp \
+ $$PWD/util/qsgvertexcolormaterial.cpp \
+ $$PWD/util/qsgtexture.cpp \
+ $$PWD/util/qsgtextureprovider.cpp \
+ $$PWD/util/qsgpainternode.cpp
+
+
+# QML / Adaptations API
+HEADERS += \
+ $$PWD/qsgadaptationlayer_p.h \
+ $$PWD/qsgcontext_p.h \
+ $$PWD/qsgcontextplugin_p.h \
+ $$PWD/qsgdefaultglyphnode_p.h \
+ $$PWD/qsgdistancefieldglyphcache_p.h \
+ $$PWD/qsgdistancefieldglyphnode_p.h \
+ $$PWD/qsgdistancefieldglyphnode_p_p.h \
+ $$PWD/qsgdefaultglyphnode_p_p.h \
+ $$PWD/qsgdefaultimagenode_p.h \
+ $$PWD/qsgdefaultrectanglenode_p.h \
+ $$PWD/qsgflashnode_p.h
+
+SOURCES += \
+ $$PWD/qsgadaptationlayer.cpp \
+ $$PWD/qsgcontext.cpp \
+ $$PWD/qsgcontextplugin.cpp \
+ $$PWD/qsgdefaultglyphnode.cpp \
+ $$PWD/qsgdefaultglyphnode_p.cpp \
+ $$PWD/qsgdistancefieldglyphcache.cpp \
+ $$PWD/qsgdistancefieldglyphnode.cpp \
+ $$PWD/qsgdistancefieldglyphnode_p.cpp \
+ $$PWD/qsgdefaultimagenode.cpp \
+ $$PWD/qsgdefaultrectanglenode.cpp \
+ $$PWD/qsgflashnode.cpp
diff --git a/src/declarative/scenegraph/util/qsgareaallocator.cpp b/src/declarative/scenegraph/util/qsgareaallocator.cpp
new file mode 100644
index 0000000000..a28575c982
--- /dev/null
+++ b/src/declarative/scenegraph/util/qsgareaallocator.cpp
@@ -0,0 +1,290 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgareaallocator_p.h"
+
+#include <QtCore/qglobal.h>
+#include <QtCore/qrect.h>
+#include <QtCore/qpoint.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace
+{
+ enum SplitType
+ {
+ VerticalSplit,
+ HorizontalSplit
+ };
+
+ static const int maxMargin = 2;
+}
+
+struct QSGAreaAllocatorNode
+{
+ QSGAreaAllocatorNode(QSGAreaAllocatorNode *parent);
+ ~QSGAreaAllocatorNode();
+ inline bool isLeaf();
+
+ QSGAreaAllocatorNode *parent;
+ QSGAreaAllocatorNode *left;
+ QSGAreaAllocatorNode *right;
+ int split; // only valid for inner nodes.
+ SplitType splitType;
+ bool isOccupied; // only valid for leaf nodes.
+};
+
+QSGAreaAllocatorNode::QSGAreaAllocatorNode(QSGAreaAllocatorNode *parent)
+ : parent(parent)
+ , left(0)
+ , right(0)
+ , isOccupied(false)
+{
+}
+
+QSGAreaAllocatorNode::~QSGAreaAllocatorNode()
+{
+ delete left;
+ delete right;
+}
+
+bool QSGAreaAllocatorNode::isLeaf()
+{
+ Q_ASSERT((left != 0) == (right != 0));
+ return !left;
+}
+
+
+QSGAreaAllocator::QSGAreaAllocator(const QSize &size) : m_size(size)
+{
+ m_root = new QSGAreaAllocatorNode(0);
+}
+
+QSGAreaAllocator::~QSGAreaAllocator()
+{
+ delete m_root;
+}
+
+QRect QSGAreaAllocator::allocate(const QSize &size)
+{
+ QPoint point;
+ bool result = allocateInNode(size, point, QRect(QPoint(0, 0), m_size), m_root);
+ return result ? QRect(point, size) : QRect();
+}
+
+bool QSGAreaAllocator::deallocate(const QRect &rect)
+{
+ return deallocateInNode(rect.topLeft(), m_root);
+}
+
+bool QSGAreaAllocator::allocateInNode(const QSize &size, QPoint &result, const QRect &currentRect, QSGAreaAllocatorNode *node)
+{
+ if (size.width() > currentRect.width() || size.height() > currentRect.height())
+ return false;
+
+ if (node->isLeaf()) {
+ if (node->isOccupied)
+ return false;
+ if (size.width() + maxMargin >= currentRect.width() && size.height() + maxMargin >= currentRect.height()) {
+ //Snug fit, occupy entire rectangle.
+ node->isOccupied = true;
+ result = currentRect.topLeft();
+ return true;
+ }
+ // TODO: Reuse nodes.
+ // Split node.
+ node->left = new QSGAreaAllocatorNode(node);
+ node->right = new QSGAreaAllocatorNode(node);
+ QRect splitRect = currentRect;
+ if ((currentRect.width() - size.width()) * currentRect.height() < (currentRect.height() - size.height()) * currentRect.width()) {
+ node->splitType = HorizontalSplit;
+ node->split = currentRect.top() + size.height();
+ splitRect.setHeight(size.height());
+ } else {
+ node->splitType = VerticalSplit;
+ node->split = currentRect.left() + size.width();
+ splitRect.setWidth(size.width());
+ }
+ return allocateInNode(size, result, splitRect, node->left);
+ } else {
+ // TODO: avoid unnecessary recursion.
+ // has been split.
+ QRect leftRect = currentRect;
+ QRect rightRect = currentRect;
+ if (node->splitType == HorizontalSplit) {
+ leftRect.setHeight(node->split - leftRect.top());
+ rightRect.setTop(node->split);
+ } else {
+ leftRect.setWidth(node->split - leftRect.left());
+ rightRect.setLeft(node->split);
+ }
+ if (allocateInNode(size, result, leftRect, node->left))
+ return true;
+ if (allocateInNode(size, result, rightRect, node->right))
+ return true;
+ return false;
+ }
+}
+
+bool QSGAreaAllocator::deallocateInNode(const QPoint &pos, QSGAreaAllocatorNode *node)
+{
+ while (!node->isLeaf()) {
+ // has been split.
+ int cmp = node->splitType == HorizontalSplit ? pos.y() : pos.x();
+ node = cmp < node->split ? node->left : node->right;
+ }
+ if (!node->isOccupied)
+ return false;
+ node->isOccupied = false;
+ mergeNodeWithNeighbors(node);
+ return true;
+}
+
+void QSGAreaAllocator::mergeNodeWithNeighbors(QSGAreaAllocatorNode *node)
+{
+ bool done = false;
+ QSGAreaAllocatorNode *parent = 0;
+ QSGAreaAllocatorNode *current = 0;
+ QSGAreaAllocatorNode *sibling;
+ while (!done) {
+ Q_ASSERT(node->isLeaf());
+ Q_ASSERT(!node->isOccupied);
+ if (node->parent == 0)
+ return; // No neighbours.
+
+ SplitType splitType = SplitType(node->parent->splitType);
+ done = true;
+
+ /* Special case. Might be faster than going through the general code path.
+ // Merge with sibling.
+ parent = node->parent;
+ sibling = (node == parent->left ? parent->right : parent->left);
+ if (sibling->isLeaf() && !sibling->isOccupied) {
+ Q_ASSERT(!sibling->right);
+ node = parent;
+ parent->isOccupied = false;
+ delete parent->left;
+ delete parent->right;
+ parent->left = parent->right = 0;
+ done = false;
+ continue;
+ }
+ */
+
+ // Merge with left neighbour.
+ current = node;
+ parent = current->parent;
+ while (parent && current == parent->left && parent->splitType == splitType) {
+ current = parent;
+ parent = parent->parent;
+ }
+
+ if (parent && parent->splitType == splitType) {
+ Q_ASSERT(current == parent->right);
+ Q_ASSERT(parent->left);
+
+ QSGAreaAllocatorNode *neighbor = parent->left;
+ while (neighbor->right && neighbor->splitType == splitType)
+ neighbor = neighbor->right;
+
+ if (neighbor->isLeaf() && neighbor->parent->splitType == splitType && !neighbor->isOccupied) {
+ // Left neighbour can be merged.
+ parent->split = neighbor->parent->split;
+
+ parent = neighbor->parent;
+ sibling = neighbor == parent->left ? parent->right : parent->left;
+ QSGAreaAllocatorNode **nodeRef = &m_root;
+ if (parent->parent) {
+ if (parent == parent->parent->left)
+ nodeRef = &parent->parent->left;
+ else
+ nodeRef = &parent->parent->right;
+ }
+ sibling->parent = parent->parent;
+ *nodeRef = sibling;
+ parent->left = parent->right = 0;
+ delete parent;
+ delete neighbor;
+ done = false;
+ }
+ }
+
+ // Merge with right neighbour.
+ current = node;
+ parent = current->parent;
+ while (parent && current == parent->right && parent->splitType == splitType) {
+ current = parent;
+ parent = parent->parent;
+ }
+
+ if (parent && parent->splitType == splitType) {
+ Q_ASSERT(current == parent->left);
+ Q_ASSERT(parent->right);
+
+ QSGAreaAllocatorNode *neighbor = parent->right;
+ while (neighbor->left && neighbor->splitType == splitType)
+ neighbor = neighbor->left;
+
+ if (neighbor->isLeaf() && neighbor->parent->splitType == splitType && !neighbor->isOccupied) {
+ // Right neighbour can be merged.
+ parent->split = neighbor->parent->split;
+
+ parent = neighbor->parent;
+ sibling = neighbor == parent->left ? parent->right : parent->left;
+ QSGAreaAllocatorNode **nodeRef = &m_root;
+ if (parent->parent) {
+ if (parent == parent->parent->left)
+ nodeRef = &parent->parent->left;
+ else
+ nodeRef = &parent->parent->right;
+ }
+ sibling->parent = parent->parent;
+ *nodeRef = sibling;
+ parent->left = parent->right = 0;
+ delete parent;
+ delete neighbor;
+ done = false;
+ }
+ }
+ } // end while(!done)
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/scenegraph/util/qsgareaallocator_p.h b/src/declarative/scenegraph/util/qsgareaallocator_p.h
new file mode 100644
index 0000000000..f84732fbdb
--- /dev/null
+++ b/src/declarative/scenegraph/util/qsgareaallocator_p.h
@@ -0,0 +1,73 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef AREAALLOCATOR_H
+#define AREAALLOCATOR_H
+
+#include <QtCore/qsize.h>
+
+QT_BEGIN_NAMESPACE
+
+class QRect;
+class QPoint;
+struct QSGAreaAllocatorNode;
+class Q_DECLARATIVE_EXPORT QSGAreaAllocator
+{
+public:
+ QSGAreaAllocator(const QSize &size);
+ ~QSGAreaAllocator();
+
+ QRect allocate(const QSize &size);
+ bool deallocate(const QRect &rect);
+ bool isEmpty() const { return m_root == 0; }
+ QSize size() const { return m_size; }
+private:
+ bool allocateInNode(const QSize &size, QPoint &result, const QRect &currentRect, QSGAreaAllocatorNode *node);
+ bool deallocateInNode(const QPoint &pos, QSGAreaAllocatorNode *node);
+ void mergeNodeWithNeighbors(QSGAreaAllocatorNode *node);
+
+ QSGAreaAllocatorNode *m_root;
+ QSize m_size;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/declarative/scenegraph/util/qsgengine.cpp b/src/declarative/scenegraph/util/qsgengine.cpp
new file mode 100644
index 0000000000..1b7f05809b
--- /dev/null
+++ b/src/declarative/scenegraph/util/qsgengine.cpp
@@ -0,0 +1,244 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgengine.h"
+
+#include <private/qsgtexture_p.h>
+#include <private/qsgrenderer_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QSGEnginePrivate : public QObjectPrivate
+{
+public:
+ QSGEnginePrivate()
+ : context(0)
+ , clearBeforeRender(true)
+ {
+ }
+
+ QSGContext *context;
+
+ bool clearBeforeRender;
+};
+
+
+/*!
+ \class QSGEngine
+ \brief The QSGEngine class serves as a generic entry point into scene graph specific APIs.
+
+ The QSGEngine class provides factory functions for creating textures. Though the user
+ can implement any type of texture using the abstract QSGTexture class, the QSGEngine
+ class provides some convenience for the default usecases. This also allows the scene
+ graph to apply hardware specific optimzations.
+
+ */
+
+
+
+/*!
+ Constructs a new QSGengine
+ */
+QSGEngine::QSGEngine(QObject *parent) :
+ QObject(*(new QSGEnginePrivate), parent)
+{
+}
+
+
+QSGEngine::~QSGEngine()
+{
+}
+
+/*!
+ \enum TextureOption
+
+ The TextureOption enums are used to customize a texture is wrapped.
+
+ \value TextureHasAlphaChannel The texture has an alpha channel and should
+ be drawn using blending.
+
+ \value TextureHasMipmaps The texture has mipmaps and can be drawn with
+ mipmapping enabled.
+
+ \value TextureOwnsGLTexture The texture object owns the texture id and
+ will delete the GL texture when the texture object is deleted.
+
+ */
+
+/*!
+ \fn void QSGEngine::beforeRendering()
+
+ This signal is emitted before the scene starts rendering.
+
+ Combined with the modes for clearing the background, this option
+ can be used to paint using raw GL under QML content.
+
+ The GL context used for rendering the scene graph will be bound
+ at this point.
+*/
+
+/*!
+ \fn void QSGEngine::afterRendering()
+
+ This signal is emitted after the scene has completed rendering, before swapbuffers is called.
+
+ This signal can be used to paint using raw GL on top of QML content,
+ or to do screen scraping of the current frame buffer.
+
+ The GL context used for rendering the scene graph will be bound at this point.
+ */
+
+
+
+/*!
+ Sets weither the scene graph rendering of QML should clear the color buffer
+ before it starts rendering to \a enbled.
+
+ By disabling clearing of the color buffer, it is possible to do GL painting
+ under the scene graph.
+
+ The color buffer is cleared by default.
+ */
+
+void QSGEngine::setClearBeforeRendering(bool enabled)
+{
+ Q_D(QSGEngine);
+ d->clearBeforeRender = enabled;
+ if (d->clearBeforeRender) {
+ d->context->renderer()->setClearMode(QSGRenderer::ClearDepthBuffer
+ | QSGRenderer::ClearColorBuffer);
+ } else {
+ d->context->renderer()->setClearMode(QSGRenderer::ClearDepthBuffer);
+ }
+}
+
+
+
+/*!
+ Returns weither clearing of the color buffer is done before rendering or not.
+ */
+
+bool QSGEngine::clearBeforeRendering() const
+{
+ Q_D(const QSGEngine);
+ return d->clearBeforeRender;
+}
+
+
+
+/*!
+ Creates a new QSGTexture from the supplied \a image. If the image has an
+ alpha channel, the corresponding texture will have an alpha channel.
+
+ The caller of the function is responsible for deleting the returned texture.
+
+ The actual GL texture will be deleted when the texture object is deleted.
+ */
+
+QSGTexture *QSGEngine::createTextureFromImage(const QImage &image) const
+{
+ Q_D(const QSGEngine);
+ return d->context->createTexture(image);
+}
+
+
+
+/*!
+ Creates a new QSGTexture object from an existing GL texture \a id.
+
+ The caller of the function is responsible for deleting the returned texture.
+
+ Use \a options to customize the texture attributes.
+ */
+QSGTexture *QSGEngine::createTextureFromId(uint id, const QSize &size, TextureOptions options) const
+{
+ QSGPlainTexture *texture = new QSGPlainTexture();
+ texture->setTextureId(id);
+ texture->setHasAlphaChannel(options & TextureHasAlphaChannel);
+ texture->setHasMipmaps(options & TextureHasMipmaps);
+ texture->setOwnsTexture(options & TextureOwnsGLTexture);
+ texture->setTextureSize(size);
+ return texture;
+}
+
+
+
+/*!
+ \internal
+
+ Sets the scene graph context of this engine to context.
+
+ The context will be set by the QSGcontext::initialize() function,
+ as part of constructing the engine object.
+ */
+
+void QSGEngine::setContext(QSGContext *context)
+{
+ Q_D(QSGEngine);
+ d->context = context;
+}
+
+
+
+/*!
+ Sets the background color of the scene graph to \a color.
+
+ Changing the clear color has no effect when clearing before rendering is
+ disabled.
+ */
+
+void QSGEngine::setClearColor(const QColor &color)
+{
+ d_func()->context->renderer()->setClearColor(color);
+}
+
+
+
+/*!
+ Returns the background color of the scene graph
+ */
+
+QColor QSGEngine::clearColor() const
+{
+ return d_func()->context->renderer()->clearColor();
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/scenegraph/util/qsgengine.h b/src/declarative/scenegraph/util/qsgengine.h
new file mode 100644
index 0000000000..1665d88ca3
--- /dev/null
+++ b/src/declarative/scenegraph/util/qsgengine.h
@@ -0,0 +1,100 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGENGINE_H
+#define QSGENGINE_H
+
+#include <QObject>
+
+#include <qsgtexture.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QSGEnginePrivate;
+
+class QSGContext;
+class Q_DECLARATIVE_EXPORT QSGEngine : public QObject
+{
+ Q_OBJECT
+
+ Q_DECLARE_PRIVATE(QSGEngine)
+
+public:
+
+ enum TextureOption {
+ TextureHasAlphaChannel = 0x0001,
+ TextureHasMipmaps = 0x0002,
+ TextureOwnsGLTexture = 0x0004
+ };
+ Q_DECLARE_FLAGS(TextureOptions, TextureOption)
+
+ QSGTexture *createTextureFromImage(const QImage &image) const;
+ QSGTexture *createTextureFromId(uint id, const QSize &size, TextureOptions options = TextureOption(0)) const;
+
+ void setClearBeforeRendering(bool enabled);
+ bool clearBeforeRendering() const;
+
+ void setClearColor(const QColor &color);
+ QColor clearColor() const;
+
+Q_SIGNALS:
+ void beforeRendering();
+ void afterRendering();
+
+private:
+ QSGEngine(QObject *parent = 0);
+ ~QSGEngine();
+
+ friend class QSGContext;
+ friend class QSGContextPrivate;
+ void setContext(QSGContext *context);
+
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QSGENGINE_H
diff --git a/src/declarative/scenegraph/util/qsgflatcolormaterial.cpp b/src/declarative/scenegraph/util/qsgflatcolormaterial.cpp
new file mode 100644
index 0000000000..74ff8acbe0
--- /dev/null
+++ b/src/declarative/scenegraph/util/qsgflatcolormaterial.cpp
@@ -0,0 +1,192 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgflatcolormaterial.h"
+
+#include <qglshaderprogram.h>
+
+QT_BEGIN_NAMESPACE
+
+class FlatColorMaterialShader : public QSGMaterialShader
+{
+public:
+ virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect);
+ virtual char const *const *attributeNames() const;
+
+ static QSGMaterialType type;
+
+private:
+ virtual void initialize();
+ virtual const char *vertexShader() const;
+ virtual const char *fragmentShader() const;
+
+ int m_matrix_id;
+ int m_color_id;
+};
+
+QSGMaterialType FlatColorMaterialShader::type;
+
+void FlatColorMaterialShader::updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect)
+{
+ Q_ASSERT(oldEffect == 0 || newEffect->type() == oldEffect->type());
+
+ QSGFlatColorMaterial *oldMaterial = static_cast<QSGFlatColorMaterial *>(oldEffect);
+ QSGFlatColorMaterial *newMaterial = static_cast<QSGFlatColorMaterial *>(newEffect);
+
+ const QColor &c = newMaterial->color();
+
+ if (oldMaterial == 0 || c != oldMaterial->color() || state.isOpacityDirty()) {
+ float opacity = state.opacity();
+ QVector4D v(c.redF() * c.alphaF() * opacity,
+ c.greenF() * c.alphaF() * opacity,
+ c.blueF() * c.alphaF() * opacity,
+ c.alphaF() * opacity);
+ program()->setUniformValue(m_color_id, v);
+ }
+
+ if (state.isMatrixDirty())
+ program()->setUniformValue(m_matrix_id, state.combinedMatrix());
+}
+
+char const *const *FlatColorMaterialShader::attributeNames() const
+{
+ static char const *const attr[] = { "vCoord", 0 };
+ return attr;
+}
+
+void FlatColorMaterialShader::initialize()
+{
+ m_matrix_id = program()->uniformLocation("matrix");
+ m_color_id = program()->uniformLocation("color");
+}
+
+const char *FlatColorMaterialShader::vertexShader() const {
+ return
+ "attribute highp vec4 vCoord; \n"
+ "uniform highp mat4 matrix; \n"
+ "void main() { \n"
+ " gl_Position = matrix * vCoord; \n"
+ "}";
+}
+
+const char *FlatColorMaterialShader::fragmentShader() const {
+ return
+ "uniform lowp vec4 color; \n"
+ "void main() { \n"
+ " gl_FragColor = color; \n"
+ "}";
+}
+
+
+
+/*!
+ \class QSGFlatColorMaterial
+ \brief The QSGFlatColorMaterial provides a convenient way of rendering
+ solid colored geometry in the scene graph.
+
+ The flat color material will fill every pixel in a geometry using
+ a solid color. The color can contain transparency.
+
+ The geometry to be rendered with a flat color material requires
+ vertices in attribute location 0 in the QSGGeometry object to render
+ correctly. The QSGGeometry::defaultAttributes_Point2D() returns an attribute
+ set compatible with this material.
+
+ The flat color material respects both current opacity and current matrix
+ when updating it's rendering state.
+ */
+
+
+/*!
+ Constructs a new flat color material.
+
+ The default color is white.
+ */
+
+QSGFlatColorMaterial::QSGFlatColorMaterial() : m_color(QColor(255, 255, 255))
+{
+}
+
+
+
+/*!
+ \fn QColor QSGFlatColorMaterial::color() const
+
+ Returns this flat color material's color.
+
+ The default color is white.
+ */
+
+
+
+/*!
+ Sets this flat color material's color to \a color.
+ */
+
+void QSGFlatColorMaterial::setColor(const QColor &color)
+{
+ m_color = color;
+ setFlag(Blending, m_color.alpha() != 0xff);
+}
+
+
+
+/*!
+ \internal
+ */
+
+QSGMaterialType *QSGFlatColorMaterial::type() const
+{
+ return &FlatColorMaterialShader::type;
+}
+
+
+
+/*!
+ \internal
+ */
+
+QSGMaterialShader *QSGFlatColorMaterial::createShader() const
+{
+ return new FlatColorMaterialShader;
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/scenegraph/util/qsgflatcolormaterial.h b/src/declarative/scenegraph/util/qsgflatcolormaterial.h
new file mode 100644
index 0000000000..d9a8d5973c
--- /dev/null
+++ b/src/declarative/scenegraph/util/qsgflatcolormaterial.h
@@ -0,0 +1,71 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef FLATCOLORMATERIAL_H
+#define FLATCOLORMATERIAL_H
+
+#include <qsgmaterial.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class Q_AUTOTEST_EXPORT QSGFlatColorMaterial : public QSGMaterial
+{
+public:
+ QSGFlatColorMaterial();
+ virtual QSGMaterialType *type() const;
+ virtual QSGMaterialShader *createShader() const;
+
+ void setColor(const QColor &color);
+ const QColor &color() const { return m_color; }
+
+private:
+ QColor m_color;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // FLATCOLORMATERIAL_H
diff --git a/src/declarative/scenegraph/util/qsgpainternode.cpp b/src/declarative/scenegraph/util/qsgpainternode.cpp
new file mode 100644
index 0000000000..b3f163c604
--- /dev/null
+++ b/src/declarative/scenegraph/util/qsgpainternode.cpp
@@ -0,0 +1,418 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgpainternode_p.h"
+
+#include "qsgpainteditem.h"
+#include <private/qsgcontext_p.h>
+#include <qglframebufferobject.h>
+#include <qglfunctions.h>
+#include <qmath.h>
+
+QT_BEGIN_NAMESPACE
+
+#define QT_MINIMUM_FBO_SIZE 64
+
+static inline int qt_next_power_of_two(int v)
+{
+ v--;
+ v |= v >> 1;
+ v |= v >> 2;
+ v |= v >> 4;
+ v |= v >> 8;
+ v |= v >> 16;
+ ++v;
+ return v;
+}
+
+QSGPainterTexture::QSGPainterTexture()
+ : QSGPlainTexture()
+{
+
+}
+
+void QSGPainterTexture::bind()
+{
+ if (m_dirty_rect.isNull() || m_texture_id == 0) {
+ QSGPlainTexture::bind();
+ } else {
+ glBindTexture(GL_TEXTURE_2D, m_texture_id);
+
+ QImage subImage = m_image.copy(m_dirty_rect);
+
+ int w = m_dirty_rect.width();
+ int h = m_dirty_rect.height();
+
+#ifdef QT_OPENGL_ES
+ glTexSubImage2D(GL_TEXTURE_2D, 0, m_dirty_rect.x(), m_dirty_rect.y(), w, h,
+ GL_RGBA, GL_UNSIGNED_BYTE, subImage.constBits());
+#else
+ glTexSubImage2D(GL_TEXTURE_2D, 0, m_dirty_rect.x(), m_dirty_rect.y(), w, h,
+ GL_BGRA, GL_UNSIGNED_BYTE, subImage.constBits());
+#endif
+
+ if (m_has_mipmaps && !m_mipmaps_generated) {
+ const QGLContext *ctx = QGLContext::currentContext();
+ ctx->functions()->glGenerateMipmap(GL_TEXTURE_2D);
+ m_mipmaps_generated = true;
+ }
+
+ m_dirty_texture = false;
+ m_dirty_bind_options = false;
+ }
+ m_dirty_rect = QRect();
+}
+
+QSGPainterNode::QSGPainterNode(QSGPaintedItem *item)
+ : QSGGeometryNode()
+ , m_preferredRenderTarget(QSGPaintedItem::Image)
+ , m_actualRenderTarget(QSGPaintedItem::Image)
+ , m_item(item)
+ , m_fbo(0)
+ , m_multisampledFbo(0)
+ , m_geometry(QSGGeometry::defaultAttributes_TexturedPoint2D(), 4)
+ , m_texture(0)
+ , m_size(1, 1)
+ , m_dirtyContents(false)
+ , m_opaquePainting(false)
+ , m_linear_filtering(false)
+ , m_mipmapping(false)
+ , m_smoothPainting(false)
+ , m_extensionsChecked(false)
+ , m_multisamplingSupported(false)
+ , m_fillColor(Qt::transparent)
+ , m_contentsScale(1.0)
+ , m_dirtyGeometry(false)
+ , m_dirtyRenderTarget(false)
+ , m_dirtyTexture(false)
+{
+ setMaterial(&m_materialO);
+ setOpaqueMaterial(&m_material);
+ setGeometry(&m_geometry);
+}
+
+QSGPainterNode::~QSGPainterNode()
+{
+ delete m_texture;
+ delete m_fbo;
+ delete m_multisampledFbo;
+}
+
+void QSGPainterNode::paint()
+{
+ QRect dirtyRect = m_dirtyRect.isNull() ? QRect(0, 0, m_size.width(), m_size.height()) : m_dirtyRect;
+
+ QPainter painter;
+ if (m_actualRenderTarget == QSGPaintedItem::Image)
+ painter.begin(&m_image);
+ else if (m_multisampledFbo)
+ painter.begin(m_multisampledFbo);
+ else
+ painter.begin(m_fbo);
+
+ if (m_smoothPainting) {
+ painter.setRenderHints(QPainter::Antialiasing | QPainter::HighQualityAntialiasing
+ | QPainter::TextAntialiasing | QPainter::SmoothPixmapTransform);
+ }
+
+ painter.scale(m_contentsScale, m_contentsScale);
+
+ QRect sclip(qFloor(dirtyRect.x()/m_contentsScale),
+ qFloor(dirtyRect.y()/m_contentsScale),
+ qCeil(dirtyRect.width()/m_contentsScale+dirtyRect.x()/m_contentsScale-qFloor(dirtyRect.x()/m_contentsScale)),
+ qCeil(dirtyRect.height()/m_contentsScale+dirtyRect.y()/m_contentsScale-qFloor(dirtyRect.y()/m_contentsScale)));
+
+ if (!m_dirtyRect.isNull())
+ painter.setClipRect(sclip);
+
+ painter.setCompositionMode(QPainter::CompositionMode_Source);
+ painter.fillRect(sclip, m_fillColor);
+ painter.setCompositionMode(QPainter::CompositionMode_SourceOver);
+
+ m_item->paint(&painter);
+ painter.end();
+
+ if (m_actualRenderTarget == QSGPaintedItem::Image) {
+ m_texture->setImage(m_image);
+ m_texture->setDirtyRect(dirtyRect);
+ } else if (m_multisampledFbo) {
+ QGLFramebufferObject::blitFramebuffer(m_fbo, dirtyRect, m_multisampledFbo, dirtyRect);
+ }
+
+ m_dirtyRect = QRect();
+}
+
+void QSGPainterNode::update()
+{
+ if (m_dirtyRenderTarget)
+ updateRenderTarget();
+ if (m_dirtyGeometry)
+ updateGeometry();
+ if (m_dirtyTexture)
+ updateTexture();
+
+ if (m_dirtyContents)
+ paint();
+
+ m_dirtyGeometry = false;
+ m_dirtyRenderTarget = false;
+ m_dirtyTexture = false;
+ m_dirtyContents = false;
+}
+
+void QSGPainterNode::updateTexture()
+{
+ m_texture->setHasMipmaps(m_mipmapping);
+ m_texture->setHasAlphaChannel(!m_opaquePainting);
+ m_material.setTexture(m_texture);
+ m_materialO.setTexture(m_texture);
+
+ markDirty(DirtyMaterial);
+}
+
+void QSGPainterNode::updateGeometry()
+{
+ QRectF source;
+ if (m_actualRenderTarget == QSGPaintedItem::Image)
+ source = QRectF(0, 0, 1, 1);
+ else
+ source = QRectF(0, 1, qreal(m_size.width()) / m_fboSize.width(), qreal(-m_size.height()) / m_fboSize.height());
+ QSGGeometry::updateTexturedRectGeometry(&m_geometry,
+ QRectF(0, 0, m_size.width(), m_size.height()),
+ source);
+ markDirty(DirtyGeometry);
+}
+
+void QSGPainterNode::updateRenderTarget()
+{
+ if (!m_extensionsChecked) {
+ QList<QByteArray> extensions = QByteArray((const char *)glGetString(GL_EXTENSIONS)).split(' ');
+ m_multisamplingSupported = extensions.contains("GL_EXT_framebuffer_multisample")
+ && extensions.contains("GL_EXT_framebuffer_blit");
+ m_extensionsChecked = true;
+ }
+
+ m_dirtyContents = true;
+
+ QSGPaintedItem::RenderTarget oldTarget = m_actualRenderTarget;
+ if (m_preferredRenderTarget == QSGPaintedItem::Image) {
+ m_actualRenderTarget = QSGPaintedItem::Image;
+ } else {
+ if (!m_multisamplingSupported && m_smoothPainting)
+ m_actualRenderTarget = QSGPaintedItem::Image;
+ else
+ m_actualRenderTarget = QSGPaintedItem::FramebufferObject;
+ }
+ if (oldTarget != m_actualRenderTarget) {
+ m_image = QImage();
+ delete m_fbo;
+ delete m_multisampledFbo;
+ m_fbo = m_multisampledFbo = 0;
+ }
+
+ if (m_actualRenderTarget == QSGPaintedItem::FramebufferObject) {
+ const QGLContext *ctx = QGLContext::currentContext();
+ if (m_fbo && !m_dirtyGeometry && (!ctx->format().sampleBuffers() || !m_multisamplingSupported))
+ return;
+
+ if (m_fboSize.isEmpty())
+ updateFBOSize();
+
+ delete m_fbo;
+ delete m_multisampledFbo;
+ m_fbo = m_multisampledFbo = 0;
+
+ if (m_smoothPainting && ctx->format().sampleBuffers() && m_multisamplingSupported) {
+ {
+ QGLFramebufferObjectFormat format;
+ format.setAttachment(QGLFramebufferObject::CombinedDepthStencil);
+ format.setSamples(ctx->format().samples());
+ m_multisampledFbo = new QGLFramebufferObject(m_fboSize, format);
+ }
+ {
+ QGLFramebufferObjectFormat format;
+ format.setAttachment(QGLFramebufferObject::NoAttachment);
+ m_fbo = new QGLFramebufferObject(m_fboSize, format);
+ }
+ } else {
+ QGLFramebufferObjectFormat format;
+ format.setAttachment(QGLFramebufferObject::CombinedDepthStencil);
+ m_fbo = new QGLFramebufferObject(m_fboSize, format);
+ }
+ } else {
+ if (!m_image.isNull() && !m_dirtyGeometry)
+ return;
+
+ m_image = QImage(m_size, QImage::Format_ARGB32_Premultiplied);
+ m_image.fill(Qt::transparent);
+ }
+
+ QSGPainterTexture *texture = new QSGPainterTexture;
+ if (m_actualRenderTarget == QSGPaintedItem::Image) {
+ texture->setOwnsTexture(true);
+ texture->setTextureSize(m_size);
+ } else {
+ texture->setTextureId(m_fbo->texture());
+ texture->setOwnsTexture(false);
+ texture->setTextureSize(m_fboSize);
+ }
+
+ if (m_texture)
+ delete m_texture;
+
+ texture->setTextureSize(m_size);
+ m_texture = texture;
+}
+
+void QSGPainterNode::updateFBOSize()
+{
+ int fboWidth = qMax(QT_MINIMUM_FBO_SIZE, qt_next_power_of_two(m_size.width()));
+ int fboHeight = qMax(QT_MINIMUM_FBO_SIZE, qt_next_power_of_two(m_size.height()));
+ m_fboSize = QSize(fboWidth, fboHeight);
+}
+
+void QSGPainterNode::setPreferredRenderTarget(QSGPaintedItem::RenderTarget target)
+{
+ if (m_preferredRenderTarget == target)
+ return;
+
+ m_preferredRenderTarget = target;
+
+ m_dirtyRenderTarget = true;
+ m_dirtyGeometry = true;
+ m_dirtyTexture = true;
+}
+
+void QSGPainterNode::setSize(const QSize &size)
+{
+ if (size == m_size)
+ return;
+
+ m_size = size;
+ updateFBOSize();
+
+ if (m_fbo)
+ m_dirtyRenderTarget = m_fbo->size() != m_fboSize || m_dirtyRenderTarget;
+ else
+ m_dirtyRenderTarget = true;
+ m_dirtyGeometry = true;
+ m_dirtyTexture = true;
+}
+
+void QSGPainterNode::setDirty(bool d, const QRect &dirtyRect)
+{
+ m_dirtyContents = d;
+ m_dirtyRect = dirtyRect;
+
+ if (m_mipmapping)
+ m_dirtyTexture = true;
+
+ markDirty(DirtyMaterial);
+}
+
+void QSGPainterNode::setOpaquePainting(bool opaque)
+{
+ if (opaque == m_opaquePainting)
+ return;
+
+ m_opaquePainting = opaque;
+ m_dirtyTexture = true;
+}
+
+void QSGPainterNode::setLinearFiltering(bool linearFiltering)
+{
+ if (linearFiltering == m_linear_filtering)
+ return;
+
+ m_linear_filtering = linearFiltering;
+
+ m_material.setFiltering(linearFiltering ? QSGTexture::Linear : QSGTexture::Nearest);
+ m_materialO.setFiltering(linearFiltering ? QSGTexture::Linear : QSGTexture::Nearest);
+ markDirty(DirtyMaterial);
+}
+
+void QSGPainterNode::setMipmapping(bool mipmapping)
+{
+ if (mipmapping == m_mipmapping)
+ return;
+
+ m_mipmapping = mipmapping;
+ m_material.setMipmapFiltering(mipmapping ? QSGTexture::Linear : QSGTexture::None);
+ m_materialO.setMipmapFiltering(mipmapping ? QSGTexture::Linear : QSGTexture::None);
+ m_dirtyTexture = true;
+}
+
+void QSGPainterNode::setSmoothPainting(bool s)
+{
+ if (s == m_smoothPainting)
+ return;
+
+ m_smoothPainting = s;
+ m_dirtyRenderTarget = true;
+}
+
+void QSGPainterNode::setFillColor(const QColor &c)
+{
+ if (c == m_fillColor)
+ return;
+
+ m_fillColor = c;
+ markDirty(DirtyMaterial);
+}
+
+void QSGPainterNode::setContentsScale(qreal s)
+{
+ if (s == m_contentsScale)
+ return;
+
+ m_contentsScale = s;
+ markDirty(DirtyMaterial);
+}
+
+QImage QSGPainterNode::toImage() const
+{
+ if (m_actualRenderTarget == QSGPaintedItem::Image)
+ return m_image;
+ else
+ return m_fbo->toImage();
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/scenegraph/util/qsgpainternode_p.h b/src/declarative/scenegraph/util/qsgpainternode_p.h
new file mode 100644
index 0000000000..625a0cbcb6
--- /dev/null
+++ b/src/declarative/scenegraph/util/qsgpainternode_p.h
@@ -0,0 +1,149 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGPAINTERNODE_P_H
+#define QSGPAINTERNODE_P_H
+
+#include "qsgnode.h"
+#include "qsgtexturematerial.h"
+#include "qsgtexture_p.h"
+#include "qsgpainteditem.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QGLFramebufferObject;
+
+class Q_DECLARATIVE_EXPORT QSGPainterTexture : public QSGPlainTexture
+{
+public:
+ QSGPainterTexture();
+
+ void setDirtyRect(const QRect &rect) { m_dirty_rect = rect; }
+
+ void bind();
+
+private:
+ QRect m_dirty_rect;
+};
+
+class Q_DECLARATIVE_EXPORT QSGPainterNode : public QSGGeometryNode
+{
+public:
+ QSGPainterNode(QSGPaintedItem *item);
+ virtual ~QSGPainterNode();
+
+ void setPreferredRenderTarget(QSGPaintedItem::RenderTarget target);
+
+ void setSize(const QSize &size);
+ QSize size() const { return m_size; }
+
+ void setDirty(bool d, const QRect &dirtyRect = QRect());
+
+ void setOpaquePainting(bool opaque);
+ bool opaquePainting() const { return m_opaquePainting; }
+
+ void setLinearFiltering(bool linearFiltering);
+ bool linearFiltering() const { return m_linear_filtering; }
+
+ void setMipmapping(bool mipmapping);
+ bool mipmapping() const { return m_mipmapping; }
+
+ void setSmoothPainting(bool s);
+ bool smoothPainting() const { return m_smoothPainting; }
+
+ void setFillColor(const QColor &c);
+ QColor fillColor() const { return m_fillColor; }
+
+ void setContentsScale(qreal s);
+ qreal contentsScale() const { return m_contentsScale; }
+
+ QImage toImage() const;
+ void update();
+
+ void paint();
+
+private:
+ void updateTexture();
+ void updateGeometry();
+ void updateRenderTarget();
+ void updateFBOSize();
+
+ QSGPaintedItem::RenderTarget m_preferredRenderTarget;
+ QSGPaintedItem::RenderTarget m_actualRenderTarget;
+
+ QSGPaintedItem *m_item;
+
+ QGLFramebufferObject *m_fbo;
+ QGLFramebufferObject *m_multisampledFbo;
+ QImage m_image;
+
+ QSGOpaqueTextureMaterial m_material;
+ QSGTextureMaterial m_materialO;
+ QSGGeometry m_geometry;
+ QSGPainterTexture *m_texture;
+
+ QSize m_size;
+ QSize m_fboSize;
+ bool m_dirtyContents;
+ QRect m_dirtyRect;
+ bool m_opaquePainting;
+ bool m_linear_filtering;
+ bool m_mipmapping;
+ bool m_smoothPainting;
+ bool m_extensionsChecked;
+ bool m_multisamplingSupported;
+ QColor m_fillColor;
+ qreal m_contentsScale;
+
+ bool m_dirtyGeometry;
+ bool m_dirtyRenderTarget;
+ bool m_dirtyTexture;
+};
+
+QT_END_HEADER
+
+QT_END_NAMESPACE
+
+#endif // QSGPAINTERNODE_P_H
diff --git a/src/declarative/scenegraph/util/qsgsimplerectnode.cpp b/src/declarative/scenegraph/util/qsgsimplerectnode.cpp
new file mode 100644
index 0000000000..604222dad5
--- /dev/null
+++ b/src/declarative/scenegraph/util/qsgsimplerectnode.cpp
@@ -0,0 +1,132 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgsimplerectnode.h"
+#include "qsgflatcolormaterial.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QSGSimpleRectNode
+
+ \brief The QSGSimpleRectNode class is a convenience class for drawing
+ solid filled rectangles using scenegraph.
+
+ */
+
+
+
+/*!
+ Constructs a QSGSimpleRectNode instance which is spanning \a rect with
+ the color \a color.
+ */
+QSGSimpleRectNode::QSGSimpleRectNode(const QRectF &rect, const QColor &color)
+ : m_geometry(QSGGeometry::defaultAttributes_Point2D(), 4)
+{
+ QSGGeometry::updateRectGeometry(&m_geometry, rect);
+ m_material.setColor(color);
+ setMaterial(&m_material);
+ setGeometry(&m_geometry);
+}
+
+
+
+/*!
+ Constructs a QSGSimpleRectNode instance with an empty rectangle and
+ white color.
+ */
+QSGSimpleRectNode::QSGSimpleRectNode()
+ : m_geometry(QSGGeometry::defaultAttributes_Point2D(), 4)
+{
+ QSGGeometry::updateRectGeometry(&m_geometry, QRectF());
+ setMaterial(&m_material);
+ setGeometry(&m_geometry);
+}
+
+
+
+/*!
+ Sets the rectangle of this rect node to \a rect.
+ */
+void QSGSimpleRectNode::setRect(const QRectF &rect)
+{
+ QSGGeometry::updateRectGeometry(&m_geometry, rect);
+ markDirty(QSGNode::DirtyGeometry);
+}
+
+
+
+/*!
+ Returns the rectangle that this rect node covers.
+ */
+QRectF QSGSimpleRectNode::rect() const
+{
+ const QSGGeometry::Point2D *pts = m_geometry.vertexDataAsPoint2D();
+ return QRectF(pts[0].x,
+ pts[0].y,
+ pts[3].x - pts[0].x,
+ pts[3].y - pts[0].y);
+}
+
+
+/*!
+ Sets the color of this rectangle to \a color. The default
+ color will be white.
+ */
+void QSGSimpleRectNode::setColor(const QColor &color)
+{
+ if (color != m_material.color()) {
+ m_material.setColor(color);
+ markDirty(QSGNode::DirtyMaterial);
+ }
+}
+
+
+
+/*!
+ Returns the color of this rectangle.
+ */
+QColor QSGSimpleRectNode::color() const
+{
+ return m_material.color();
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/scenegraph/util/qsgsimplerectnode.h b/src/declarative/scenegraph/util/qsgsimplerectnode.h
new file mode 100644
index 0000000000..ac001ab4eb
--- /dev/null
+++ b/src/declarative/scenegraph/util/qsgsimplerectnode.h
@@ -0,0 +1,77 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef SOLIDRECTNODE_H
+#define SOLIDRECTNODE_H
+
+#include "qsgnode.h"
+#include "qsgflatcolormaterial.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class Q_DECLARATIVE_EXPORT QSGSimpleRectNode : public QSGGeometryNode
+{
+public:
+ QSGSimpleRectNode(const QRectF &rect, const QColor &color);
+ QSGSimpleRectNode();
+
+ void setRect(const QRectF &rect);
+ inline void setRect(qreal x, qreal y, qreal w, qreal h) { setRect(QRectF(x, y, w, h)); }
+ QRectF rect() const;
+
+ void setColor(const QColor &color);
+ QColor color() const;
+
+private:
+ QSGFlatColorMaterial m_material;
+ QSGGeometry m_geometry;
+ void *reserved;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // SOLIDRECTNODE_H
diff --git a/src/declarative/scenegraph/util/qsgsimpletexturenode.cpp b/src/declarative/scenegraph/util/qsgsimpletexturenode.cpp
new file mode 100644
index 0000000000..a3c96dcd2b
--- /dev/null
+++ b/src/declarative/scenegraph/util/qsgsimpletexturenode.cpp
@@ -0,0 +1,152 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include "qsgsimpletexturenode.h"
+
+QT_BEGIN_NAMESPACE
+
+static void qsgsimpletexturenode_update(QSGGeometry *g,
+ QSGTexture *texture,
+ const QRectF &rect)
+{
+ if (!texture)
+ return;
+
+ QSize ts = texture->textureSize();
+ QRectF sourceRect(0, 0, ts.width(), ts.height());
+ QSGGeometry::updateTexturedRectGeometry(g, rect, texture->convertToNormalizedSourceRect(sourceRect));
+}
+
+/*!
+ \class QSGSimpleTextureNode
+ \brief The QSGSimpleTextureNode provided for convenience to easily draw
+ textured content using the QML scene graph.
+
+ \warning The simple texture node class must have texture before being
+ added to the scene graph to be rendered.
+*/
+
+/*!
+ Constructs a new simple texture node
+ */
+QSGSimpleTextureNode::QSGSimpleTextureNode()
+ : m_geometry(QSGGeometry::defaultAttributes_TexturedPoint2D(), 4)
+{
+ setGeometry(&m_geometry);
+ setMaterial(&m_material);
+ setOpaqueMaterial(&m_opaque_material);
+}
+
+/*!
+ Sets the filtering to be used for this texture node to \a filtering.
+
+ For smooth scaling, use QSGTexture::Linear; for normal scaling, use
+ QSGTexture::Nearest.
+ */
+void QSGSimpleTextureNode::setFiltering(QSGTexture::Filtering filtering)
+{
+ if (m_material.filtering() == filtering)
+ return;
+
+ m_material.setFiltering(filtering);
+ m_opaque_material.setFiltering(filtering);
+ markDirty(DirtyMaterial);
+}
+
+
+/*!
+ Returns the filtering currently set on this texture node
+ */
+QSGTexture::Filtering QSGSimpleTextureNode::filtering() const
+{
+ return m_material.filtering();
+}
+
+
+/*!
+ Sets the target rect of this texture node to \a r
+ */
+void QSGSimpleTextureNode::setRect(const QRectF &r)
+{
+ if (m_rect == r)
+ return;
+ m_rect = r;
+ qsgsimpletexturenode_update(&m_geometry, texture(), m_rect);
+ markDirty(DirtyGeometry);
+}
+
+
+/*!
+ Returns the target rect of this texture node.
+ */
+QRectF QSGSimpleTextureNode::rect() const
+{
+ return m_rect;
+}
+
+/*!
+ Sets the texture of this texture node to \a texture.
+
+ \warning A texture node must have a texture before being added
+ to the scenegraph to be rendered.
+ */
+void QSGSimpleTextureNode::setTexture(QSGTexture *texture)
+{
+ if (m_material.texture() == texture)
+ return;
+ m_material.setTexture(texture);
+ m_opaque_material.setTexture(texture);
+ qsgsimpletexturenode_update(&m_geometry, texture, m_rect);
+ markDirty(DirtyMaterial);
+}
+
+
+
+/*!
+ Returns the texture for this texture node
+ */
+QSGTexture *QSGSimpleTextureNode::texture() const
+{
+ return m_material.texture();
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/scenegraph/util/qsgsimpletexturenode.h b/src/declarative/scenegraph/util/qsgsimpletexturenode.h
new file mode 100644
index 0000000000..44925be881
--- /dev/null
+++ b/src/declarative/scenegraph/util/qsgsimpletexturenode.h
@@ -0,0 +1,82 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGSIMPLETEXTURENODE_H
+#define QSGSIMPLETEXTURENODE_H
+
+#include "qsgnode.h"
+#include "qsggeometry.h"
+#include "qsgtexturematerial.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class Q_DECLARATIVE_EXPORT QSGSimpleTextureNode : public QSGGeometryNode
+{
+public:
+ QSGSimpleTextureNode();
+
+ void setRect(const QRectF &rect);
+ inline void setRect(qreal x, qreal y, qreal w, qreal h) { setRect(QRectF(x, y, w, h)); }
+ QRectF rect() const;
+
+ void setTexture(QSGTexture *texture);
+ QSGTexture *texture() const;
+
+ void setFiltering(QSGTexture::Filtering filtering);
+ QSGTexture::Filtering filtering() const;
+
+private:
+ QSGGeometry m_geometry;
+ QSGOpaqueTextureMaterial m_opaque_material;
+ QSGTextureMaterial m_material;
+
+ QRectF m_rect;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QSGSIMPLETEXTURENODE_H
diff --git a/src/declarative/scenegraph/util/qsgtexture.cpp b/src/declarative/scenegraph/util/qsgtexture.cpp
new file mode 100644
index 0000000000..c82f214cc8
--- /dev/null
+++ b/src/declarative/scenegraph/util/qsgtexture.cpp
@@ -0,0 +1,415 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#define GL_GLEXT_PROTOTYPES
+
+#include <private/qsgtexture_p.h>
+#include <qglfunctions.h>
+#include <private/qsgcontext_p.h>
+#include <qthread.h>
+
+QT_BEGIN_NAMESPACE
+
+inline static bool isPowerOfTwo(int x)
+{
+ // Assumption: x >= 1
+ return x == (x & -x);
+}
+
+QSGTexturePrivate::QSGTexturePrivate()
+ : wrapChanged(false)
+ , filteringChanged(false)
+ , horizontalWrap(QSGTexture::ClampToEdge)
+ , verticalWrap(QSGTexture::ClampToEdge)
+ , mipmapMode(QSGTexture::None)
+ , filterMode(QSGTexture::Nearest)
+{
+}
+
+#ifndef QT_NO_DEBUG
+static int qt_texture_count = 0;
+
+static void qt_print_texture_count()
+{
+ qDebug("Number of leaked textures: %i", qt_texture_count);
+ qt_texture_count = -1;
+}
+#endif
+
+
+
+QSGTexture::QSGTexture()
+ : QObject(*(new QSGTexturePrivate))
+{
+#ifndef QT_NO_DEBUG
+ ++qt_texture_count;
+ static bool atexit_registered = false;
+ if (!atexit_registered) {
+ atexit(qt_print_texture_count);
+ atexit_registered = true;
+ }
+#endif
+}
+
+QSGTexture::~QSGTexture()
+{
+#ifndef QT_NO_DEBUG
+ --qt_texture_count;
+ if (qt_texture_count < 0)
+ qDebug("Material destroyed after qt_print_texture_count() was called.");
+#endif
+}
+
+
+/*!
+ \fn void QSGTexture::setImage(const QImage &image)
+
+ This function may be calld from arbitrary an arbitrary thread and may not
+ use GL calls.
+ */
+
+
+/*!
+ \fn void QSGTexture::bind()
+
+ Call this function to bind this texture to the current texture
+ target.
+
+ Binding a texture may also include uploading the texture data from
+ a previously set QImage.
+ */
+
+void QSGTexture::removeFromAtlas()
+{
+ // default textures are not in atlasses, so do nothing...
+}
+
+/*!
+ Returns weither this texture is part of an atlas or not.
+
+ The default implementation returns false.
+ */
+bool QSGTexture::isAtlasTexture() const
+{
+ return false;
+}
+
+
+/*!
+ Returns the rectangle inside textureSize() that this texture
+ represents in normalized coordinates.
+
+ The default implementation returns a rect at position (0, 0) with
+ width and height of 1.
+ */
+QRectF QSGTexture::textureSubRect() const
+{
+ return QRectF(0, 0, 1, 1);
+}
+
+/*!
+ \fn bool QSGTexture::hasMipmaps() const
+
+ Returns true if the texture data contains mipmap levels.
+ */
+
+
+/*!
+ Sets the mipmap sampling mode to be used for the upcoming bind() call to \a filter.
+
+ Setting the mipmap filtering has no effect it the texture does not have mipmaps.
+
+ \sa hasMipmaps()
+ */
+void QSGTexture::setMipmapFiltering(Filtering filter)
+{
+ Q_D(QSGTexture);
+ if (d->mipmapMode != (uint) filter) {
+ d->mipmapMode = filter;
+ d->filteringChanged = true;
+ }
+}
+
+/*!
+ Returns whether mipmapping should be used when sampling from this texture.
+ */
+QSGTexture::Filtering QSGTexture::mipmapFiltering() const
+{
+ return (QSGTexture::Filtering) d_func()->mipmapMode;
+}
+
+
+/*!
+ Sets the sampling mode to be used for the upcoming bind() call to \a filter.
+ */
+void QSGTexture::setFiltering(QSGTexture::Filtering filter)
+{
+ Q_D(QSGTexture);
+ if (d->filterMode != (uint) filter) {
+ d->filterMode = filter;
+ d->filteringChanged = true;
+ }
+}
+
+QSGTexture::Filtering QSGTexture::filtering() const
+{
+ return (QSGTexture::Filtering) d_func()->filterMode;
+}
+
+
+
+/*!
+ Sets the horizontal wrap mode to be used for the upcoming bind() call to \a hwrap
+ */
+
+void QSGTexture::setHorizontalWrapMode(WrapMode hwrap)
+{
+ Q_D(QSGTexture);
+ if ((uint) hwrap != d->horizontalWrap) {
+ d->horizontalWrap = hwrap;
+ d->wrapChanged = true;
+ }
+}
+
+QSGTexture::WrapMode QSGTexture::horizontalWrapMode() const
+{
+ return (QSGTexture::WrapMode) d_func()->horizontalWrap;
+}
+
+
+
+void QSGTexture::setVerticalWrapMode(WrapMode vwrap)
+{
+ Q_D(QSGTexture);
+ if ((uint) vwrap != d->verticalWrap) {
+ d->verticalWrap = vwrap;
+ d->wrapChanged = true;
+ }
+}
+
+QSGTexture::WrapMode QSGTexture::verticalWrapMode() const
+{
+ return (QSGTexture::WrapMode) d_func()->verticalWrap;
+}
+
+
+/*!
+ Update the texture state to match the filtering, mipmap and wrap options
+ currently set.
+
+ If \a force is true, all properties will be updated regardless of weither
+ they have changed or not.
+ */
+void QSGTexture::updateBindOptions(bool force)
+{
+ Q_D(QSGTexture);
+ if (force || d->filteringChanged) {
+ bool linear = d->filterMode == Linear;
+ GLint minFilter = linear ? GL_LINEAR : GL_NEAREST;
+ GLint magFilter = linear ? GL_LINEAR : GL_NEAREST;
+
+ if (hasMipmaps()) {
+ if (d->mipmapMode == Nearest)
+ minFilter = linear ? GL_LINEAR_MIPMAP_NEAREST : GL_NEAREST_MIPMAP_NEAREST;
+ else if (d->mipmapMode == Linear)
+ minFilter = linear ? GL_LINEAR_MIPMAP_LINEAR : GL_NEAREST_MIPMAP_LINEAR;
+ }
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, minFilter);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, magFilter);
+ d->filteringChanged = false;
+ }
+
+ if (force || d->wrapChanged) {
+#if !defined(QT_NO_DEBUG) && defined(QT_OPENGL_ES_2)
+ if (d->horizontalWrap == Repeat || d->verticalWrap == Repeat) {
+ bool npotSupported = QGLContext::currentContext()->functions()->hasOpenGLFeature(QGLFunctions::NPOTTextures);
+ QSize size = textureSize();
+ bool isNpot = !isPowerOfTwo(size.width()) || !isPowerOfTwo(size.height());
+ if (!npotSupported && isNpot)
+ qWarning("Scene Graph: This system does not support the REPEAT wrap mode for non-power-of-two textures.");
+ }
+#endif
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, d->horizontalWrap == Repeat ? GL_REPEAT : GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, d->verticalWrap == Repeat ? GL_REPEAT : GL_CLAMP_TO_EDGE);
+ d->wrapChanged = false;
+ }
+}
+
+QSGPlainTexture::QSGPlainTexture()
+ : QSGTexture()
+ , m_texture_id(0)
+ , m_has_alpha(false)
+ , m_has_mipmaps(false)
+ , m_dirty_bind_options(false)
+ , m_owns_texture(true)
+ , m_mipmaps_generated(false)
+{
+}
+
+
+QSGPlainTexture::~QSGPlainTexture()
+{
+ if (m_texture_id && m_owns_texture)
+ glDeleteTextures(1, &m_texture_id);
+}
+
+#ifdef QT_OPENGL_ES
+static void swizzleBGRAToRGBA(QImage *image)
+{
+ const int width = image->width();
+ const int height = image->height();
+ for (int i = 0; i < height; ++i) {
+ uint *p = (uint *) image->scanLine(i);
+ for (int x = 0; x < width; ++x)
+ p[x] = ((p[x] << 16) & 0xff0000) | ((p[x] >> 16) & 0xff) | (p[x] & 0xff00ff00);
+ }
+}
+#endif
+
+void QSGPlainTexture::setImage(const QImage &image)
+{
+ m_image = image.convertToFormat(QImage::Format_ARGB32_Premultiplied);
+#ifdef QT_OPENGL_ES
+ swizzleBGRAToRGBA(&m_image);
+#endif
+
+ m_texture_size = image.size();
+ m_has_alpha = image.hasAlphaChannel();
+ m_dirty_texture = true;
+ m_dirty_bind_options = true;
+ }
+
+void QSGPlainTexture::setTextureId(int id)
+{
+ if (m_texture_id && m_owns_texture)
+ glDeleteTextures(1, &m_texture_id);
+
+ m_texture_id = id;
+ m_dirty_texture = false;
+ m_dirty_bind_options = true;
+ m_image = QImage();
+ m_mipmaps_generated = false;
+}
+
+void QSGPlainTexture::setHasMipmaps(bool mm)
+{
+ m_has_mipmaps = mm;
+ m_mipmaps_generated = false;
+}
+
+
+void QSGPlainTexture::bind()
+{
+ if (!m_dirty_texture) {
+ glBindTexture(GL_TEXTURE_2D, m_texture_id);
+ if (m_has_mipmaps && !m_mipmaps_generated) {
+ const QGLContext *ctx = QGLContext::currentContext();
+ ctx->functions()->glGenerateMipmap(GL_TEXTURE_2D);
+ m_mipmaps_generated = true;
+ }
+ updateBindOptions(m_dirty_bind_options);
+ m_dirty_bind_options = false;
+ return;
+ }
+
+ m_dirty_texture = false;
+
+ if (m_texture_id && m_owns_texture)
+ glDeleteTextures(1, &m_texture_id);
+
+ if (m_image.isNull()) {
+ m_texture_id = 0;
+ m_texture_size = QSize();
+ m_has_mipmaps = false;
+ m_has_alpha = false;
+ return;
+ }
+
+ glGenTextures(1, &m_texture_id);
+ glBindTexture(GL_TEXTURE_2D, m_texture_id);
+
+ // ### TODO: check for out-of-memory situations...
+ int w = m_image.width();
+ int h = m_image.height();
+
+#ifdef QT_OPENGL_ES
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, m_image.constBits());
+#else
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_BGRA, GL_UNSIGNED_BYTE, m_image.constBits());
+#endif
+
+ if (m_has_mipmaps) {
+ const QGLContext *ctx = QGLContext::currentContext();
+ ctx->functions()->glGenerateMipmap(GL_TEXTURE_2D);
+ m_mipmaps_generated = true;
+ }
+
+ m_texture_size = QSize(w, h);
+ m_texture_rect = QRectF(0, 0, 1, 1);
+
+ updateBindOptions(m_dirty_bind_options);
+ m_dirty_bind_options = false;
+}
+
+
+/*!
+ \class QSGDynamicTexture
+ \brief The QSGDynamicTexture class serves as a baseclass for dynamically changing textures,
+ such as content that is rendered to FBO's.
+
+ To update the content of the texture, call updateTexture() explicitly. Simply calling bind()
+ will not update the texture.
+ */
+
+
+/*!
+ \fn bool QSGDynamicTexture::updateTexture()
+
+ Call this function to explicitely update the dynamic texture. Calling bind() will bind
+ the content that was previously updated.
+
+ The function returns true if the texture was changed as a resul of the update; otherwise
+ returns false.
+ */
+
+
+
+QT_END_NAMESPACE
diff --git a/src/declarative/scenegraph/util/qsgtexture.h b/src/declarative/scenegraph/util/qsgtexture.h
new file mode 100644
index 0000000000..9b95ef36ad
--- /dev/null
+++ b/src/declarative/scenegraph/util/qsgtexture.h
@@ -0,0 +1,132 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGTEXTURE_H
+#define QSGTEXTURE_H
+
+#include <QObject>
+#include <QImage>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QSGTexturePrivate;
+class Q_DECLARATIVE_EXPORT QSGTexture : public QObject
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QSGTexture)
+
+public:
+ QSGTexture();
+ ~QSGTexture();
+
+ enum WrapMode {
+ Repeat,
+ ClampToEdge
+ };
+
+ enum Filtering {
+ None,
+ Nearest,
+ Linear
+ };
+
+ virtual int textureId() const = 0;
+ virtual QSize textureSize() const = 0;
+ virtual bool hasAlphaChannel() const = 0;
+ virtual bool hasMipmaps() const = 0;
+
+ virtual QRectF textureSubRect() const;
+
+ virtual bool isAtlasTexture() const;
+ virtual void removeFromAtlas();
+
+ virtual void bind() = 0;
+ void updateBindOptions(bool force = false);
+
+ void setMipmapFiltering(Filtering filter);
+ QSGTexture::Filtering mipmapFiltering() const;
+
+ void setFiltering(Filtering filter);
+ QSGTexture::Filtering filtering() const;
+
+ void setHorizontalWrapMode(WrapMode hwrap);
+ QSGTexture::WrapMode horizontalWrapMode() const;
+
+ void setVerticalWrapMode(WrapMode vwrap);
+ QSGTexture::WrapMode verticalWrapMode() const;
+
+ inline QRectF convertToNormalizedSourceRect(const QRectF &rect) const;
+
+protected:
+ QSGTexture(QSGTexturePrivate &dd);
+};
+
+QRectF QSGTexture::convertToNormalizedSourceRect(const QRectF &rect) const
+{
+ QSize s = textureSize();
+ QRectF r = textureSubRect();
+
+ qreal sx = r.width() / s.width();
+ qreal sy = r.height() / s.height();
+
+ return QRectF(r.x() + rect.x() * sx,
+ r.y() + rect.y() * sy,
+ rect.width() * sx,
+ rect.height() * sy);
+}
+
+
+class QSGDynamicTexture : public QSGTexture
+{
+ Q_OBJECT
+public:
+ virtual bool updateTexture() = 0;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/declarative/scenegraph/util/qsgtexture_p.h b/src/declarative/scenegraph/util/qsgtexture_p.h
new file mode 100644
index 0000000000..d504732f35
--- /dev/null
+++ b/src/declarative/scenegraph/util/qsgtexture_p.h
@@ -0,0 +1,113 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGTEXTURE_P_H
+#define QSGTEXTURE_P_H
+
+#include <private/qobject_p.h>
+
+#include <QtOpenGL/qgl.h>
+
+#include "qsgtexture.h"
+#include <private/qsgcontext_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QSGTexturePrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QSGTexture);
+public:
+ QSGTexturePrivate();
+
+ uint wrapChanged : 1;
+ uint filteringChanged : 1;
+
+ uint horizontalWrap : 1;
+ uint verticalWrap : 1;
+ uint mipmapMode : 2;
+ uint filterMode : 2;
+};
+
+class Q_DECLARATIVE_EXPORT QSGPlainTexture : public QSGTexture
+{
+ Q_OBJECT
+public:
+ QSGPlainTexture();
+ virtual ~QSGPlainTexture();
+
+ void setOwnsTexture(bool owns) { m_owns_texture = owns; }
+ bool ownsTexture() const { return m_owns_texture; }
+
+ void setTextureId(int id);
+ int textureId() const { return m_texture_id; }
+
+ void setTextureSize(const QSize &size) { m_texture_size = size; }
+ QSize textureSize() const { return m_texture_size; }
+
+ void setHasAlphaChannel(bool alpha) { m_has_alpha = alpha; }
+ bool hasAlphaChannel() const { return m_has_alpha; }
+
+ void setHasMipmaps(bool mm);
+ bool hasMipmaps() const { return m_has_mipmaps; }
+
+ void setImage(const QImage &image);
+ const QImage &image() { return m_image; }
+
+ virtual void bind();
+
+protected:
+ QImage m_image;
+
+ GLuint m_texture_id;
+ QSize m_texture_size;
+ QRectF m_texture_rect;
+
+ uint m_has_alpha : 1;
+ uint m_has_mipmaps : 1;
+ uint m_dirty_texture : 1;
+ uint m_dirty_bind_options : 1;
+ uint m_owns_texture : 1;
+ uint m_mipmaps_generated : 1;
+};
+
+QT_END_NAMESPACE
+
+#endif // QSGTEXTURE_P_H
diff --git a/src/declarative/scenegraph/util/qsgtexturematerial.cpp b/src/declarative/scenegraph/util/qsgtexturematerial.cpp
new file mode 100644
index 0000000000..cdca59963c
--- /dev/null
+++ b/src/declarative/scenegraph/util/qsgtexturematerial.cpp
@@ -0,0 +1,410 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgtexturematerial_p.h"
+
+#include <QtOpenGL/qglshaderprogram.h>
+#include <QtOpenGL/qglfunctions.h>
+
+QT_BEGIN_NAMESPACE
+
+inline static bool isPowerOfTwo(int x)
+{
+ // Assumption: x >= 1
+ return x == (x & -x);
+}
+
+const char qt_scenegraph_texture_material_vertex_code[] =
+ "uniform highp mat4 qt_Matrix; \n"
+ "attribute highp vec4 qt_VertexPosition; \n"
+ "attribute highp vec2 qt_VertexTexCoord; \n"
+ "varying highp vec2 qt_TexCoord; \n"
+ "void main() { \n"
+ " qt_TexCoord = qt_VertexTexCoord; \n"
+ " gl_Position = qt_Matrix * qt_VertexPosition; \n"
+ "}";
+
+const char qt_scenegraph_texture_material_fragment[] =
+ "varying highp vec2 qt_TexCoord; \n"
+ "uniform sampler2D qt_Texture; \n"
+ "void main() { \n"
+ " gl_FragColor = texture2D(qt_Texture, qt_TexCoord);\n"
+ "}";
+
+
+const char *QSGOpaqueTextureMaterialShader::vertexShader() const
+{
+ return qt_scenegraph_texture_material_vertex_code;
+}
+
+const char *QSGOpaqueTextureMaterialShader::fragmentShader() const
+{
+ return qt_scenegraph_texture_material_fragment;
+}
+
+QSGMaterialType QSGOpaqueTextureMaterialShader::type;
+
+char const *const *QSGOpaqueTextureMaterialShader::attributeNames() const
+{
+ static char const *const attr[] = { "qt_VertexPosition", "qt_VertexTexCoord", 0 };
+ return attr;
+}
+
+void QSGOpaqueTextureMaterialShader::initialize()
+{
+ m_matrix_id = program()->uniformLocation("qt_Matrix");
+}
+
+void QSGOpaqueTextureMaterialShader::updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect)
+{
+ Q_ASSERT(oldEffect == 0 || newEffect->type() == oldEffect->type());
+ QSGOpaqueTextureMaterial *tx = static_cast<QSGOpaqueTextureMaterial *>(newEffect);
+ QSGOpaqueTextureMaterial *oldTx = static_cast<QSGOpaqueTextureMaterial *>(oldEffect);
+
+ QSGTexture *t = tx->texture();
+
+ t->setFiltering(tx->filtering());
+#ifdef QT_OPENGL_ES_2
+ bool npotSupported = state.context()->functions()->hasOpenGLFeature(QGLFunctions::NPOTTextures);
+ QSize size = t->textureSize();
+ bool isNpot = !isPowerOfTwo(size.width()) || !isPowerOfTwo(size.height());
+ if (!npotSupported && isNpot) {
+ t->setHorizontalWrapMode(QSGTexture::ClampToEdge);
+ t->setVerticalWrapMode(QSGTexture::ClampToEdge);
+ } else
+#endif
+ {
+ t->setHorizontalWrapMode(tx->horizontalWrapMode());
+ t->setVerticalWrapMode(tx->verticalWrapMode());
+ }
+ t->setMipmapFiltering(tx->mipmapFiltering());
+
+ if (oldTx == 0 || oldTx->texture()->textureId() != t->textureId())
+ t->bind();
+ else
+ t->updateBindOptions();
+
+ if (state.isMatrixDirty())
+ program()->setUniformValue(m_matrix_id, state.combinedMatrix());
+}
+
+
+/*!
+ \class QSGOpaqueTextureMaterial
+ \brief The QSGOpaqueTextureMaterial class provides a convenient way of
+ rendering textured geometry in the scene graph.
+
+ The opaque textured material will fill every pixel in a geometry with
+ the supplied texture. The material does not respect the opacity of the
+ QSGMaterialShader::RenderState, so opacity nodes in the parent chain
+ of nodes using this material, have no effect.
+
+ The geometry to be rendered with an opaque texture material requires
+ vertices in attribute location 0 and texture coordinates in attribute
+ location 1. The texture coordinate is a 2-dimensional floating-point
+ tuple. The QSGGeometry::defaultAttributes_TexturedPoint2D returns an
+ attribute set compatible with this material.
+
+ The texture to be rendered is can be set using setTexture(). How the
+ texure should be rendered can be specified using setMipmapFiltering(),
+ setFiltering(), setHorizontalWrapMode() and setVerticalWrapMode().
+ The rendering state is set on the texture instance just before it
+ is bound.
+
+ The opaque textured material respects the current matrix and the alpha
+ channel of the texture. It will disregard the accumulated opacity in
+ the scenegraph.
+
+ A texture material must have a texture set before it is used as
+ a material in the scene graph.
+ */
+
+
+
+/*!
+ Creates a new QSGOpaqueTextureMaterial.
+
+ The default mipmap filtering and filtering mode is set to
+ QSGTexture::Nearest. The default wrap modes is set to
+ QSGTexture::ClampToEdge.
+
+ */
+QSGOpaqueTextureMaterial::QSGOpaqueTextureMaterial()
+ : m_texture(0)
+ , m_filtering(QSGTexture::Nearest)
+ , m_mipmap_filtering(QSGTexture::Nearest)
+ , m_horizontal_wrap(QSGTexture::ClampToEdge)
+ , m_vertical_wrap(QSGTexture::ClampToEdge)
+{
+}
+
+
+/*!
+ \internal
+ */
+QSGMaterialType *QSGOpaqueTextureMaterial::type() const
+{
+ return &QSGOpaqueTextureMaterialShader::type;
+}
+
+/*!
+ \internal
+ */
+QSGMaterialShader *QSGOpaqueTextureMaterial::createShader() const
+{
+ return new QSGOpaqueTextureMaterialShader;
+}
+
+
+
+/*!
+ \fn QSGTexture *QSGOpaqueTextureMaterial::texture() const
+
+ Returns this texture material's texture.
+ */
+
+
+
+/*!
+ Sets the texture of this material to \a texture.
+
+ The material does not take ownership over the texture.
+ */
+
+void QSGOpaqueTextureMaterial::setTexture(QSGTexture *texture)
+{
+ m_texture = texture;
+ setFlag(Blending, m_texture ? m_texture->hasAlphaChannel() : false);
+}
+
+
+
+/*!
+ \fn void QSGOpaqueTextureMaterial::setMipmapFiltering(QSGTexture::Filtering filtering)
+
+ Sets the mipmap mode to \a filtering.
+
+ The mipmap filtering mode is set on the texture instance just before the
+ texture is bound for rendering.
+
+ If the texture does not have mipmapping support, enabling mipmapping has no
+ effect.
+ */
+
+
+
+/*!
+ \fn QSGTexture::Filtering QSGOpaqueTextureMaterial::mipmapFiltering() const
+
+ Returns this material's mipmap filtering mode.
+
+ The default mipmap mode is QSGTexture::Nearest.
+ */
+
+
+
+/*!
+ \fn void QSGOpaqueTextureMaterial::setFiltering(QSGTexture::Filtering filtering)
+
+ Sets the filtering to \a filtering.
+
+ The filtering mode is set on the texture instance just before the texture
+ is bound for rendering.
+ */
+
+
+
+/*!
+ \fn QSGTexture::Filtering filtering() const
+
+ Returns this material's filtering mode.
+
+ The default filtering is QSGTexture::Nearest.
+ */
+
+
+
+/*!
+ \fn void setHorizontalWrapMode(QSGTexture::WrapMode mode)
+
+ Sets the horizontal wrap mode to \a mode.
+
+ The horizontal wrap mode is set on the texture instance just before the texture
+ is bound for rendering.
+ */
+
+
+
+ /*!
+ \fn QSGTexture::WrapMode horizontalWrapMode() const
+
+ Returns this material's horizontal wrap mode.
+
+ The default horizontal wrap mode is QSGTexutre::ClampToEdge
+ */
+
+
+
+/*!
+ \fn void setVerticalWrapMode(QSGTexture::WrapMode mode)
+
+ Sets the vertical wrap mode to \a mode.
+
+ The vertical wrap mode is set on the texture instance just before the texture
+ is bound for rendering.
+ */
+
+
+
+ /*!
+ \fn QSGTexture::WrapMode verticalWrapMode() const
+
+ Returns this material's vertical wrap mode.
+
+ The default vertical wrap mode is QSGTexutre::ClampToEdge
+ */
+
+
+
+/*!
+ \internal
+ */
+
+int QSGOpaqueTextureMaterial::compare(const QSGMaterial *o) const
+{
+ Q_ASSERT(o && type() == o->type());
+ const QSGOpaqueTextureMaterial *other = static_cast<const QSGOpaqueTextureMaterial *>(o);
+ if (int diff = m_texture->textureId() - other->texture()->textureId())
+ return diff;
+ return int(m_filtering) - int(other->m_filtering);
+}
+
+
+
+/*!
+ \class QSGTextureMaterial
+ \brief The QSGTextureMaterial class provides a convenient way of
+ rendering textured geometry in the scene graph.
+
+ The textured material will fill every pixel in a geometry with
+ the supplied texture.
+
+ The geometry to be rendered with an opaque texture material requires
+ vertices in attribute location 0 and texture coordinates in attribute
+ location 1. The texture coordinate is a 2-dimensional floating-point
+ tuple. The QSGGeometry::defaultAttributes_TexturedPoint2D returns an
+ attribute set compatible with this material.
+
+ The texture to be rendered is set using setTexture(). How the
+ texure should be rendered can be specified using setMipmapFiltering(),
+ setFiltering(), setHorizontalWrapMode() and setVerticalWrapMode().
+ The rendering state is set on the texture instance just before it
+ is bound.
+
+ The opaque textured material respects the current matrix and the alpha
+ channel of the texture. It will disregard the accumulated opacity in
+ the scenegraph.
+
+ A texture material must have a texture set before it is used as
+ a material in the scene graph.
+ */
+
+static const char qt_scenegraph_texture_material_opacity_fragment[] =
+ "varying highp vec2 qt_TexCoord; \n"
+ "uniform sampler2D qt_Texture; \n"
+ "uniform lowp float opacity; \n"
+ "void main() { \n"
+ " gl_FragColor = texture2D(qt_Texture, qt_TexCoord) * opacity; \n"
+ "}";
+
+class QSGTextureMaterialShader : public QSGOpaqueTextureMaterialShader
+{
+public:
+ virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect);
+ virtual void initialize();
+
+ static QSGMaterialType type;
+
+protected:
+ virtual const char *fragmentShader() const { return qt_scenegraph_texture_material_opacity_fragment; }
+
+ int m_opacity_id;
+};
+QSGMaterialType QSGTextureMaterialShader::type;
+
+
+
+/*!
+ \internal
+ */
+
+QSGMaterialType *QSGTextureMaterial::type() const
+{
+ return &QSGTextureMaterialShader::type;
+}
+
+
+
+/*!
+ \internal
+ */
+
+QSGMaterialShader *QSGTextureMaterial::createShader() const
+{
+ return new QSGTextureMaterialShader;
+}
+
+void QSGTextureMaterialShader::updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect)
+{
+ Q_ASSERT(oldEffect == 0 || newEffect->type() == oldEffect->type());
+ if (state.isOpacityDirty())
+ program()->setUniformValue(m_opacity_id, state.opacity());
+
+ QSGOpaqueTextureMaterialShader::updateState(state, newEffect, oldEffect);
+}
+
+void QSGTextureMaterialShader::initialize()
+{
+ QSGOpaqueTextureMaterialShader::initialize();
+ m_opacity_id = program()->uniformLocation("opacity");
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/scenegraph/util/qsgtexturematerial.h b/src/declarative/scenegraph/util/qsgtexturematerial.h
new file mode 100644
index 0000000000..375d4849cf
--- /dev/null
+++ b/src/declarative/scenegraph/util/qsgtexturematerial.h
@@ -0,0 +1,102 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef TEXTUREMATERIAL_H
+#define TEXTUREMATERIAL_H
+
+#include "qsgmaterial.h"
+#include <qsgtexture.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+
+class Q_DECLARATIVE_EXPORT QSGOpaqueTextureMaterial : public QSGMaterial
+{
+public:
+ QSGOpaqueTextureMaterial();
+
+ virtual QSGMaterialType *type() const;
+ virtual QSGMaterialShader *createShader() const;
+ virtual int compare(const QSGMaterial *other) const;
+
+ void setTexture(QSGTexture *texture);
+ QSGTexture *texture() const { return m_texture; }
+
+ void setMipmapFiltering(QSGTexture::Filtering filtering) { m_mipmap_filtering = filtering; }
+ QSGTexture::Filtering mipmapFiltering() const { return (QSGTexture::Filtering) m_mipmap_filtering; }
+
+ void setFiltering(QSGTexture::Filtering filtering) { m_filtering = filtering; }
+ QSGTexture::Filtering filtering() const { return (QSGTexture::Filtering) m_filtering; }
+
+ void setHorizontalWrapMode(QSGTexture::WrapMode mode) { m_horizontal_wrap = mode; }
+ QSGTexture::WrapMode horizontalWrapMode() const { return (QSGTexture::WrapMode) m_horizontal_wrap; }
+
+ void setVerticalWrapMode(QSGTexture::WrapMode mode) { m_vertical_wrap = mode; }
+ QSGTexture::WrapMode verticalWrapMode() const { return (QSGTexture::WrapMode) m_vertical_wrap; }
+
+protected:
+ QSGTexture *m_texture;
+
+ uint m_filtering: 2;
+ uint m_mipmap_filtering: 2;
+ uint m_horizontal_wrap : 1;
+ uint m_vertical_wrap: 1;
+
+ uint m_reserved : 26;
+};
+
+
+class Q_DECLARATIVE_EXPORT QSGTextureMaterial : public QSGOpaqueTextureMaterial
+{
+public:
+ virtual QSGMaterialType *type() const;
+ virtual QSGMaterialShader *createShader() const;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // TEXTUREMATERIAL_H
diff --git a/src/declarative/scenegraph/util/qsgtexturematerial_p.h b/src/declarative/scenegraph/util/qsgtexturematerial_p.h
new file mode 100644
index 0000000000..3e14da525a
--- /dev/null
+++ b/src/declarative/scenegraph/util/qsgtexturematerial_p.h
@@ -0,0 +1,73 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef TEXTUREMATERIAL_P_H
+#define TEXTUREMATERIAL_P_H
+
+#include "qsgtexturematerial.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class Q_DECLARATIVE_EXPORT QSGOpaqueTextureMaterialShader : public QSGMaterialShader
+{
+public:
+ virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect);
+ virtual char const *const *attributeNames() const;
+
+ static QSGMaterialType type;
+
+protected:
+ virtual void initialize();
+ virtual const char *vertexShader() const;
+ virtual const char *fragmentShader() const;
+
+ int m_matrix_id;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QSGTEXTUREMATERIAL_P_H
diff --git a/src/declarative/scenegraph/util/qsgtextureprovider.cpp b/src/declarative/scenegraph/util/qsgtextureprovider.cpp
new file mode 100644
index 0000000000..2cae0f8f92
--- /dev/null
+++ b/src/declarative/scenegraph/util/qsgtextureprovider.cpp
@@ -0,0 +1,65 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgtextureprovider_p.h"
+
+#ifndef GL_CLAMP_TO_EDGE
+#define GL_CLAMP_TO_EDGE 0x812F
+#endif
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QSGTextureProvider
+ \brief The QSGTextureProvider class encapsulates texture based entities in QML.
+ */
+
+
+/*!
+ Convenience function for casting a QObject to a QSGTextureProvider
+ */
+QSGTextureProvider *QSGTextureProvider::from(QObject *object)
+{
+ return object ? static_cast<QSGTextureProvider *>(object->qt_metacast("QSGTextureProvider")) : 0;
+}
+
+
+QT_END_NAMESPACE
diff --git a/src/declarative/scenegraph/util/qsgtextureprovider_p.h b/src/declarative/scenegraph/util/qsgtextureprovider_p.h
new file mode 100644
index 0000000000..486e7d5882
--- /dev/null
+++ b/src/declarative/scenegraph/util/qsgtextureprovider_p.h
@@ -0,0 +1,70 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGTEXTUREPROVIDER_H
+#define QSGTEXTUREPROVIDER_H
+
+#include <qgl.h>
+
+#include "qsgtexture.h"
+#include "qobject.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QSGTextureProvider
+{
+public:
+ virtual QSGTexture *texture() const = 0;
+ virtual const char *textureChangedSignal() const { return 0; }
+
+ static QSGTextureProvider *from(QObject *object);
+};
+Q_DECLARE_INTERFACE(QSGTextureProvider, "QSGTextureProvider")
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/declarative/scenegraph/util/qsgvertexcolormaterial.cpp b/src/declarative/scenegraph/util/qsgvertexcolormaterial.cpp
new file mode 100644
index 0000000000..033de1f73e
--- /dev/null
+++ b/src/declarative/scenegraph/util/qsgvertexcolormaterial.cpp
@@ -0,0 +1,171 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgvertexcolormaterial_p.h"
+
+#include <qglshaderprogram.h>
+
+QT_BEGIN_NAMESPACE
+
+class QSGVertexColorMaterialShader : public QSGMaterialShader
+{
+public:
+ virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect);
+ virtual char const *const *attributeNames() const;
+
+ static QSGMaterialType type;
+
+private:
+ virtual void initialize();
+ virtual const char *vertexShader() const;
+ virtual const char *fragmentShader() const;
+
+ int m_matrix_id;
+ int m_opacity_id;
+};
+
+QSGMaterialType QSGVertexColorMaterialShader::type;
+
+void QSGVertexColorMaterialShader::updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *)
+{
+ if (!(newEffect->flags() & QSGMaterial::Blending) || state.isOpacityDirty())
+ program()->setUniformValue(m_opacity_id, state.opacity());
+
+ if (state.isMatrixDirty())
+ program()->setUniformValue(m_matrix_id, state.combinedMatrix());
+}
+
+char const *const *QSGVertexColorMaterialShader::attributeNames() const
+{
+ static const char *const attr[] = { "vertexCoord", "vertexColor", 0 };
+ return attr;
+}
+
+void QSGVertexColorMaterialShader::initialize()
+{
+ m_matrix_id = program()->uniformLocation("matrix");
+ m_opacity_id = program()->uniformLocation("opacity");
+}
+
+const char *QSGVertexColorMaterialShader::vertexShader() const {
+ return
+ "attribute highp vec4 vertexCoord; \n"
+ "attribute highp vec4 vertexColor; \n"
+ "uniform highp mat4 matrix; \n"
+ "uniform highp float opacity; \n"
+ "varying lowp vec4 color; \n"
+ "void main() { \n"
+ " gl_Position = matrix * vertexCoord; \n"
+ " color = vertexColor * opacity; \n"
+ "}";
+}
+
+const char *QSGVertexColorMaterialShader::fragmentShader() const {
+ return
+ "varying lowp vec4 color; \n"
+ "void main() { \n"
+ " gl_FragColor = color; \n"
+ "}";
+}
+
+
+
+/*!
+ \class QSGVertexColorMaterial
+ \brief The QSGVertexColorMaterial provides a convenient way of rendering per-vertex
+ colored geometry in the scene graph.
+
+ The vertex color material will give each vertex in a geometry a color. Pixels between
+ vertices will be linearly interpolated. The colors can contain transparency.
+
+ The geometry to be rendered with vertex color must have the following layout. Attribute
+ position 0 must contain vertices. Attribute position 1 must contain colors, a tuple of
+ 4 values with RGBA layout. Both floats in the range of 0 to 1 and unsigned bytes in
+ the range 0 to 255 are valid for the color values. The
+ QSGGeometry::defaultAttributes_ColoredPoint2D() constructs an attribute set
+ compatible with this material.
+
+ The vertex color material respets both current opacity and current matrix when
+ updating it's rendering state.
+ */
+
+
+QSGVertexColorMaterial::QSGVertexColorMaterial()
+{
+ setFlag(Blending, true);
+}
+
+
+
+/*!
+ Sets if the renderer should treat colors as opaque.
+
+ Setting this flag can in some cases improve performance.
+ */
+
+void QSGVertexColorMaterial::setColorsAreOpaque(bool opaqueHint)
+{
+ setFlag(Blending, !opaqueHint);
+}
+
+
+
+/*!
+ \internal
+ */
+
+QSGMaterialType *QSGVertexColorMaterial::type() const
+{
+ return &QSGVertexColorMaterialShader::type;
+}
+
+
+
+/*!
+ \internal
+ */
+
+QSGMaterialShader *QSGVertexColorMaterial::createShader() const
+{
+ return new QSGVertexColorMaterialShader;
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/scenegraph/util/qsgvertexcolormaterial_p.h b/src/declarative/scenegraph/util/qsgvertexcolormaterial_p.h
new file mode 100644
index 0000000000..7f05537986
--- /dev/null
+++ b/src/declarative/scenegraph/util/qsgvertexcolormaterial_p.h
@@ -0,0 +1,69 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef VERTEXCOLORMATERIAL_H
+#define VERTEXCOLORMATERIAL_H
+
+#include <qsgmaterial.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QSGVertexColorMaterial : public QSGMaterial
+{
+public:
+ QSGVertexColorMaterial();
+
+ void setColorsAreOpaque(bool opaqueHint);
+
+protected:
+ virtual QSGMaterialType *type() const;
+ virtual QSGMaterialShader *createShader() const;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // VERTEXCOLORMATERIAL_H
diff --git a/src/declarative/util/qdeclarativepixmapcache.cpp b/src/declarative/util/qdeclarativepixmapcache.cpp
index 07d39774b3..194dc70e10 100644
--- a/src/declarative/util/qdeclarativepixmapcache.cpp
+++ b/src/declarative/util/qdeclarativepixmapcache.cpp
@@ -47,6 +47,10 @@
#include <private/qdeclarativeglobal_p.h>
#include <private/qdeclarativeengine_p.h>
+#include <qsgtexture.h>
+#include <private/qsgtexture_p.h>
+#include <private/qsgcontext_p.h>
+
#include <QCoreApplication>
#include <QImageReader>
#include <QHash>
@@ -75,7 +79,7 @@ QT_BEGIN_NAMESPACE
#if defined(Q_WS_QWS) || defined(Q_WS_WINCE)
static int cache_limit = 2048 * 1024; // 2048 KB cache limit for embedded
#else
-static int cache_limit = 10240 * 1024; // 10 MB cache limit for desktop
+static int cache_limit = 128 * 1024; // 10 MB cache limit for desktop
#endif
class QDeclarativePixmapReader;
@@ -98,14 +102,18 @@ public:
class Event : public QEvent {
public:
- Event(ReadError, const QString &, const QSize &, const QImage &);
+ Event(ReadError, const QString &, const QSize &, const QImage &image);
+ Event(ReadError, const QString &, const QSize &, QSGTexture *t, QSGContext *context, const QImage &image);
ReadError error;
QString errorString;
QSize implicitSize;
QImage image;
+ QSGTexture *texture;
+ QSGContext *context;
};
void postReply(ReadError, const QString &, const QSize &, const QImage &);
+ void postReply(ReadError, const QString &, const QSize &, QSGTexture *t, QSGContext *context, const QImage &image);
Q_SIGNALS:
@@ -184,32 +192,46 @@ class QDeclarativePixmapData
public:
QDeclarativePixmapData(const QUrl &u, const QSize &s, const QString &e)
: refCount(1), inCache(false), pixmapStatus(QDeclarativePixmap::Error),
- url(u), errorString(e), requestSize(s), reply(0), prevUnreferenced(0),
+ url(u), errorString(e), requestSize(s), texture(0), context(0), reply(0), prevUnreferenced(0),
prevUnreferencedPtr(0), nextUnreferenced(0)
{
}
QDeclarativePixmapData(const QUrl &u, const QSize &r)
: refCount(1), inCache(false), pixmapStatus(QDeclarativePixmap::Loading),
- url(u), requestSize(r), reply(0), prevUnreferenced(0), prevUnreferencedPtr(0),
+ url(u), requestSize(r), texture(0), context(0), reply(0), prevUnreferenced(0), prevUnreferencedPtr(0),
nextUnreferenced(0)
{
}
QDeclarativePixmapData(const QUrl &u, const QPixmap &p, const QSize &s, const QSize &r)
- : refCount(1), inCache(false), privatePixmap(false), pixmapStatus(QDeclarativePixmap::Ready),
- url(u), pixmap(p), implicitSize(s), requestSize(r), reply(0), prevUnreferenced(0),
+ : refCount(1), inCache(false), privatePixmap(false), pixmapStatus(QDeclarativePixmap::Ready),
+ url(u), pixmap(p), implicitSize(s), requestSize(r), texture(0), context(0), reply(0), prevUnreferenced(0),
+ prevUnreferencedPtr(0), nextUnreferenced(0)
+ {
+ }
+
+ QDeclarativePixmapData(const QUrl &u, QSGTexture *t, QSGContext *c, const QPixmap &p, const QSize &s, const QSize &r)
+ : refCount(1), inCache(false), privatePixmap(false), pixmapStatus(QDeclarativePixmap::Ready),
+ url(u), pixmap(p), implicitSize(s), requestSize(r), texture(t), context(c), reply(0), prevUnreferenced(0),
prevUnreferencedPtr(0), nextUnreferenced(0)
{
}
QDeclarativePixmapData(const QPixmap &p)
: refCount(1), inCache(false), privatePixmap(true), pixmapStatus(QDeclarativePixmap::Ready),
- pixmap(p), implicitSize(p.size()), requestSize(p.size()), reply(0), prevUnreferenced(0),
+ pixmap(p), implicitSize(p.size()), requestSize(p.size()), texture(0), context(0), reply(0), prevUnreferenced(0),
prevUnreferencedPtr(0), nextUnreferenced(0)
{
}
+ ~QDeclarativePixmapData()
+ {
+ if (texture && context) {
+ context->scheduleTextureForCleanup(texture);
+ }
+ }
+
int cost() const;
void addref();
void release();
@@ -228,6 +250,9 @@ public:
QSize implicitSize;
QSize requestSize;
+ QSGTexture *texture;
+ QSGContext *context;
+
QDeclarativePixmapReply *reply;
QDeclarativePixmapData *prevUnreferenced;
@@ -248,15 +273,28 @@ int QDeclarativePixmapReader::downloadProgress = -1;
int QDeclarativePixmapReader::threadNetworkRequestDone = -1;
-void QDeclarativePixmapReply::postReply(ReadError error, const QString &errorString,
+void QDeclarativePixmapReply::postReply(ReadError error, const QString &errorString,
const QSize &implicitSize, const QImage &image)
{
loading = false;
QCoreApplication::postEvent(this, new Event(error, errorString, implicitSize, image));
}
+void QDeclarativePixmapReply::postReply(ReadError error, const QString &errorString,
+ const QSize &implicitSize, QSGTexture *texture,
+ QSGContext *context, const QImage &image)
+{
+ loading = false;
+ QCoreApplication::postEvent(this, new Event(error, errorString, implicitSize, texture, context, image));
+}
+
QDeclarativePixmapReply::Event::Event(ReadError e, const QString &s, const QSize &iSize, const QImage &i)
-: QEvent(QEvent::User), error(e), errorString(s), implicitSize(iSize), image(i)
+ : QEvent(QEvent::User), error(e), errorString(s), implicitSize(iSize), image(i), texture(0), context(0)
+{
+}
+
+QDeclarativePixmapReply::Event::Event(ReadError e, const QString &s, const QSize &iSize, QSGTexture *t, QSGContext *c, const QImage &i)
+ : QEvent(QEvent::User), error(e), errorString(s), implicitSize(iSize), image(i), texture(t), context(c)
{
}
@@ -355,6 +393,8 @@ void QDeclarativePixmapReader::networkRequestDone(QNetworkReply *reply)
}
QImage image;
+ QSGTexture *texture = 0;
+ QSGContext *ctx = QDeclarativeEnginePrivate::get(engine)->sgContext;
QDeclarativePixmapReply::ReadError error = QDeclarativePixmapReply::NoError;
QString errorString;
QSize readSize;
@@ -365,13 +405,26 @@ void QDeclarativePixmapReader::networkRequestDone(QNetworkReply *reply)
QByteArray all = reply->readAll();
QBuffer buff(&all);
buff.open(QIODevice::ReadOnly);
- if (!readImage(reply->url(), &buff, &image, &errorString, &readSize, job->requestSize)) {
- error = QDeclarativePixmapReply::Decoding;
+ if (ctx && ctx->canDecodeImageToTexture())
+ texture = ctx->decodeImageToTexture(&buff, &readSize, job->requestSize);
+ if (!texture) {
+ if (!readImage(reply->url(), &buff, &image, &errorString, &readSize, job->requestSize)) {
+ error = QDeclarativePixmapReply::Decoding;
+ } else if (ctx) {
+ texture = ctx->createTexture(image);
+ }
}
}
// send completion event to the QDeclarativePixmapReply
mutex.lock();
- if (!cancelled.contains(job)) job->postReply(error, errorString, readSize, image);
+ if (!cancelled.contains(job)) {
+ if (texture)
+ job->postReply(error, errorString, readSize, texture, ctx, image);
+ else
+ job->postReply(error, errorString, readSize, image);
+ } else {
+ delete texture;
+ }
mutex.unlock();
}
reply->deleteLater();
@@ -446,23 +499,57 @@ void QDeclarativePixmapReader::processJobs()
void QDeclarativePixmapReader::processJob(QDeclarativePixmapReply *runningJob, const QUrl &url,
const QSize &requestSize)
{
+ QSGContext *sgContext = QDeclarativeEnginePrivate::get(engine)->sgContext;
+
// fetch
if (url.scheme() == QLatin1String("image")) {
// Use QmlImageProvider
QSize readSize;
QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
- QImage image = ep->getImageFromProvider(url, &readSize, requestSize);
+ QDeclarativeImageProvider::ImageType imageType = ep->getImageProviderType(url);
+ if (imageType == QDeclarativeImageProvider::Invalid) {
+ QDeclarativePixmapReply::ReadError errorCode = QDeclarativePixmapReply::Loading;
+ QString errorStr = QDeclarativePixmap::tr("Invalid image provider: %1").arg(url.toString());
+ QImage image;
+ mutex.lock();
+ if (!cancelled.contains(runningJob)) {
+ if (sgContext)
+ runningJob->postReply(errorCode, errorStr, readSize, sgContext->createTexture(image), sgContext, image);
+ else
+ runningJob->postReply(errorCode, errorStr, readSize, image);
+ }
+ mutex.unlock();
+ } else if (imageType == QDeclarativeImageProvider::Image) {
+ QImage image = ep->getImageFromProvider(url, &readSize, requestSize);
+ QDeclarativePixmapReply::ReadError errorCode = QDeclarativePixmapReply::NoError;
+ QString errorStr;
+ if (image.isNull()) {
+ errorCode = QDeclarativePixmapReply::Loading;
+ errorStr = QDeclarativePixmap::tr("Failed to get image from provider: %1").arg(url.toString());
+ }
+ mutex.lock();
+ if (!cancelled.contains(runningJob)) {
+ if (sgContext)
+ runningJob->postReply(errorCode, errorStr, readSize, sgContext->createTexture(image), sgContext, image);
+ else
+ runningJob->postReply(errorCode, errorStr, readSize, image);
+ }
+ mutex.unlock();
+ } else {
+ QSGTexture *t = ep->getTextureFromProvider(url, &readSize, requestSize);
+ QDeclarativePixmapReply::ReadError errorCode = QDeclarativePixmapReply::NoError;
+ QString errorStr;
+ if (!t) {
+ errorCode = QDeclarativePixmapReply::Loading;
+ errorStr = QDeclarativePixmap::tr("Failed to get texture from provider: %1").arg(url.toString());
+ }
+ mutex.lock();
+ if (!cancelled.contains(runningJob))
+ runningJob->postReply(errorCode, errorStr, readSize, t, sgContext, QImage());
+ mutex.unlock();
- QDeclarativePixmapReply::ReadError errorCode = QDeclarativePixmapReply::NoError;
- QString errorStr;
- if (image.isNull()) {
- errorCode = QDeclarativePixmapReply::Loading;
- errorStr = QDeclarativePixmap::tr("Failed to get image from provider: %1").arg(url.toString());
}
- mutex.lock();
- if (!cancelled.contains(runningJob)) runningJob->postReply(errorCode, errorStr, readSize, image);
- mutex.unlock();
} else {
QString lf = QDeclarativeEnginePrivate::urlToLocalFileOrQrc(url);
if (!lf.isEmpty()) {
@@ -472,15 +559,30 @@ void QDeclarativePixmapReader::processJob(QDeclarativePixmapReply *runningJob, c
QString errorStr;
QFile f(lf);
QSize readSize;
+ QSGTexture *texture = 0;
if (f.open(QIODevice::ReadOnly)) {
- if (!readImage(url, &f, &image, &errorStr, &readSize, requestSize))
- errorCode = QDeclarativePixmapReply::Loading;
+ if (sgContext && sgContext ->canDecodeImageToTexture())
+ texture = sgContext->decodeImageToTexture(&f, &readSize, requestSize);
+ if (!texture) {
+ if (!readImage(url, &f, &image, &errorStr, &readSize, requestSize)) {
+ errorCode = QDeclarativePixmapReply::Loading;
+ } else if (sgContext) {
+ texture = sgContext->createTexture(image);
+ }
+ }
} else {
errorStr = QDeclarativePixmap::tr("Cannot open: %1").arg(url.toString());
errorCode = QDeclarativePixmapReply::Loading;
}
mutex.lock();
- if (!cancelled.contains(runningJob)) runningJob->postReply(errorCode, errorStr, readSize, image);
+ if (!cancelled.contains(runningJob)) {
+ if (texture)
+ runningJob->postReply(errorCode, errorStr, readSize, texture, sgContext, image);
+ else
+ runningJob->postReply(errorCode, errorStr, readSize, image);
+ } else {
+ delete texture;
+ }
mutex.unlock();
} else {
// Network resource
@@ -576,6 +678,8 @@ inline uint qHash(const QDeclarativePixmapKey &key)
return qHash(*key.url) ^ key.size->width() ^ key.size->height();
}
+class QSGContext;
+
class QDeclarativePixmapStore : public QObject
{
Q_OBJECT
@@ -591,6 +695,9 @@ protected:
public:
QHash<QDeclarativePixmapKey, QDeclarativePixmapData *> m_cache;
+ void cleanTexturesForContext(QSGContext *context);
+ void cleanTextureForContext(QDeclarativePixmapData *data);
+
private:
void shrinkCache(int remove);
@@ -602,11 +709,52 @@ private:
};
Q_GLOBAL_STATIC(QDeclarativePixmapStore, pixmapStore);
+
+void qt_declarative_pixmapstore_clean(QSGContext *context)
+{
+ pixmapStore()->cleanTexturesForContext(context);
+}
+
+
QDeclarativePixmapStore::QDeclarativePixmapStore()
: m_unreferencedPixmaps(0), m_lastUnreferencedPixmap(0), m_unreferencedCost(0), m_timerId(-1)
{
}
+void QDeclarativePixmapStore::cleanTextureForContext(QDeclarativePixmapData *data)
+{
+ if (data->context) {
+ Q_ASSERT(QGLContext::currentContext());
+ delete data->texture;
+ data->context = 0;
+ data->texture = 0;
+ }
+}
+
+void QDeclarativePixmapStore::cleanTexturesForContext(QSGContext *context)
+{
+ QDeclarativePixmapData *data = m_unreferencedPixmaps;
+ while (data) {
+ if (data->context == context)
+ cleanTextureForContext(data);
+ if (data == m_lastUnreferencedPixmap)
+ break;
+ data = data->nextUnreferenced;
+ }
+
+ QHash<QDeclarativePixmapKey, QDeclarativePixmapData *>::iterator it = m_cache.begin();
+ while (it != m_cache.end()) {
+ data = *it;
+ if (data->context == context) {
+ cleanTextureForContext(data);
+ }
+ ++it;
+ }
+
+}
+
+
+
void QDeclarativePixmapStore::unreferencePixmap(QDeclarativePixmapData *data)
{
Q_ASSERT(data->prevUnreferenced == 0);
@@ -702,9 +850,13 @@ bool QDeclarativePixmapReply::event(QEvent *event)
if (data) {
Event *de = static_cast<Event *>(event);
data->pixmapStatus = (de->error == NoError) ? QDeclarativePixmap::Ready : QDeclarativePixmap::Error;
-
+
if (data->pixmapStatus == QDeclarativePixmap::Ready) {
- data->pixmap = QPixmap::fromImage(de->image);
+ if (de->texture) {
+ data->texture = de->texture;
+ data->context = de->context;
+ } else
+ data->pixmap = QPixmap::fromImage(de->image);
data->implicitSize = de->implicitSize;
} else {
data->errorString = de->errorString;
@@ -724,6 +876,10 @@ bool QDeclarativePixmapReply::event(QEvent *event)
int QDeclarativePixmapData::cost() const
{
+ if (texture) {
+ const QSize textureSize = texture->textureSize();
+ return textureSize.width() * textureSize.height();
+ }
return (pixmap.width() * pixmap.height() * pixmap.depth()) / 8;
}
@@ -774,17 +930,35 @@ void QDeclarativePixmapData::removeFromCache()
static QDeclarativePixmapData* createPixmapDataSync(QDeclarativeEngine *engine, const QUrl &url, const QSize &requestSize, bool *ok)
{
+ QSGContext *sgContext = QDeclarativeEnginePrivate::get(engine)->sgContext;
+
if (url.scheme() == QLatin1String("image")) {
QSize readSize;
QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
QDeclarativeImageProvider::ImageType imageType = ep->getImageProviderType(url);
switch (imageType) {
+ case QDeclarativeImageProvider::Invalid:
+ return new QDeclarativePixmapData(url, requestSize,
+ QDeclarativePixmap::tr("Invalid image provider: %1").arg(url.toString()));
+ case QDeclarativeImageProvider::Texture:
+ {
+ QSGTexture *texture = ep->getTextureFromProvider(url, &readSize, requestSize);
+ if (texture) {
+ *ok = true;
+ return new QDeclarativePixmapData(url, texture, sgContext, QPixmap(), readSize, requestSize);
+ }
+ }
+
case QDeclarativeImageProvider::Image:
{
QImage image = ep->getImageFromProvider(url, &readSize, requestSize);
if (!image.isNull()) {
*ok = true;
+ if (sgContext) {
+ QSGTexture *t = sgContext->createTexture(image);
+ return new QDeclarativePixmapData(url, t, sgContext, QPixmap::fromImage(image), readSize, requestSize);
+ }
return new QDeclarativePixmapData(url, QPixmap::fromImage(image), readSize, requestSize);
}
}
@@ -793,12 +967,16 @@ static QDeclarativePixmapData* createPixmapDataSync(QDeclarativeEngine *engine,
QPixmap pixmap = ep->getPixmapFromProvider(url, &readSize, requestSize);
if (!pixmap.isNull()) {
*ok = true;
+ if (sgContext) {
+ QSGTexture *t = sgContext->createTexture(pixmap.toImage());
+ return new QDeclarativePixmapData(url, t, sgContext, pixmap, readSize, requestSize);
+ }
return new QDeclarativePixmapData(url, pixmap, readSize, requestSize);
}
}
}
- // no matching provider, or provider has bad image type, or provider returned null image
+ // provider has bad image type, or provider returned null image
return new QDeclarativePixmapData(url, requestSize,
QDeclarativePixmap::tr("Failed to get image from provider: %1").arg(url.toString()));
}
@@ -812,11 +990,29 @@ static QDeclarativePixmapData* createPixmapDataSync(QDeclarativeEngine *engine,
QString errorString;
if (f.open(QIODevice::ReadOnly)) {
+ QSGContext *ctx = QDeclarativeEnginePrivate::get(engine)->sgContext;
+ QSGTexture *texture = 0;
QImage image;
- if (readImage(url, &f, &image, &errorString, &readSize, requestSize)) {
+
+ if (ctx && ctx->canDecodeImageToTexture()) {
+ texture = ctx->decodeImageToTexture(&f, &readSize, requestSize);
*ok = true;
- return new QDeclarativePixmapData(url, QPixmap::fromImage(image), readSize, requestSize);
}
+
+ if (!texture) {
+ if (readImage(url, &f, &image, &errorString, &readSize, requestSize))
+ *ok = true;
+
+ if (ok && ctx) {
+ texture = ctx->createTexture(image);
+ }
+ }
+
+ if (texture)
+ return new QDeclarativePixmapData(url, texture, ctx, QPixmap::fromImage(image), readSize, requestSize);
+ else
+ return new QDeclarativePixmapData(url, QPixmap::fromImage(image), readSize, requestSize);
+
} else {
errorString = QDeclarativePixmap::tr("Cannot open: %1").arg(url.toString());
}
@@ -916,6 +1112,19 @@ const QSize &QDeclarativePixmap::requestSize() const
return nullPixmap()->size;
}
+QSGTexture *QDeclarativePixmap::texture(QSGContext *context) const
+{
+ if (d) {
+ if (d->texture)
+ return d->texture;
+ else if (d->pixmapStatus == Ready) {
+ d->texture = context->createTexture(d->pixmap.toImage());
+ return d->texture;
+ }
+ }
+ return 0;
+}
+
const QPixmap &QDeclarativePixmap::pixmap() const
{
if (d)
@@ -935,7 +1144,7 @@ void QDeclarativePixmap::setPixmap(const QPixmap &p)
int QDeclarativePixmap::width() const
{
if (d)
- return d->pixmap.width();
+ return d->texture ? d->texture->textureSize().width() : d->pixmap.width();
else
return 0;
}
@@ -943,7 +1152,7 @@ int QDeclarativePixmap::width() const
int QDeclarativePixmap::height() const
{
if (d)
- return d->pixmap.height();
+ return d->texture? d->texture->textureSize().height() : d->pixmap.height();
else
return 0;
}
@@ -951,7 +1160,7 @@ int QDeclarativePixmap::height() const
QRect QDeclarativePixmap::rect() const
{
if (d)
- return d->pixmap.rect();
+ return d->texture ? QRect(QPoint(), d->texture->textureSize()) : d->pixmap.rect();
else
return QRect();
}
diff --git a/src/declarative/util/qdeclarativepixmapcache_p.h b/src/declarative/util/qdeclarativepixmapcache_p.h
index 396c1963a3..c1256d78f5 100644
--- a/src/declarative/util/qdeclarativepixmapcache_p.h
+++ b/src/declarative/util/qdeclarativepixmapcache_p.h
@@ -55,6 +55,9 @@ QT_MODULE(Declarative)
class QDeclarativeEngine;
class QDeclarativePixmapData;
+class QSGTexture;
+class QSGContext;
+
class Q_DECLARATIVE_EXPORT QDeclarativePixmap
{
Q_DECLARE_TR_FUNCTIONS(QDeclarativePixmap)
@@ -85,6 +88,8 @@ public:
const QPixmap &pixmap() const;
void setPixmap(const QPixmap &);
+ QSGTexture *texture(QSGContext *context) const;
+
QRect rect() const;
int width() const;
int height() const;
diff --git a/src/declarative/util/qdeclarativeview.h b/src/declarative/util/qdeclarativeview.h
index b3854fc94c..6959d246e4 100644
--- a/src/declarative/util/qdeclarativeview.h
+++ b/src/declarative/util/qdeclarativeview.h
@@ -73,7 +73,6 @@ public:
virtual ~QDeclarativeView();
QUrl source() const;
- void setSource(const QUrl&);
QDeclarativeEngine* engine() const;
QDeclarativeContext* rootContext() const;
@@ -92,6 +91,9 @@ public:
QSize sizeHint() const;
QSize initialSize() const;
+public Q_SLOTS:
+ void setSource(const QUrl&);
+
Q_SIGNALS:
void sceneResized(QSize size); // ???
void statusChanged(QDeclarativeView::Status);