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