Add missing QT_{BEGIN,END}_NAMESPACE
[profile/ivi/qtdeclarative.git] / src / qml / qml / qqmlpropertycache.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the QtQml module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
16 **
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
20 **
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
28 **
29 ** Other Usage
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qqmlpropertycache_p.h"
43
44 #include "qqmlengine_p.h"
45 #include "qqmlbinding_p.h"
46 #include <private/qv8engine_p.h>
47
48 #include <private/qmetaobject_p.h>
49 #include <private/qqmlaccessors_p.h>
50 #include <private/qmetaobjectbuilder_p.h>
51
52 #include <QtCore/qdebug.h>
53
54 #include <ctype.h> // for toupper
55
56 #ifdef Q_CC_MSVC
57 // nonstandard extension used : zero-sized array in struct/union.
58 #  pragma warning( disable : 4200 )
59 #endif
60
61 Q_DECLARE_METATYPE(QJSValue)
62 Q_DECLARE_METATYPE(QQmlV8Handle);
63
64 QT_BEGIN_NAMESPACE
65
66 #define Q_INT16_MAX 32767
67
68 class QQmlPropertyCacheMethodArguments
69 {
70 public:
71     QQmlPropertyCacheMethodArguments *next;
72
73     QList<QByteArray> *names;
74     int arguments[0];
75 };
76
77 // Flags that do *NOT* depend on the property's QMetaProperty::userType() and thus are quick
78 // to load
79 static QQmlPropertyData::Flags fastFlagsForProperty(const QMetaProperty &p)
80 {
81     QQmlPropertyData::Flags flags;
82
83     if (p.isConstant())
84         flags |= QQmlPropertyData::IsConstant;
85     if (p.isWritable())
86         flags |= QQmlPropertyData::IsWritable;
87     if (p.isResettable())
88         flags |= QQmlPropertyData::IsResettable;
89     if (p.isFinal())
90         flags |= QQmlPropertyData::IsFinal;
91     if (p.isEnumType())
92         flags |= QQmlPropertyData::IsEnumType;
93
94     return flags;
95 }
96
97 // Flags that do depend on the property's QMetaProperty::userType() and thus are slow to
98 // load
99 static QQmlPropertyData::Flags flagsForPropertyType(int propType, QQmlEngine *engine)
100 {
101     Q_ASSERT(propType != -1);
102
103     QQmlPropertyData::Flags flags;
104
105     if (propType == QMetaType::QObjectStar) {
106         flags |= QQmlPropertyData::IsQObjectDerived;
107     } else if (propType == QMetaType::QVariant) {
108         flags |= QQmlPropertyData::IsQVariant;
109     } else if (propType < (int)QVariant::UserType) {
110     } else if (propType == qMetaTypeId<QQmlBinding *>()) {
111         flags |= QQmlPropertyData::IsQmlBinding;
112     } else if (propType == qMetaTypeId<QJSValue>()) {
113         flags |= QQmlPropertyData::IsQJSValue;
114     } else if (propType == qMetaTypeId<QQmlV8Handle>()) {
115         flags |= QQmlPropertyData::IsV8Handle;
116     } else {
117         QQmlMetaType::TypeCategory cat =
118             engine ? QQmlEnginePrivate::get(engine)->typeCategory(propType)
119                    : QQmlMetaType::typeCategory(propType);
120
121         if (cat == QQmlMetaType::Object)
122             flags |= QQmlPropertyData::IsQObjectDerived;
123         else if (cat == QQmlMetaType::List)
124             flags |= QQmlPropertyData::IsQList;
125     }
126
127     return flags;
128 }
129
130 static int metaObjectSignalCount(const QMetaObject *metaObject)
131 {
132     int signalCount = 0;
133     for (const QMetaObject *obj = metaObject; obj; obj = obj->superClass())
134         signalCount += QMetaObjectPrivate::get(obj)->signalCount;
135     return signalCount;
136 }
137
138 QQmlPropertyData::Flags
139 QQmlPropertyData::flagsForProperty(const QMetaProperty &p, QQmlEngine *engine)
140 {
141     return fastFlagsForProperty(p) | flagsForPropertyType(p.userType(), engine);
142 }
143
144 void QQmlPropertyData::lazyLoad(const QMetaProperty &p, QQmlEngine *engine)
145 {
146     Q_UNUSED(engine);
147
148     coreIndex = p.propertyIndex();
149     notifyIndex = QMetaObjectPrivate::signalIndex(p.notifySignal());
150     Q_ASSERT(p.revision() <= Q_INT16_MAX);
151     revision = p.revision();
152
153     flags = fastFlagsForProperty(p);
154
155     int type = p.type();
156     if (type == QMetaType::QObjectStar) {
157         propType = type;
158         flags |= QQmlPropertyData::IsQObjectDerived;
159     } else if (type == QMetaType::QVariant) {
160         propType = type;
161         flags |= QQmlPropertyData::IsQVariant;
162     } else if (type == QVariant::UserType || type == -1) {
163         propTypeName = p.typeName();
164         flags |= QQmlPropertyData::NotFullyResolved;
165     } else {
166         propType = type;
167     }
168 }
169
170 void QQmlPropertyData::load(const QMetaProperty &p, QQmlEngine *engine)
171 {
172     propType = p.userType();
173     coreIndex = p.propertyIndex();
174     notifyIndex = QMetaObjectPrivate::signalIndex(p.notifySignal());
175     flags = fastFlagsForProperty(p) | flagsForPropertyType(propType, engine);
176     Q_ASSERT(p.revision() <= Q_INT16_MAX);
177     revision = p.revision();
178 }
179
180 void QQmlPropertyData::load(const QMetaMethod &m)
181 {
182     coreIndex = m.methodIndex();
183     arguments = 0;
184     flags |= IsFunction;
185     if (m.methodType() == QMetaMethod::Signal)
186         flags |= IsSignal;
187     propType = m.returnType();
188
189     if (m.parameterCount()) {
190         flags |= HasArguments;
191         if ((m.parameterCount() == 1) && (m.parameterTypes().first() == "QQmlV8Function*")) {
192             flags |= IsV8Function;
193         }
194     }
195
196     if (m.attributes() & QMetaMethod::Cloned)
197         flags |= IsCloned;
198
199     Q_ASSERT(m.revision() <= Q_INT16_MAX);
200     revision = m.revision();
201 }
202
203 void QQmlPropertyData::lazyLoad(const QMetaMethod &m)
204 {
205     coreIndex = m.methodIndex();
206     arguments = 0;
207     flags |= IsFunction;
208     if (m.methodType() == QMetaMethod::Signal)
209         flags |= IsSignal;
210     propType = QMetaType::Void;
211
212     const char *returnType = m.typeName();
213     if (!returnType)
214         returnType = "\0";
215     if ((*returnType != 'v') || (qstrcmp(returnType+1, "oid") != 0)) {
216         propTypeName = returnType;
217         flags |= NotFullyResolved;
218     }
219
220     if (m.parameterCount()) {
221         flags |= HasArguments;
222         if ((m.parameterCount() == 1) && (m.parameterTypes().first() == "QQmlV8Function*")) {
223             flags |= IsV8Function;
224         }
225     }
226
227     if (m.attributes() & QMetaMethod::Cloned)
228         flags |= IsCloned;
229
230     Q_ASSERT(m.revision() <= Q_INT16_MAX);
231     revision = m.revision();
232 }
233
234 /*!
235 Creates a new empty QQmlPropertyCache.
236 */
237 QQmlPropertyCache::QQmlPropertyCache(QQmlEngine *e)
238 : engine(e), _parent(0), propertyIndexCacheStart(0), methodIndexCacheStart(0),
239   signalHandlerIndexCacheStart(0), _ownMetaObject(false), _metaObject(0), argumentsCache(0)
240 {
241     Q_ASSERT(engine);
242 }
243
244 /*!
245 Creates a new QQmlPropertyCache of \a metaObject.
246 */
247 QQmlPropertyCache::QQmlPropertyCache(QQmlEngine *e, const QMetaObject *metaObject)
248 : engine(e), _parent(0), propertyIndexCacheStart(0), methodIndexCacheStart(0),
249   signalHandlerIndexCacheStart(0), _ownMetaObject(false), _metaObject(0), argumentsCache(0)
250 {
251     Q_ASSERT(engine);
252     Q_ASSERT(metaObject);
253
254     update(engine, metaObject);
255 }
256
257 QQmlPropertyCache::~QQmlPropertyCache()
258 {
259     clear();
260
261     QQmlPropertyCacheMethodArguments *args = argumentsCache;
262     while (args) {
263         QQmlPropertyCacheMethodArguments *next = args->next;
264         if (args->names) delete args->names;
265         free(args);
266         args = next;
267     }
268
269     // We must clear this prior to releasing the parent incase it is a
270     // linked hash
271     stringCache.clear();
272     if (_parent) _parent->release();
273
274     if (_ownMetaObject) free((void *)_metaObject);
275     _metaObject = 0;
276     _parent = 0;
277     engine = 0;
278 }
279
280 void QQmlPropertyCache::destroy()
281 {
282     Q_ASSERT(engine || constructor.IsEmpty());
283     if (constructor.IsEmpty())
284         delete this;
285     else
286         QQmlEnginePrivate::deleteInEngineThread(engine, this);
287 }
288
289 // This is inherited from QQmlCleanup, so it should only clear the things
290 // that are tied to the specific QQmlEngine.
291 void QQmlPropertyCache::clear()
292 {
293     qPersistentDispose(constructor);
294     engine = 0;
295 }
296
297 QQmlPropertyCache *QQmlPropertyCache::copy(int reserve)
298 {
299     QQmlPropertyCache *cache = new QQmlPropertyCache(engine);
300     cache->_parent = this;
301     cache->_parent->addref();
302     cache->propertyIndexCacheStart = propertyIndexCache.count() + propertyIndexCacheStart;
303     cache->methodIndexCacheStart = methodIndexCache.count() + methodIndexCacheStart;
304     cache->signalHandlerIndexCacheStart = signalHandlerIndexCache.count() + signalHandlerIndexCacheStart;
305     cache->stringCache.linkAndReserve(stringCache, reserve);
306     cache->allowedRevisionCache = allowedRevisionCache;
307     cache->_metaObject = _metaObject;
308     cache->_defaultPropertyName = _defaultPropertyName;
309
310     // We specifically do *NOT* copy the constructor
311
312     return cache;
313 }
314
315 QQmlPropertyCache *QQmlPropertyCache::copy()
316 {
317     return copy(0);
318 }
319
320 QQmlPropertyCache *QQmlPropertyCache::copyAndReserve(QQmlEngine *, int propertyCount, int methodCount,
321                                                      int signalCount)
322 {
323     QQmlPropertyCache *rv = copy(propertyCount + methodCount + signalCount);
324     rv->propertyIndexCache.reserve(propertyCount);
325     rv->methodIndexCache.reserve(methodCount);
326     rv->signalHandlerIndexCache.reserve(signalCount);
327     rv->_metaObject = 0;
328
329     return rv;
330 }
331
332 /*! \internal
333
334     \a notifyIndex MUST be in the signal index range (see QObjectPrivate::signalIndex()).
335     This is different from QMetaMethod::methodIndex().
336 */
337 void QQmlPropertyCache::appendProperty(const QString &name,
338                                        quint32 flags, int coreIndex, int propType, int notifyIndex)
339 {
340     QQmlPropertyData data;
341     data.propType = propType;
342     data.coreIndex = coreIndex;
343     data.notifyIndex = notifyIndex;
344     data.flags = flags;
345
346     QHashedString string(name);
347     if (QQmlPropertyData **old = stringCache.value(string)) {
348         data.overrideIndexIsProperty = !(*old)->isFunction();
349         data.overrideIndex = (*old)->coreIndex;
350         (*old)->flags |= QQmlPropertyData::IsOverridden;
351     }
352
353     propertyIndexCache.append(data);
354
355     stringCache.insert(string, propertyIndexCache.data() + propertyIndexCache.count() - 1);
356 }
357
358 void QQmlPropertyCache::appendProperty(const QHashedCStringRef &name,
359                                        quint32 flags, int coreIndex, int propType, int notifyIndex)
360 {
361     QQmlPropertyData data;
362     data.propType = propType;
363     data.coreIndex = coreIndex;
364     data.notifyIndex = notifyIndex;
365     data.flags = flags;
366
367     if (QQmlPropertyData **old = stringCache.value(name)) {
368         data.overrideIndexIsProperty = !(*old)->isFunction();
369         data.overrideIndex = (*old)->coreIndex;
370         (*old)->flags |= QQmlPropertyData::IsOverridden;
371     }
372
373     propertyIndexCache.append(data);
374
375     stringCache.insert(name, propertyIndexCache.data() + propertyIndexCache.count() - 1);
376 }
377
378 void QQmlPropertyCache::appendSignal(const QString &name, quint32 flags, int coreIndex,
379                                      const int *types, const QList<QByteArray> &names)
380 {
381     QQmlPropertyData data;
382     data.propType = QVariant::Invalid;
383     data.coreIndex = coreIndex;
384     data.flags = flags;
385     data.arguments = 0;
386
387     QQmlPropertyData handler = data;
388     handler.flags |= QQmlPropertyData::IsSignalHandler;
389
390     if (types) {
391         int argumentCount = *types;
392         typedef QQmlPropertyCacheMethodArguments A;
393         A *args = static_cast<A *>(malloc(sizeof(A) + (argumentCount + 1) * sizeof(int)));
394         ::memcpy(args->arguments, types, (argumentCount + 1) * sizeof(int));
395         args->names = new QList<QByteArray>(names);
396         args->next = argumentsCache;
397         argumentsCache = args;
398         data.arguments = args;
399     }
400
401     QString handlerName = QLatin1String("on") + name;
402     handlerName[2] = handlerName[2].toUpper();
403
404     QHashedString string(name);
405     if (QQmlPropertyData **old = stringCache.value(string)) {
406         data.overrideIndexIsProperty = !(*old)->isFunction();
407         data.overrideIndex = (*old)->coreIndex;
408         (*old)->flags |= QQmlPropertyData::IsOverridden;
409     }
410
411     methodIndexCache.append(data);
412     signalHandlerIndexCache.append(handler);
413
414     stringCache.insert(string, methodIndexCache.data() + methodIndexCache.count() - 1);
415     stringCache.insert(handlerName, signalHandlerIndexCache.data() + signalHandlerIndexCache.count() - 1);
416 }
417
418 void QQmlPropertyCache::appendSignal(const QHashedCStringRef &name, quint32 flags, int coreIndex,
419                                      const int *types, const QList<QByteArray> &names)
420 {
421     QQmlPropertyData data;
422     data.propType = QVariant::Invalid;
423     data.coreIndex = coreIndex;
424     data.flags = flags;
425     data.arguments = 0;
426
427     QQmlPropertyData handler = data;
428     handler.flags |= QQmlPropertyData::IsSignalHandler;
429
430     if (types) {
431         int argumentCount = *types;
432         typedef QQmlPropertyCacheMethodArguments A;
433         A *args = static_cast<A *>(malloc(sizeof(A) + (argumentCount + 1) * sizeof(int)));
434         ::memcpy(args->arguments, types, (argumentCount + 1) * sizeof(int));
435         args->names = new QList<QByteArray>(names);
436         args->next = argumentsCache;
437         argumentsCache = args;
438         data.arguments = args;
439     }
440
441     QString handlerName = QLatin1String("on") + name.toUtf16();
442     handlerName[2] = handlerName[2].toUpper();
443
444     if (QQmlPropertyData **old = stringCache.value(name)) {
445         data.overrideIndexIsProperty = !(*old)->isFunction();
446         data.overrideIndex = (*old)->coreIndex;
447         (*old)->flags |= QQmlPropertyData::IsOverridden;
448     }
449
450     methodIndexCache.append(data);
451     signalHandlerIndexCache.append(handler);
452
453     stringCache.insert(name, methodIndexCache.data() + methodIndexCache.count() - 1);
454     stringCache.insert(handlerName, signalHandlerIndexCache.data() + signalHandlerIndexCache.count() - 1);
455 }
456
457 void QQmlPropertyCache::appendMethod(const QString &name, quint32 flags, int coreIndex,
458                                      const QList<QByteArray> &names)
459 {
460     int argumentCount = names.count();
461
462     QQmlPropertyData data;
463     data.propType = QMetaType::QVariant;
464     data.coreIndex = coreIndex;
465
466     typedef QQmlPropertyCacheMethodArguments A;
467     A *args = static_cast<A *>(malloc(sizeof(A) + (argumentCount + 1) * sizeof(int)));
468     args->arguments[0] = argumentCount;
469     for (int ii = 0; ii < argumentCount; ++ii)
470         args->arguments[ii + 1] = QMetaType::QVariant;
471     args->names = 0;
472     if (argumentCount)
473         args->names = new QList<QByteArray>(names);
474     args->next = argumentsCache;
475     argumentsCache = args;
476     data.arguments = args;
477
478     data.flags = flags;
479
480     QHashedString string(name);
481     if (QQmlPropertyData **old = stringCache.value(string)) {
482         data.overrideIndexIsProperty = !(*old)->isFunction();
483         data.overrideIndex = (*old)->coreIndex;
484         (*old)->flags |= QQmlPropertyData::IsOverridden;
485     }
486
487     methodIndexCache.append(data);
488
489     stringCache.insert(string, methodIndexCache.data() + methodIndexCache.count() - 1);
490 }
491
492 void QQmlPropertyCache::appendMethod(const QHashedCStringRef &name, quint32 flags, int coreIndex,
493                                      const QList<QByteArray> &names)
494 {
495     int argumentCount = names.count();
496
497     QQmlPropertyData data;
498     data.propType = QMetaType::QVariant;
499     data.coreIndex = coreIndex;
500
501     typedef QQmlPropertyCacheMethodArguments A;
502     A *args = static_cast<A *>(malloc(sizeof(A) + (argumentCount + 1) * sizeof(int)));
503     args->arguments[0] = argumentCount;
504     for (int ii = 0; ii < argumentCount; ++ii)
505         args->arguments[ii + 1] = QMetaType::QVariant;
506     args->names = 0;
507     if (argumentCount)
508         args->names = new QList<QByteArray>(names);
509     args->next = argumentsCache;
510     argumentsCache = args;
511     data.arguments = args;
512
513     data.flags = flags;
514
515     if (QQmlPropertyData **old = stringCache.value(name)) {
516         data.overrideIndexIsProperty = !(*old)->isFunction();
517         data.overrideIndex = (*old)->coreIndex;
518         (*old)->flags |= QQmlPropertyData::IsOverridden;
519     }
520
521     methodIndexCache.append(data);
522
523     stringCache.insert(name, methodIndexCache.data() + methodIndexCache.count() - 1);
524 }
525
526 // Returns this property cache's metaObject.  May be null if it hasn't been created yet.
527 const QMetaObject *QQmlPropertyCache::metaObject() const
528 {
529     return _metaObject;
530 }
531
532 // Returns this property cache's metaObject, creating it if necessary.
533 const QMetaObject *QQmlPropertyCache::createMetaObject()
534 {
535     if (!_metaObject) {
536         _ownMetaObject = true;
537
538         QMetaObjectBuilder builder;
539         toMetaObjectBuilder(builder);
540         builder.setSuperClass(_parent->createMetaObject());
541         _metaObject = builder.toMetaObject();
542     }
543
544     return _metaObject;
545 }
546
547 // Returns the name of the default property for this cache
548 QString QQmlPropertyCache::defaultPropertyName() const
549 {
550     return _defaultPropertyName;
551 }
552
553 QQmlPropertyData *QQmlPropertyCache::defaultProperty() const
554 {
555     return property(defaultPropertyName());
556 }
557
558 QQmlPropertyCache *QQmlPropertyCache::parent() const
559 {
560     return _parent;
561 }
562
563 // Returns the first C++ type's QMetaObject - that is, the first QMetaObject not created by
564 // QML
565 const QMetaObject *QQmlPropertyCache::firstCppMetaObject() const
566 {
567     while (_parent && (_metaObject == 0 || _ownMetaObject))
568         return _parent->firstCppMetaObject();
569     return _metaObject;
570 }
571
572 QQmlPropertyCache *
573 QQmlPropertyCache::copyAndAppend(QQmlEngine *engine, const QMetaObject *metaObject,
574                                          QQmlPropertyData::Flag propertyFlags,
575                                          QQmlPropertyData::Flag methodFlags,
576                                          QQmlPropertyData::Flag signalFlags)
577 {
578     return copyAndAppend(engine, metaObject, -1, propertyFlags, methodFlags, signalFlags);
579 }
580
581 QQmlPropertyCache *
582 QQmlPropertyCache::copyAndAppend(QQmlEngine *engine, const QMetaObject *metaObject,
583                                          int revision,
584                                          QQmlPropertyData::Flag propertyFlags,
585                                          QQmlPropertyData::Flag methodFlags,
586                                          QQmlPropertyData::Flag signalFlags)
587 {
588     Q_ASSERT(QMetaObjectPrivate::get(metaObject)->revision >= 4);
589
590     // Reserve enough space in the name hash for all the methods (including signals), all the
591     // signal handlers and all the properties.  This assumes no name clashes, but this is the
592     // common case.
593     QQmlPropertyCache *rv = copy(QMetaObjectPrivate::get(metaObject)->methodCount +
594                                          QMetaObjectPrivate::get(metaObject)->signalCount +
595                                          QMetaObjectPrivate::get(metaObject)->propertyCount);
596
597     rv->append(engine, metaObject, revision, propertyFlags, methodFlags, signalFlags);
598
599     return rv;
600 }
601
602 void QQmlPropertyCache::append(QQmlEngine *engine, const QMetaObject *metaObject,
603                                        int revision,
604                                        QQmlPropertyData::Flag propertyFlags,
605                                        QQmlPropertyData::Flag methodFlags,
606                                        QQmlPropertyData::Flag signalFlags)
607 {
608     Q_UNUSED(revision);
609     Q_ASSERT(constructor.IsEmpty()); // We should not be appending to an in-use property cache
610
611     _metaObject = metaObject;
612
613     bool dynamicMetaObject = isDynamicMetaObject(metaObject);
614
615     allowedRevisionCache.append(0);
616
617     int methodCount = metaObject->methodCount();
618     Q_ASSERT(QMetaObjectPrivate::get(metaObject)->revision >= 4);
619     int signalCount = metaObjectSignalCount(metaObject);
620     int classInfoCount = QMetaObjectPrivate::get(metaObject)->classInfoCount;
621
622     QQmlAccessorProperties::Properties accessorProperties;
623
624     if (classInfoCount) {
625         int classInfoOffset = metaObject->classInfoOffset();
626         bool hasFastProperty = false;
627         for (int ii = 0; ii < classInfoCount; ++ii) {
628             int idx = ii + classInfoOffset;
629
630             if (0 == qstrcmp(metaObject->classInfo(idx).name(), "qt_HasQmlAccessors")) {
631                 hasFastProperty = true;
632             } else if (0 == qstrcmp(metaObject->classInfo(idx).name(), "DefaultProperty")) {
633                 _defaultPropertyName = QString::fromUtf8(metaObject->classInfo(idx).value());
634             }
635         }
636
637         if (hasFastProperty) {
638             accessorProperties = QQmlAccessorProperties::properties(metaObject);
639             if (accessorProperties.count == 0)
640                 qFatal("QQmlPropertyCache: %s has FastProperty class info, but has not "
641                        "installed property accessors", metaObject->className());
642         } else {
643 #ifndef QT_NO_DEBUG
644             accessorProperties = QQmlAccessorProperties::properties(metaObject);
645             if (accessorProperties.count != 0)
646                 qFatal("QQmlPropertyCache: %s has fast property accessors, but is missing "
647                        "FastProperty class info", metaObject->className());
648 #endif
649         }
650     }
651
652     //Used to block access to QObject::destroyed() and QObject::deleteLater() from QML
653     static const int destroyedIdx1 = QObject::staticMetaObject.indexOfSignal("destroyed(QObject*)");
654     static const int destroyedIdx2 = QObject::staticMetaObject.indexOfSignal("destroyed()");
655     static const int deleteLaterIdx = QObject::staticMetaObject.indexOfSlot("deleteLater()");
656
657     int methodOffset = metaObject->methodOffset();
658     int signalOffset = signalCount - QMetaObjectPrivate::get(metaObject)->signalCount;
659
660     // update() should have reserved enough space in the vector that this doesn't cause a realloc
661     // and invalidate the stringCache.
662     methodIndexCache.resize(methodCount - methodIndexCacheStart);
663     signalHandlerIndexCache.resize(signalCount - signalHandlerIndexCacheStart);
664     int signalHandlerIndex = signalOffset;
665     for (int ii = methodOffset; ii < methodCount; ++ii) {
666         if (ii == destroyedIdx1 || ii == destroyedIdx2 || ii == deleteLaterIdx)
667             continue;
668         QMetaMethod m = metaObject->method(ii);
669         if (m.access() == QMetaMethod::Private)
670             continue;
671
672         // Extract method name
673         // It's safe to keep the raw name pointer
674         Q_ASSERT(QMetaObjectPrivate::get(metaObject)->revision >= 7);
675         const char *rawName = m.name().constData();
676         const char *cptr = rawName;
677         char utf8 = 0;
678         while (*cptr) {
679             utf8 |= *cptr & 0x80;
680             ++cptr;
681         }
682
683         QQmlPropertyData *data = &methodIndexCache[ii - methodIndexCacheStart];
684         QQmlPropertyData *sigdata = 0;
685
686         data->lazyLoad(m);
687
688         if (data->isSignal())
689             data->flags |= signalFlags;
690         else
691             data->flags |= methodFlags;
692
693         if (!dynamicMetaObject)
694             data->flags |= QQmlPropertyData::IsDirect;
695
696         Q_ASSERT((allowedRevisionCache.count() - 1) < Q_INT16_MAX);
697         data->metaObjectOffset = allowedRevisionCache.count() - 1;
698
699         if (data->isSignal()) {
700             sigdata = &signalHandlerIndexCache[signalHandlerIndex - signalHandlerIndexCacheStart];
701             *sigdata = *data;
702             sigdata->flags |= QQmlPropertyData::IsSignalHandler;
703         }
704
705         QQmlPropertyData *old = 0;
706
707         if (utf8) {
708             QHashedString methodName(QString::fromUtf8(rawName, cptr - rawName));
709             if (QQmlPropertyData **it = stringCache.value(methodName))
710                 old = *it;
711             stringCache.insert(methodName, data);
712
713             if (data->isSignal()) {
714                 QHashedString on(QStringLiteral("on") % methodName.at(0).toUpper() % methodName.midRef(1));
715                 stringCache.insert(on, sigdata);
716                 ++signalHandlerIndex;
717             }
718         } else {
719             QHashedCStringRef methodName(rawName, cptr - rawName);
720             if (QQmlPropertyData **it = stringCache.value(methodName))
721                 old = *it;
722             stringCache.insert(methodName, data);
723
724             if (data->isSignal()) {
725                 int length = methodName.length();
726
727                 QVarLengthArray<char, 128> str(length+3);
728                 str[0] = 'o';
729                 str[1] = 'n';
730                 str[2] = toupper(rawName[0]);
731                 if (length > 1)
732                     memcpy(&str[3], &rawName[1], length - 1);
733                 str[length + 2] = '\0';
734
735                 QHashedString on(QString::fromLatin1(str.data()));
736                 stringCache.insert(on, sigdata);
737                 ++signalHandlerIndex;
738             }
739         }
740
741         if (old) {
742             // We only overload methods in the same class, exactly like C++
743             if (old->isFunction() && old->coreIndex >= methodOffset)
744                 data->flags |= QQmlPropertyData::IsOverload;
745             data->overrideIndexIsProperty = !old->isFunction();
746             data->overrideIndex = old->coreIndex;
747             old->flags |= QQmlPropertyData::IsOverridden;
748         }
749     }
750
751     int propCount = metaObject->propertyCount();
752     int propOffset = metaObject->propertyOffset();
753
754     // update() should have reserved enough space in the vector that this doesn't cause a realloc
755     // and invalidate the stringCache.
756     propertyIndexCache.resize(propCount - propertyIndexCacheStart);
757     for (int ii = propOffset; ii < propCount; ++ii) {
758         QMetaProperty p = metaObject->property(ii);
759         if (!p.isScriptable())
760             continue;
761
762         const char *str = p.name();
763         char utf8 = 0;
764         const char *cptr = str;
765         while (*cptr != 0) {
766             utf8 |= *cptr & 0x80;
767             ++cptr;
768         }
769
770         QQmlPropertyData *data = &propertyIndexCache[ii - propertyIndexCacheStart];
771
772         data->lazyLoad(p, engine);
773         data->flags |= propertyFlags;
774
775         if (!dynamicMetaObject)
776             data->flags |= QQmlPropertyData::IsDirect;
777
778         Q_ASSERT((allowedRevisionCache.count() - 1) < Q_INT16_MAX);
779         data->metaObjectOffset = allowedRevisionCache.count() - 1;
780
781         QQmlPropertyData *old = 0;
782
783         if (utf8) {
784             QHashedString propName(QString::fromUtf8(str, cptr - str));
785             if (QQmlPropertyData **it = stringCache.value(propName))
786                 old = *it;
787             stringCache.insert(propName, data);
788         } else {
789             QHashedCStringRef propName(str, cptr - str);
790             if (QQmlPropertyData **it = stringCache.value(propName))
791                 old = *it;
792             stringCache.insert(propName, data);
793         }
794
795         QQmlAccessorProperties::Property *accessorProperty = accessorProperties.property(str);
796
797         // Fast properties may not be overrides or revisioned
798         Q_ASSERT(accessorProperty == 0 || (old == 0 && data->revision == 0));
799
800         if (accessorProperty) {
801             data->flags |= QQmlPropertyData::HasAccessors;
802             data->accessors = accessorProperty->accessors;
803             data->accessorData = accessorProperty->data;
804         } else if (old) {
805             data->overrideIndexIsProperty = !old->isFunction();
806             data->overrideIndex = old->coreIndex;
807             old->flags |= QQmlPropertyData::IsOverridden;
808         }
809     }
810 }
811
812 void QQmlPropertyCache::resolve(QQmlPropertyData *data) const
813 {
814     Q_ASSERT(data->notFullyResolved());
815
816     data->propType = QMetaType::type(data->propTypeName);
817
818     if (!data->isFunction())
819         data->flags |= flagsForPropertyType(data->propType, engine);
820
821     data->flags &= ~QQmlPropertyData::NotFullyResolved;
822 }
823
824 void QQmlPropertyCache::updateRecur(QQmlEngine *engine, const QMetaObject *metaObject)
825 {
826     if (!metaObject)
827         return;
828
829     updateRecur(engine, metaObject->superClass());
830
831     append(engine, metaObject, -1);
832 }
833
834 void QQmlPropertyCache::update(QQmlEngine *engine, const QMetaObject *metaObject)
835 {
836     Q_ASSERT(engine);
837     Q_ASSERT(metaObject);
838     Q_ASSERT(stringCache.isEmpty());
839
840     // Preallocate enough space in the index caches for all the properties/methods/signals that
841     // are not cached in a parent cache so that the caches never need to be reallocated as this
842     // would invalidate pointers stored in the stringCache.
843     int pc = metaObject->propertyCount();
844     int mc = metaObject->methodCount();
845     int sc = metaObjectSignalCount(metaObject);
846     propertyIndexCache.reserve(pc - propertyIndexCacheStart);
847     methodIndexCache.reserve(mc - methodIndexCacheStart);
848     signalHandlerIndexCache.reserve(sc - signalHandlerIndexCacheStart);
849
850     // Reserve enough space in the stringCache for all properties/methods/signals including those
851     // cached in a parent cache.
852     stringCache.reserve(pc + mc + sc);
853
854     updateRecur(engine,metaObject);
855 }
856
857 /*! \internal
858     \a index MUST be in the signal index range (see QObjectPrivate::signalIndex()).
859     This is different from QMetaMethod::methodIndex().
860 */
861 QQmlPropertyData *
862 QQmlPropertyCache::signal(int index) const
863 {
864     if (index < 0 || index >= (signalHandlerIndexCacheStart + signalHandlerIndexCache.count()))
865         return 0;
866
867     if (index < signalHandlerIndexCacheStart)
868         return _parent->signal(index);
869
870     QQmlPropertyData *rv = const_cast<QQmlPropertyData *>(&methodIndexCache.at(index - signalHandlerIndexCacheStart));
871     if (rv->notFullyResolved()) resolve(rv);
872     Q_ASSERT(rv->isSignal() || rv->coreIndex == -1);
873     return rv;
874 }
875
876 int QQmlPropertyCache::methodIndexToSignalIndex(int index) const
877 {
878     if (index < 0 || index >= (methodIndexCacheStart + methodIndexCache.count()))
879         return index;
880
881     if (index < methodIndexCacheStart)
882         return _parent->methodIndexToSignalIndex(index);
883
884     return index - methodIndexCacheStart + signalHandlerIndexCacheStart;
885 }
886
887 QQmlPropertyData *
888 QQmlPropertyCache::property(int index) const
889 {
890     if (index < 0 || index >= (propertyIndexCacheStart + propertyIndexCache.count()))
891         return 0;
892
893     if (index < propertyIndexCacheStart)
894         return _parent->property(index);
895
896     QQmlPropertyData *rv = const_cast<QQmlPropertyData *>(&propertyIndexCache.at(index - propertyIndexCacheStart));
897     if (rv->notFullyResolved()) resolve(rv);
898     return rv;
899 }
900
901 QQmlPropertyData *
902 QQmlPropertyCache::method(int index) const
903 {
904     if (index < 0 || index >= (methodIndexCacheStart + methodIndexCache.count()))
905         return 0;
906
907     if (index < methodIndexCacheStart)
908         return _parent->method(index);
909
910     QQmlPropertyData *rv = const_cast<QQmlPropertyData *>(&methodIndexCache.at(index - methodIndexCacheStart));
911     if (rv->notFullyResolved()) resolve(rv);
912     return rv;
913 }
914
915 QQmlPropertyData *
916 QQmlPropertyCache::property(const QHashedStringRef &str) const
917 {
918     QQmlPropertyData **rv = stringCache.value(str);
919     if (rv && (*rv)->notFullyResolved()) resolve(*rv);
920     return rv?*rv:0;
921 }
922
923 QQmlPropertyData *
924 QQmlPropertyCache::property(const QHashedCStringRef &str) const
925 {
926     QQmlPropertyData **rv = stringCache.value(str);
927     if (rv && (*rv)->notFullyResolved()) resolve(*rv);
928     return rv?*rv:0;
929 }
930
931 QQmlPropertyData *
932 QQmlPropertyCache::property(const QString &str) const
933 {
934     QQmlPropertyData **rv = stringCache.value(str);
935     if (rv && (*rv)->notFullyResolved()) resolve(*rv);
936     return rv?*rv:0;
937 }
938
939 QString QQmlPropertyData::name(QObject *object)
940 {
941     if (!object)
942         return QString();
943
944     return name(object->metaObject());
945 }
946
947 QString QQmlPropertyData::name(const QMetaObject *metaObject)
948 {
949     if (!metaObject || coreIndex == -1)
950         return QString();
951
952     if (flags & IsFunction) {
953         QMetaMethod m = metaObject->method(coreIndex);
954
955         return QString::fromUtf8(m.name().constData());
956     } else {
957         QMetaProperty p = metaObject->property(coreIndex);
958         return QString::fromUtf8(p.name());
959     }
960 }
961
962 QStringList QQmlPropertyCache::propertyNames() const
963 {
964     QStringList keys;
965     for (StringCache::ConstIterator iter = stringCache.begin(); iter != stringCache.end(); ++iter)
966         keys.append(iter.key());
967     return keys;
968 }
969
970 struct StaticQtMetaObject : public QObject
971 {
972     static const QMetaObject *get()
973         { return &static_cast<StaticQtMetaObject*> (0)->staticQtMetaObject; }
974 };
975
976 static int EnumType(const QMetaObject *metaobj, const QByteArray &str, int type)
977 {
978     QByteArray scope;
979     QByteArray name;
980     int scopeIdx = str.lastIndexOf("::");
981     if (scopeIdx != -1) {
982         scope = str.left(scopeIdx);
983         name = str.mid(scopeIdx + 2);
984     } else {
985         name = str;
986     }
987     const QMetaObject *meta;
988     if (scope == "Qt")
989         meta = StaticQtMetaObject::get();
990     else
991         meta = metaobj;
992     for (int i = meta->enumeratorCount() - 1; i >= 0; --i) {
993         QMetaEnum m = meta->enumerator(i);
994         if ((m.name() == name) && (scope.isEmpty() || (m.scope() == scope)))
995             return QVariant::Int;
996     }
997     return type;
998 }
999
1000 /*! \internal
1001     \a index MUST be in the signal index range (see QObjectPrivate::signalIndex()).
1002     This is different from QMetaMethod::methodIndex().
1003 */
1004 QList<QByteArray> QQmlPropertyCache::signalParameterNames(QObject *object, int index)
1005 {
1006     QQmlData *data = QQmlData::get(object, false);
1007     if (data->propertyCache) {
1008         QQmlPropertyData *p = data->propertyCache->signal(index);
1009         if (!p->hasArguments())
1010             return QList<QByteArray>();
1011     }
1012
1013     return QMetaObjectPrivate::signal(object->metaObject(), index).parameterNames();
1014 }
1015
1016 // Returns an array of the arguments for method \a index.  The first entry in the array
1017 // is the number of arguments.
1018 int *QQmlPropertyCache::methodParameterTypes(QObject *object, int index,
1019                                                      QVarLengthArray<int, 9> &dummy,
1020                                                      QByteArray *unknownTypeError)
1021 {
1022     Q_ASSERT(object && index >= 0);
1023
1024     QQmlData *ddata = QQmlData::get(object, false);
1025
1026     if (ddata && ddata->propertyCache) {
1027         typedef QQmlPropertyCacheMethodArguments A;
1028
1029         QQmlPropertyCache *c = ddata->propertyCache;
1030         Q_ASSERT(index < c->methodIndexCacheStart + c->methodIndexCache.count());
1031
1032         while (index < c->methodIndexCacheStart)
1033             c = c->_parent;
1034
1035         QQmlPropertyData *rv = const_cast<QQmlPropertyData *>(&c->methodIndexCache.at(index - c->methodIndexCacheStart));
1036
1037         if (rv->arguments)
1038             return static_cast<A *>(rv->arguments)->arguments;
1039
1040         const QMetaObject *metaObject = c->createMetaObject();
1041         Q_ASSERT(metaObject);
1042         QMetaMethod m = metaObject->method(index);
1043
1044         int argc = m.parameterCount();
1045         A *args = static_cast<A *>(malloc(sizeof(A) + (argc + 1) * sizeof(int)));
1046         args->arguments[0] = argc;
1047         args->names = 0;
1048         QList<QByteArray> argTypeNames; // Only loaded if needed
1049
1050         for (int ii = 0; ii < argc; ++ii) {
1051             int type = m.parameterType(ii);
1052             QMetaType::TypeFlags flags = QMetaType::typeFlags(type);
1053             if (flags & QMetaType::IsEnumeration)
1054                 type = QVariant::Int;
1055             else if (type == QMetaType::UnknownType ||
1056                      (type >= (int)QVariant::UserType && !(flags & QMetaType::PointerToQObject) &&
1057                       type != qMetaTypeId<QJSValue>())) {
1058                 //the UserType clause is to catch registered QFlags
1059                 if (argTypeNames.isEmpty())
1060                     argTypeNames = m.parameterTypes();
1061                 type = EnumType(object->metaObject(), argTypeNames.at(ii), type);
1062             }
1063             if (type == QMetaType::UnknownType) {
1064                 if (unknownTypeError) *unknownTypeError = argTypeNames.at(ii);
1065                 free(args);
1066                 return 0;
1067             }
1068             args->arguments[ii + 1] = type;
1069         }
1070
1071         rv->arguments = args;
1072         args->next = c->argumentsCache;
1073         c->argumentsCache = args;
1074         return static_cast<A *>(rv->arguments)->arguments;
1075
1076     } else {
1077         QMetaMethod m = object->metaObject()->method(index);
1078         int argc = m.parameterCount();
1079         dummy.resize(argc + 1);
1080         dummy[0] = argc;
1081         QList<QByteArray> argTypeNames; // Only loaded if needed
1082
1083         for (int ii = 0; ii < argc; ++ii) {
1084             int type = m.parameterType(ii);
1085             QMetaType::TypeFlags flags = QMetaType::typeFlags(type);
1086             if (flags & QMetaType::IsEnumeration)
1087                 type = QVariant::Int;
1088             else if (type == QMetaType::UnknownType ||
1089                      (type >= (int)QVariant::UserType && !(flags & QMetaType::PointerToQObject) &&
1090                       type != qMetaTypeId<QJSValue>())) {
1091                 //the UserType clause is to catch registered QFlags)
1092                 if (argTypeNames.isEmpty())
1093                     argTypeNames = m.parameterTypes();
1094                 type = EnumType(object->metaObject(), argTypeNames.at(ii), type);
1095             }
1096             if (type == QMetaType::UnknownType) {
1097                 if (unknownTypeError) *unknownTypeError = argTypeNames.at(ii);
1098                 return 0;
1099             }
1100             dummy[ii + 1] = type;
1101         }
1102
1103         return dummy.data();
1104     }
1105 }
1106
1107 // Returns the return type of the method.
1108 int QQmlPropertyCache::methodReturnType(QObject *object, const QQmlPropertyData &data,
1109                                         QByteArray *unknownTypeError)
1110 {
1111     Q_ASSERT(object && data.coreIndex >= 0);
1112
1113     int type = data.propType;
1114
1115     const char *propTypeName = 0;
1116
1117     if (type == QMetaType::UnknownType) {
1118         // Find the return type name from the method info
1119         QMetaMethod m;
1120
1121         QQmlData *ddata = QQmlData::get(object, false);
1122         if (ddata && ddata->propertyCache) {
1123             QQmlPropertyCache *c = ddata->propertyCache;
1124             Q_ASSERT(data.coreIndex < c->methodIndexCacheStart + c->methodIndexCache.count());
1125
1126             while (data.coreIndex < c->methodIndexCacheStart)
1127                 c = c->_parent;
1128
1129             const QMetaObject *metaObject = c->createMetaObject();
1130             Q_ASSERT(metaObject);
1131             m = metaObject->method(data.coreIndex);
1132         } else {
1133             m = object->metaObject()->method(data.coreIndex);
1134         }
1135
1136         type = m.returnType();
1137         propTypeName = m.typeName();
1138     }
1139
1140     QMetaType::TypeFlags flags = QMetaType::typeFlags(type);
1141     if (flags & QMetaType::IsEnumeration) {
1142         type = QVariant::Int;
1143     } else if (type == QMetaType::UnknownType ||
1144                (type >= (int)QVariant::UserType && !(flags & QMetaType::PointerToQObject) &&
1145                type != qMetaTypeId<QJSValue>())) {
1146         //the UserType clause is to catch registered QFlags
1147         type = EnumType(object->metaObject(), propTypeName, type);
1148     }
1149
1150     if (type == QMetaType::UnknownType) {
1151         if (unknownTypeError) *unknownTypeError = propTypeName;
1152     }
1153
1154     return type;
1155 }
1156
1157 QQmlPropertyData qQmlPropertyCacheCreate(const QMetaObject *metaObject, const QString &property)
1158 {
1159     Q_ASSERT(metaObject);
1160
1161     QQmlPropertyData rv;
1162     {
1163         const QMetaObject *cmo = metaObject;
1164         const QByteArray propertyName = property.toUtf8();
1165         while (cmo) {
1166             int idx = cmo->indexOfProperty(propertyName);
1167             if (idx != -1) {
1168                 QMetaProperty p = cmo->property(idx);
1169                 if (p.isScriptable()) {
1170                     rv.load(p);
1171                     return rv;
1172                 } else {
1173                     while (cmo && cmo->propertyOffset() >= idx)
1174                         cmo = cmo->superClass();
1175                 }
1176             } else {
1177                 cmo = 0;
1178             }
1179         }
1180     }
1181
1182     //Used to block access to QObject::destroyed() and QObject::deleteLater() from QML
1183     static const int destroyedIdx1 = QObject::staticMetaObject.indexOfSignal("destroyed(QObject*)");
1184     static const int destroyedIdx2 = QObject::staticMetaObject.indexOfSignal("destroyed()");
1185     static const int deleteLaterIdx = QObject::staticMetaObject.indexOfSlot("deleteLater()");
1186
1187     int methodCount = metaObject->methodCount();
1188     for (int ii = methodCount - 1; ii >= 0; --ii) {
1189         if (ii == destroyedIdx1 || ii == destroyedIdx2 || ii == deleteLaterIdx)
1190             continue;
1191         QMetaMethod m = metaObject->method(ii);
1192         if (m.access() == QMetaMethod::Private)
1193             continue;
1194         QString methodName = QString::fromUtf8(m.name().constData());
1195
1196         if (methodName == property) {
1197             rv.load(m);
1198             return rv;
1199         }
1200     }
1201
1202     return rv;
1203 }
1204
1205 inline const QString &qQmlPropertyCacheToString(const QString &string)
1206 {
1207     return string;
1208 }
1209
1210 inline QString qQmlPropertyCacheToString(const QHashedV8String &string)
1211 {
1212     return QV8Engine::toStringStatic(string.string());
1213 }
1214
1215 template<typename T>
1216 QQmlPropertyData *
1217 qQmlPropertyCacheProperty(QQmlEngine *engine, QObject *obj, const T &name, QQmlPropertyData &local)
1218 {
1219     QQmlPropertyCache *cache = 0;
1220
1221     QQmlData *ddata = QQmlData::get(obj, false);
1222
1223     if (ddata && ddata->propertyCache) {
1224         cache = ddata->propertyCache;
1225     } else if (engine) {
1226         QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine);
1227         cache = ep->cache(obj);
1228         if (cache) {
1229             ddata = QQmlData::get(obj, true);
1230             cache->addref();
1231             ddata->propertyCache = cache;
1232         }
1233     }
1234
1235     QQmlPropertyData *rv = 0;
1236
1237     if (cache) {
1238         rv = cache->property(name);
1239     } else {
1240         local = qQmlPropertyCacheCreate(obj->metaObject(), qQmlPropertyCacheToString(name));
1241         if (local.isValid())
1242             rv = &local;
1243     }
1244
1245     return rv;
1246 }
1247
1248 QQmlPropertyData *
1249 QQmlPropertyCache::property(QQmlEngine *engine, QObject *obj,
1250                                     const QHashedV8String &name, QQmlPropertyData &local)
1251 {
1252     return qQmlPropertyCacheProperty<QHashedV8String>(engine, obj, name, local);
1253 }
1254
1255 QQmlPropertyData *
1256 QQmlPropertyCache::property(QQmlEngine *engine, QObject *obj,
1257                                     const QString &name, QQmlPropertyData &local)
1258 {
1259     return qQmlPropertyCacheProperty<QString>(engine, obj, name, local);
1260 }
1261
1262 static inline const QMetaObjectPrivate *priv(const uint* data)
1263 { return reinterpret_cast<const QMetaObjectPrivate*>(data); }
1264
1265 bool QQmlPropertyCache::isDynamicMetaObject(const QMetaObject *mo)
1266 {
1267     return priv(mo->d.data)->revision >= 3 && priv(mo->d.data)->flags & DynamicMetaObject;
1268 }
1269
1270 const char *QQmlPropertyCache::className() const
1271 {
1272     if (!_ownMetaObject && _metaObject)
1273         return _metaObject->className();
1274     else
1275         return _dynamicClassName.constData();
1276 }
1277
1278 void QQmlPropertyCache::toMetaObjectBuilder(QMetaObjectBuilder &builder)
1279 {
1280     struct Sort { static bool lt(const QPair<QString, QQmlPropertyData *> &lhs,
1281                                  const QPair<QString, QQmlPropertyData *> &rhs) {
1282         return lhs.second->coreIndex < rhs.second->coreIndex;
1283     } };
1284
1285     struct Insert { static void in(QQmlPropertyCache *This,
1286                                    QList<QPair<QString, QQmlPropertyData *> > &properties,
1287                                    QList<QPair<QString, QQmlPropertyData *> > &methods,
1288                                    StringCache::ConstIterator iter, QQmlPropertyData *data) {
1289         if (data->isSignalHandler())
1290             return;
1291
1292         if (data->isFunction()) {
1293             if (data->coreIndex < This->methodIndexCacheStart)
1294                 return;
1295
1296             QPair<QString, QQmlPropertyData *> entry = qMakePair((QString)iter.key(), data);
1297             // Overrides can cause the entry to already exist
1298             if (!methods.contains(entry)) methods.append(entry);
1299
1300             data = This->overrideData(data);
1301             if (data && !data->isFunction()) Insert::in(This, properties, methods, iter, data);
1302         } else {
1303             if (data->coreIndex < This->propertyIndexCacheStart)
1304                 return;
1305
1306             QPair<QString, QQmlPropertyData *> entry = qMakePair((QString)iter.key(), data);
1307             // Overrides can cause the entry to already exist
1308             if (!properties.contains(entry)) properties.append(entry);
1309
1310             data = This->overrideData(data);
1311             if (data) Insert::in(This, properties, methods, iter, data);
1312         }
1313
1314     } };
1315
1316     builder.setClassName(_dynamicClassName);
1317
1318     QList<QPair<QString, QQmlPropertyData *> > properties;
1319     QList<QPair<QString, QQmlPropertyData *> > methods;
1320
1321     for (StringCache::ConstIterator iter = stringCache.begin(); iter != stringCache.end(); ++iter)
1322         Insert::in(this, properties, methods, iter, iter.value());
1323
1324     Q_ASSERT(properties.count() == propertyIndexCache.count());
1325     Q_ASSERT(methods.count() == methodIndexCache.count());
1326
1327     qSort(properties.begin(), properties.end(), Sort::lt);
1328     qSort(methods.begin(), methods.end(), Sort::lt);
1329
1330     for (int ii = 0; ii < properties.count(); ++ii) {
1331         QQmlPropertyData *data = properties.at(ii).second;
1332
1333         int notifierId = -1;
1334         if (data->notifyIndex != -1)
1335             notifierId = data->notifyIndex - signalHandlerIndexCacheStart;
1336
1337         QMetaPropertyBuilder property = builder.addProperty(properties.at(ii).first.toUtf8(),
1338                                                             QMetaType::typeName(data->propType),
1339                                                             notifierId);
1340
1341         property.setReadable(true);
1342         property.setWritable(data->isWritable());
1343         property.setResettable(data->isResettable());
1344     }
1345
1346     for (int ii = 0; ii < methods.count(); ++ii) {
1347         QQmlPropertyData *data = methods.at(ii).second;
1348
1349         QByteArray returnType;
1350         if (data->propType != 0)
1351             returnType = QMetaType::typeName(data->propType);
1352
1353         QByteArray signature = methods.at(ii).first.toUtf8() + "(";
1354
1355         QQmlPropertyCacheMethodArguments *arguments = 0;
1356         if (data->hasArguments()) {
1357             arguments = (QQmlPropertyCacheMethodArguments *)data->arguments;
1358
1359             for (int ii = 0; ii < arguments->arguments[0]; ++ii) {
1360                 if (ii != 0) signature.append(",");
1361                 signature.append(QMetaType::typeName(arguments->arguments[1 + ii]));
1362             }
1363         }
1364
1365         signature.append(")");
1366
1367         QMetaMethodBuilder method;
1368         if (data->isSignal()) {
1369             method = builder.addSignal(signature);
1370         } else {
1371             method = builder.addSlot(signature);
1372         }
1373         method.setAccess(QMetaMethod::Protected);
1374
1375         if (arguments && arguments->names)
1376             method.setParameterNames(*arguments->names);
1377
1378         if (!returnType.isEmpty())
1379             method.setReturnType(returnType);
1380     }
1381
1382     if (!_defaultPropertyName.isEmpty()) {
1383         QQmlPropertyData *dp = property(_defaultPropertyName);
1384         if (dp && dp->coreIndex >= propertyIndexCacheStart) {
1385             Q_ASSERT(!dp->isFunction());
1386             builder.addClassInfo("DefaultProperty", _defaultPropertyName.toUtf8());
1387         }
1388     }
1389 }
1390
1391 // Returns true if \a from is assignable to a property of type \a to
1392 bool QQmlMetaObject::canConvert(const QQmlMetaObject &from, const QQmlMetaObject &to)
1393 {
1394     Q_ASSERT(!from.isNull() && !to.isNull());
1395
1396     struct I { static bool equal(const QMetaObject *lhs, const QMetaObject *rhs) {
1397         return lhs == rhs || (lhs && rhs && lhs->d.stringdata == rhs->d.stringdata);
1398     } };
1399
1400     const QMetaObject *tom = to._m.isT1()?to._m.asT1()->metaObject():to._m.asT2();
1401     if (tom == &QObject::staticMetaObject) return true;
1402
1403     if (from._m.isT1() && to._m.isT1()) { // QQmlPropertyCache -> QQmlPropertyCache
1404         QQmlPropertyCache *fromp = from._m.asT1();
1405         QQmlPropertyCache *top = to._m.asT1();
1406
1407         while (fromp) {
1408             if (fromp == top) return true;
1409             fromp = fromp->parent();
1410         }
1411     } else if (from._m.isT1() && to._m.isT2()) { // QQmlPropertyCache -> QMetaObject
1412         QQmlPropertyCache *fromp = from._m.asT1();
1413
1414         while (fromp) {
1415             const QMetaObject *fromm = fromp->metaObject();
1416             if (fromm && I::equal(fromm, tom)) return true;
1417             fromp = fromp->parent();
1418         }
1419     } else if (from._m.isT2() && to._m.isT1()) { // QMetaObject -> QQmlPropertyCache
1420         const QMetaObject *fromm = from._m.asT2();
1421
1422         if (!tom) return false;
1423
1424         while (fromm) {
1425             if (I::equal(fromm, tom)) return true;
1426             fromm = fromm->superClass();
1427         }
1428     } else { // QMetaObject -> QMetaObject
1429         const QMetaObject *fromm = from._m.asT2();
1430
1431         while (fromm) {
1432             if (I::equal(fromm, tom)) return true;
1433             fromm = fromm->superClass();
1434         }
1435     }
1436
1437     return false;
1438 }
1439
1440 QQmlPropertyCache *QQmlMetaObject::propertyCache(QQmlEnginePrivate *e) const
1441 {
1442     if (_m.isNull()) return 0;
1443     if (_m.isT1()) return _m.asT1();
1444     else return e->cache(_m.asT2());
1445 }
1446
1447 QT_END_NAMESPACE