Update copyright year in license headers.
[profile/ivi/qtdeclarative.git] / src / declarative / qml / qdeclarativepropertycache.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 **
7 ** This file is part of the QtDeclarative module of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 **
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 **
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
29 **
30 ** Other Usage
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qdeclarativepropertycache_p.h"
43
44 #include "qdeclarativeengine_p.h"
45 #include "qdeclarativebinding_p.h"
46 #include <private/qv8engine_p.h>
47
48 #include <private/qmetaobject_p.h>
49 #include <private/qdeclarativeaccessors_p.h>
50
51 #include <QtCore/qdebug.h>
52
53 Q_DECLARE_METATYPE(QJSValue)
54 Q_DECLARE_METATYPE(QDeclarativeV8Handle);
55
56 QT_BEGIN_NAMESPACE
57
58 #define Q_INT16_MAX 32767
59
60 class QDeclarativePropertyCacheMethodArguments 
61 {
62 public:
63     QDeclarativePropertyCacheMethodArguments *next;
64     int arguments[0];
65 };
66
67 // Flags that do *NOT* depend on the property's QMetaProperty::userType() and thus are quick
68 // to load
69 static QDeclarativePropertyData::Flags fastFlagsForProperty(const QMetaProperty &p)
70 {
71     QDeclarativePropertyData::Flags flags;
72
73     if (p.isConstant())
74         flags |= QDeclarativePropertyData::IsConstant;
75     if (p.isWritable())
76         flags |= QDeclarativePropertyData::IsWritable;
77     if (p.isResettable())
78         flags |= QDeclarativePropertyData::IsResettable;
79     if (p.isFinal())
80         flags |= QDeclarativePropertyData::IsFinal;
81     if (p.isEnumType())
82         flags |= QDeclarativePropertyData::IsEnumType;
83
84     return flags;
85 }
86
87 // Flags that do depend on the property's QMetaProperty::userType() and thus are slow to 
88 // load
89 static QDeclarativePropertyData::Flags flagsForPropertyType(int propType, QDeclarativeEngine *engine)
90 {
91     Q_ASSERT(propType != -1);
92
93     QDeclarativePropertyData::Flags flags;
94
95     if (propType == QMetaType::QObjectStar || propType == QMetaType::QWidgetStar) {
96         flags |= QDeclarativePropertyData::IsQObjectDerived;
97     } else if (propType == QMetaType::QVariant) {
98         flags |= QDeclarativePropertyData::IsQVariant;
99     } else if (propType < (int)QVariant::UserType) {
100     } else if (propType == qMetaTypeId<QDeclarativeBinding *>()) {
101         flags |= QDeclarativePropertyData::IsQmlBinding;
102     } else if (propType == qMetaTypeId<QJSValue>()) {
103         flags |= QDeclarativePropertyData::IsQJSValue;
104     } else if (propType == qMetaTypeId<QDeclarativeV8Handle>()) {
105         flags |= QDeclarativePropertyData::IsV8Handle;
106     } else {
107         QDeclarativeMetaType::TypeCategory cat = 
108             engine ? QDeclarativeEnginePrivate::get(engine)->typeCategory(propType)
109                    : QDeclarativeMetaType::typeCategory(propType);
110
111         if (cat == QDeclarativeMetaType::Object)
112             flags |= QDeclarativePropertyData::IsQObjectDerived;
113         else if (cat == QDeclarativeMetaType::List)
114             flags |= QDeclarativePropertyData::IsQList;
115     }
116
117     return flags;
118 }
119
120 static int metaObjectSignalCount(const QMetaObject *metaObject)
121 {
122     int signalCount = 0;
123     for (const QMetaObject *obj = metaObject; obj; obj = obj->superClass())
124         signalCount += QMetaObjectPrivate::get(obj)->signalCount;
125     return signalCount;
126 }
127
128 QDeclarativePropertyData::Flags
129 QDeclarativePropertyData::flagsForProperty(const QMetaProperty &p, QDeclarativeEngine *engine)
130 {
131     return fastFlagsForProperty(p) | flagsForPropertyType(p.userType(), engine);
132 }
133
134 void QDeclarativePropertyData::lazyLoad(const QMetaProperty &p, QDeclarativeEngine *engine)
135 {
136     Q_UNUSED(engine);
137
138     coreIndex = p.propertyIndex();
139     notifyIndex = p.notifySignalIndex();
140     Q_ASSERT(p.revision() <= Q_INT16_MAX);
141     revision = p.revision();
142
143     flags = fastFlagsForProperty(p);
144
145     int type = p.type();
146     if (type == QMetaType::QObjectStar || type == QMetaType::QWidgetStar) {
147         propType = type;
148         flags |= QDeclarativePropertyData::IsQObjectDerived;
149     } else if (type == QVariant::UserType || type == -1) {
150         propTypeName = p.typeName();
151         flags |= QDeclarativePropertyData::NotFullyResolved;
152     } else {
153         propType = type;
154     }
155 }
156
157 void QDeclarativePropertyData::load(const QMetaProperty &p, QDeclarativeEngine *engine)
158 {
159     propType = p.userType();
160     if (QVariant::Type(propType) == QVariant::LastType)
161         propType = QMetaType::QVariant;
162     coreIndex = p.propertyIndex();
163     notifyIndex = p.notifySignalIndex();
164     flags = fastFlagsForProperty(p) | flagsForPropertyType(propType, engine);
165     Q_ASSERT(p.revision() <= Q_INT16_MAX);
166     revision = p.revision();
167 }
168
169 void QDeclarativePropertyData::load(const QMetaMethod &m)
170 {
171     coreIndex = m.methodIndex();
172     arguments = 0;
173     flags |= IsFunction;
174     if (m.methodType() == QMetaMethod::Signal)
175         flags |= IsSignal;
176     propType = QVariant::Invalid;
177
178     const char *returnType = m.typeName();
179     if (returnType) 
180         propType = QMetaType::type(returnType);
181
182     const char *signature = m.signature();
183     while (*signature != '(') { Q_ASSERT(*signature != 0); ++signature; }
184
185     ++signature;
186     if (*signature != ')') {
187         flags |= HasArguments;
188         if (0 == ::strcmp(signature, "QDeclarativeV8Function*)")) {
189             flags |= IsV8Function;
190         }
191     }
192
193     Q_ASSERT(m.revision() <= Q_INT16_MAX);
194     revision = m.revision();
195 }
196
197 void QDeclarativePropertyData::lazyLoad(const QMetaMethod &m)
198 {
199     coreIndex = m.methodIndex();
200     arguments = 0;
201     flags |= IsFunction;
202     if (m.methodType() == QMetaMethod::Signal)
203         flags |= IsSignal;
204     propType = QVariant::Invalid;
205
206     const char *returnType = m.typeName();
207     if (returnType && *returnType) {
208         propTypeName = returnType;
209         flags |= NotFullyResolved;
210     }
211
212     const char *signature = m.signature();
213     while (*signature != '(') { Q_ASSERT(*signature != 0); ++signature; }
214
215     ++signature;
216     if (*signature != ')') {
217         flags |= HasArguments;
218         if (0 == ::strcmp(signature, "QDeclarativeV8Function*)")) {
219             flags |= IsV8Function;
220         }
221     }
222
223     Q_ASSERT(m.revision() <= Q_INT16_MAX);
224     revision = m.revision();
225 }
226
227 /*!
228 Creates a new empty QDeclarativePropertyCache.
229 */
230 QDeclarativePropertyCache::QDeclarativePropertyCache(QDeclarativeEngine *e)
231 : engine(e), parent(0), propertyIndexCacheStart(0), methodIndexCacheStart(0),
232   signalHanderIndexCacheStart(0), metaObject(0), argumentsCache(0)
233 {
234     Q_ASSERT(engine);
235 }
236
237 /*!
238 Creates a new QDeclarativePropertyCache of \a metaObject.
239 */
240 QDeclarativePropertyCache::QDeclarativePropertyCache(QDeclarativeEngine *e, const QMetaObject *metaObject)
241 : engine(e), parent(0), propertyIndexCacheStart(0), methodIndexCacheStart(0),
242   signalHanderIndexCacheStart(0), metaObject(0), argumentsCache(0)
243 {
244     Q_ASSERT(engine);
245     Q_ASSERT(metaObject);
246
247     update(engine, metaObject);
248 }
249
250 QDeclarativePropertyCache::~QDeclarativePropertyCache()
251 {
252     clear();
253
254     QDeclarativePropertyCacheMethodArguments *args = argumentsCache;
255     while (args) {
256         QDeclarativePropertyCacheMethodArguments *next = args->next;
257         qFree(args);
258         args = next;
259     }
260
261     if (parent) parent->release();
262     parent = 0;
263     engine = 0;
264 }
265
266 void QDeclarativePropertyCache::destroy()
267 {
268     Q_ASSERT(engine || constructor.IsEmpty());
269     if (constructor.IsEmpty())
270         delete this;
271     else
272         QDeclarativeEnginePrivate::deleteInEngineThread(engine, this);
273 }
274
275 // This is inherited from QDeclarativeCleanup, so it should only clear the things
276 // that are tied to the specific QDeclarativeEngine.
277 void QDeclarativePropertyCache::clear()
278 {
279     qPersistentDispose(constructor);
280     engine = 0;
281 }
282
283 QDeclarativePropertyCache *QDeclarativePropertyCache::copy(int reserve)
284 {
285     QDeclarativePropertyCache *cache = new QDeclarativePropertyCache(engine);
286     cache->parent = this;
287     cache->parent->addref();
288     cache->propertyIndexCacheStart = propertyIndexCache.count() + propertyIndexCacheStart;
289     cache->methodIndexCacheStart = methodIndexCache.count() + methodIndexCacheStart;
290     cache->signalHanderIndexCacheStart = signalHandlerIndexCache.count() + signalHanderIndexCacheStart;
291     cache->stringCache.copyAndReserve(stringCache, reserve);
292     cache->allowedRevisionCache = allowedRevisionCache;
293     cache->metaObject = metaObject;
294
295     // We specifically do *NOT* copy the constructor
296
297     return cache;
298 }
299
300 QDeclarativePropertyCache *QDeclarativePropertyCache::copy()
301 {
302     return copy(0);
303 }
304
305 QDeclarativePropertyCache *
306 QDeclarativePropertyCache::copyAndAppend(QDeclarativeEngine *engine, const QMetaObject *metaObject,
307                                          QDeclarativePropertyData::Flag propertyFlags,
308                                          QDeclarativePropertyData::Flag methodFlags,
309                                          QDeclarativePropertyData::Flag signalFlags)
310 {
311     return copyAndAppend(engine, metaObject, -1, propertyFlags, methodFlags, signalFlags);
312 }
313
314 QDeclarativePropertyCache *
315 QDeclarativePropertyCache::copyAndAppend(QDeclarativeEngine *engine, const QMetaObject *metaObject,
316                                          int revision,
317                                          QDeclarativePropertyData::Flag propertyFlags,
318                                          QDeclarativePropertyData::Flag methodFlags,
319                                          QDeclarativePropertyData::Flag signalFlags)
320 {
321     Q_ASSERT(QMetaObjectPrivate::get(metaObject)->revision >= 4);
322
323     // Reserve enough space in the name hash for all the methods (including signals), all the
324     // signal handlers and all the properties.  This assumes no name clashes, but this is the
325     // common case.
326     QDeclarativePropertyCache *rv = copy(QMetaObjectPrivate::get(metaObject)->methodCount +
327                                          QMetaObjectPrivate::get(metaObject)->signalCount +
328                                          QMetaObjectPrivate::get(metaObject)->propertyCount);
329
330     rv->append(engine, metaObject, revision, propertyFlags, methodFlags, signalFlags);
331
332     return rv;
333 }
334
335 void QDeclarativePropertyCache::append(QDeclarativeEngine *engine, const QMetaObject *metaObject, 
336                                        QDeclarativePropertyData::Flag propertyFlags,
337                                        QDeclarativePropertyData::Flag methodFlags,
338                                        QDeclarativePropertyData::Flag signalFlags)
339 {
340     append(engine, metaObject, -1, propertyFlags, methodFlags, signalFlags);
341 }
342
343 void QDeclarativePropertyCache::append(QDeclarativeEngine *engine, const QMetaObject *metaObject, 
344                                        int revision, 
345                                        QDeclarativePropertyData::Flag propertyFlags,
346                                        QDeclarativePropertyData::Flag methodFlags,
347                                        QDeclarativePropertyData::Flag signalFlags)
348 {
349     Q_UNUSED(revision);
350     Q_ASSERT(constructor.IsEmpty()); // We should not be appending to an in-use property cache
351
352     this->metaObject = metaObject;
353
354     bool dynamicMetaObject = isDynamicMetaObject(metaObject);
355
356     allowedRevisionCache.append(0);
357
358     int methodCount = metaObject->methodCount();
359     Q_ASSERT(QMetaObjectPrivate::get(metaObject)->revision >= 4);
360     int signalCount = metaObjectSignalCount(metaObject);
361     int classInfoCount = QMetaObjectPrivate::get(metaObject)->classInfoCount;
362
363     QDeclarativeAccessorProperties::Properties accessorProperties;
364
365     // Special case QObject as we don't want to add a qt_HasQmlAccessors classinfo to it
366     if (metaObject == &QObject::staticMetaObject) {
367         accessorProperties = QDeclarativeAccessorProperties::properties(metaObject);
368     } else if (classInfoCount) {
369         int classInfoOffset = metaObject->classInfoOffset();
370         bool hasFastProperty = false;
371         for (int ii = 0; ii < classInfoCount; ++ii) {
372             int idx = ii + classInfoOffset;
373
374             if (0 == qstrcmp(metaObject->classInfo(idx).name(), "qt_HasQmlAccessors")) {
375                 hasFastProperty = true;
376                 break;
377             }
378         }
379
380         if (hasFastProperty) {
381             accessorProperties = QDeclarativeAccessorProperties::properties(metaObject);
382             if (accessorProperties.count == 0)
383                 qFatal("QDeclarativePropertyCache: %s has FastProperty class info, but has not "
384                        "installed property accessors", metaObject->className());
385         } else {
386 #ifndef QT_NO_DEBUG
387             accessorProperties = QDeclarativeAccessorProperties::properties(metaObject);
388             if (accessorProperties.count != 0)
389                 qFatal("QDeclarativePropertyCache: %s has fast property accessors, but is missing "
390                        "FastProperty class info", metaObject->className());
391 #endif
392         }
393     }
394
395     // qMax(defaultMethods, methodOffset) to block the signals and slots of QObject::staticMetaObject
396     // incl. destroyed signals, objectNameChanged signal, deleteLater slot, _q_reregisterTimers slot.
397     int methodOffset = qMax(QObject::staticMetaObject.methodCount(), metaObject->methodOffset());
398     int signalOffset = signalCount - QMetaObjectPrivate::get(metaObject)->signalCount;
399
400     // update() should have reserved enough space in the vector that this doesn't cause a realloc
401     // and invalidate the stringCache.
402     methodIndexCache.resize(methodCount - methodIndexCacheStart);
403     signalHandlerIndexCache.resize(signalCount - signalHanderIndexCacheStart);
404     int signalHandlerIndex = signalOffset;
405     for (int ii = methodOffset; ii < methodCount; ++ii) {
406         QMetaMethod m = metaObject->method(ii);
407         if (m.access() == QMetaMethod::Private) 
408             continue;
409
410         // Extract method name
411         const char *signature = m.signature();
412         const char *cptr = signature;
413         char utf8 = 0;
414         while (*cptr != '(') {
415             Q_ASSERT(*cptr != 0);
416             utf8 |= *cptr & 0x80;
417             ++cptr;
418         }
419
420         QDeclarativePropertyData *data = &methodIndexCache[ii - methodIndexCacheStart];
421         QDeclarativePropertyData *sigdata = 0;
422
423         data->lazyLoad(m);
424
425         if (data->isSignal())
426             data->flags |= signalFlags;
427         else
428             data->flags |= methodFlags;
429
430         if (!dynamicMetaObject)
431             data->flags |= QDeclarativePropertyData::IsDirect;
432
433         Q_ASSERT((allowedRevisionCache.count() - 1) < Q_INT16_MAX);
434         data->metaObjectOffset = allowedRevisionCache.count() - 1;
435
436         if (data->isSignal()) {
437             sigdata = &signalHandlerIndexCache[signalHandlerIndex - signalHanderIndexCacheStart];
438             *sigdata = *data;
439             sigdata->flags |= QDeclarativePropertyData::IsSignalHandler;
440         }
441
442         QDeclarativePropertyData *old = 0;
443
444         if (utf8) {
445             QHashedString methodName(QString::fromUtf8(signature, cptr - signature));
446             if (QDeclarativePropertyData **it = stringCache.value(methodName))
447                 old = *it;
448             stringCache.insert(methodName, data);
449
450             if (data->isSignal()) {
451                 QHashedString on(QStringLiteral("on") % methodName.at(0).toUpper() % methodName.midRef(1));
452                 stringCache.insert(on, sigdata);
453                 ++signalHandlerIndex;
454             }
455         } else {
456             QHashedCStringRef methodName(signature, cptr - signature);
457             if (QDeclarativePropertyData **it = stringCache.value(methodName))
458                 old = *it;
459             stringCache.insert(methodName, data);
460
461             if (data->isSignal()) {
462                 int length = methodName.length();
463
464                 QVarLengthArray<char, 128> str(length+3);
465                 str[0] = 'o';
466                 str[1] = 'n';
467                 str[2] = toupper(signature[0]);
468                 if (length > 1)
469                     memcpy(&str[3], &signature[1], length - 1);
470                 str[length + 2] = '\0';
471
472                 QHashedString on(QString::fromLatin1(str.data()));
473                 stringCache.insert(on, sigdata);
474                 ++signalHandlerIndex;
475             }
476         }
477
478         if (old) {
479             // We only overload methods in the same class, exactly like C++
480             if (old->isFunction() && old->coreIndex >= methodOffset)
481                 data->flags |= QDeclarativePropertyData::IsOverload;
482             data->overrideIndexIsProperty = !old->isFunction();
483             data->overrideIndex = old->coreIndex;
484         }
485     }
486
487     int propCount = metaObject->propertyCount();
488     int propOffset = metaObject->propertyOffset();
489
490     // update() should have reserved enough space in the vector that this doesn't cause a realloc
491     // and invalidate the stringCache.
492     propertyIndexCache.resize(propCount - propertyIndexCacheStart);
493     for (int ii = propOffset; ii < propCount; ++ii) {
494         QMetaProperty p = metaObject->property(ii);
495         if (!p.isScriptable())
496             continue;
497
498         const char *str = p.name();
499         char utf8 = 0;
500         const char *cptr = str;
501         while (*cptr != 0) {
502             utf8 |= *cptr & 0x80;
503             ++cptr;
504         }
505
506         QDeclarativePropertyData *data = &propertyIndexCache[ii - propertyIndexCacheStart];
507
508         data->lazyLoad(p, engine);
509         data->flags |= propertyFlags;
510
511         if (!dynamicMetaObject) 
512             data->flags |= QDeclarativePropertyData::IsDirect;
513
514         Q_ASSERT((allowedRevisionCache.count() - 1) < Q_INT16_MAX);
515         data->metaObjectOffset = allowedRevisionCache.count() - 1;
516
517         QDeclarativePropertyData *old = 0;
518
519         if (utf8) {
520             QHashedString propName(QString::fromUtf8(str, cptr - str));
521             if (QDeclarativePropertyData **it = stringCache.value(propName))
522                 old = *it;
523             stringCache.insert(propName, data);
524         } else {
525             QHashedCStringRef propName(str, cptr - str);
526             if (QDeclarativePropertyData **it = stringCache.value(propName))
527                 old = *it;
528             stringCache.insert(propName, data);
529         }
530
531         QDeclarativeAccessorProperties::Property *accessorProperty = accessorProperties.property(str);
532
533         // Fast properties may not be overrides
534         Q_ASSERT(accessorProperty == 0 || old == 0);
535
536         if (accessorProperty) {
537             data->flags |= QDeclarativePropertyData::HasAccessors;
538             data->accessors = accessorProperty->accessors;
539             data->accessorData = accessorProperty->data;
540         } else if (old) {
541             data->overrideIndexIsProperty = !old->isFunction();
542             data->overrideIndex = old->coreIndex;
543         }
544     }
545 }
546
547 void QDeclarativePropertyCache::resolve(QDeclarativePropertyData *data) const
548 {
549     Q_ASSERT(data->notFullyResolved());
550
551     data->propType = QMetaType::type(data->propTypeName);
552     if (QVariant::Type(data->propType) == QVariant::LastType)
553         data->propType = QMetaType::QVariant;
554
555     if (!data->isFunction())
556         data->flags |= flagsForPropertyType(data->propType, engine);
557
558     data->flags &= ~QDeclarativePropertyData::NotFullyResolved;
559 }
560
561 void QDeclarativePropertyCache::updateRecur(QDeclarativeEngine *engine, const QMetaObject *metaObject)
562 {
563     if (!metaObject)
564         return;
565
566     updateRecur(engine, metaObject->superClass());
567
568     append(engine, metaObject);
569 }
570
571 void QDeclarativePropertyCache::update(QDeclarativeEngine *engine, const QMetaObject *metaObject)
572 {
573     Q_ASSERT(engine);
574     Q_ASSERT(metaObject);
575     Q_ASSERT(stringCache.isEmpty());
576
577     // Preallocate enough space in the index caches for all the properties/methods/signals that
578     // are not cached in a parent cache so that the caches never need to be reallocated as this
579     // would invalidate pointers stored in the stringCache.
580     int pc = metaObject->propertyCount();
581     int mc = metaObject->methodCount();
582     int sc = metaObjectSignalCount(metaObject);
583     propertyIndexCache.reserve(pc - propertyIndexCacheStart);
584     methodIndexCache.reserve(mc - methodIndexCacheStart);
585     signalHandlerIndexCache.reserve(sc - signalHanderIndexCacheStart);
586
587     // Reserve enough space in the stringCache for all properties/methods/signals including those
588     // cached in a parent cache.
589     stringCache.reserve(pc + mc + sc);
590
591     updateRecur(engine,metaObject);
592 }
593
594 QDeclarativePropertyData *
595 QDeclarativePropertyCache::property(int index) const
596 {
597     if (index < 0 || index >= (propertyIndexCacheStart + propertyIndexCache.count()))
598         return 0;
599     
600     if (index < propertyIndexCacheStart)
601         return parent->property(index);
602
603     QDeclarativePropertyData *rv = const_cast<QDeclarativePropertyData *>(&propertyIndexCache.at(index - propertyIndexCacheStart));
604     if (rv->notFullyResolved()) resolve(rv);
605     return rv;
606 }
607
608 QDeclarativePropertyData *
609 QDeclarativePropertyCache::method(int index) const
610 {
611     if (index < 0 || index >= (methodIndexCacheStart + methodIndexCache.count()))
612         return 0;
613
614     if (index < methodIndexCacheStart)
615         return parent->method(index);
616
617     QDeclarativePropertyData *rv = const_cast<QDeclarativePropertyData *>(&methodIndexCache.at(index - methodIndexCacheStart));
618     if (rv->notFullyResolved()) resolve(rv);
619     return rv;
620 }
621
622 QDeclarativePropertyData *
623 QDeclarativePropertyCache::property(const QHashedStringRef &str) const
624 {
625     QDeclarativePropertyData **rv = stringCache.value(str);
626     if (rv && (*rv)->notFullyResolved()) resolve(*rv);
627     return rv?*rv:0;
628 }
629
630 QDeclarativePropertyData *
631 QDeclarativePropertyCache::property(const QHashedCStringRef &str) const
632 {
633     QDeclarativePropertyData **rv = stringCache.value(str);
634     if (rv && (*rv)->notFullyResolved()) resolve(*rv);
635     return rv?*rv:0;
636 }
637
638 QDeclarativePropertyData *
639 QDeclarativePropertyCache::property(const QString &str) const
640 {
641     QDeclarativePropertyData **rv = stringCache.value(str);
642     if (rv && (*rv)->notFullyResolved()) resolve(*rv);
643     return rv?*rv:0;
644 }
645
646 QString QDeclarativePropertyData::name(QObject *object)
647 {
648     if (!object)
649         return QString();
650
651     return name(object->metaObject());
652 }
653
654 QString QDeclarativePropertyData::name(const QMetaObject *metaObject)
655 {
656     if (!metaObject || coreIndex == -1)
657         return QString();
658
659     if (flags & IsFunction) {
660         QMetaMethod m = metaObject->method(coreIndex);
661
662         QString name = QString::fromUtf8(m.signature());
663         int parenIdx = name.indexOf(QLatin1Char('('));
664         if (parenIdx != -1)
665             name = name.left(parenIdx);
666         return name;
667     } else {
668         QMetaProperty p = metaObject->property(coreIndex);
669         return QString::fromUtf8(p.name());
670     }
671 }
672
673 QStringList QDeclarativePropertyCache::propertyNames() const
674 {
675     QStringList keys;
676     for (StringCache::ConstIterator iter = stringCache.begin(); iter != stringCache.end(); ++iter) 
677         keys.append(iter.key());
678     return keys;
679 }
680
681 static int EnumType(const QMetaObject *meta, const QByteArray &str)
682 {
683     QByteArray scope;
684     QByteArray name;
685     int scopeIdx = str.lastIndexOf("::");
686     if (scopeIdx != -1) {
687         scope = str.left(scopeIdx);
688         name = str.mid(scopeIdx + 2);
689     } else { 
690         name = str;
691     }
692     for (int i = meta->enumeratorCount() - 1; i >= 0; --i) {
693         QMetaEnum m = meta->enumerator(i);
694         if ((m.name() == name) && (scope.isEmpty() || (m.scope() == scope)))
695             return QVariant::Int;
696     }
697     return QVariant::Invalid;
698 }
699
700 // Returns an array of the arguments for method \a index.  The first entry in the array
701 // is the number of arguments.
702 int *QDeclarativePropertyCache::methodParameterTypes(QObject *object, int index, 
703                                                      QVarLengthArray<int, 9> &dummy,
704                                                      QByteArray *unknownTypeError)
705 {
706     Q_ASSERT(object && index >= 0);
707
708     QDeclarativeData *ddata = QDeclarativeData::get(object, false);
709
710     if (ddata && ddata->propertyCache) {
711         typedef QDeclarativePropertyCacheMethodArguments A;
712
713         QDeclarativePropertyCache *c = ddata->propertyCache;
714         Q_ASSERT(index < c->methodIndexCacheStart + c->methodIndexCache.count());
715
716         while (index < c->methodIndexCacheStart)
717             c = c->parent;
718
719         QDeclarativePropertyData *rv = const_cast<QDeclarativePropertyData *>(&c->methodIndexCache.at(index - c->methodIndexCacheStart));
720
721         if (rv->arguments)  
722             return static_cast<A *>(rv->arguments)->arguments;
723
724         const QMetaObject *metaObject = object->metaObject();
725         QMetaMethod m = metaObject->method(index);
726         QList<QByteArray> argTypeNames = m.parameterTypes();
727
728         A *args = static_cast<A *>(qMalloc(sizeof(A) + (argTypeNames.count() + 1) * sizeof(int)));
729         args->arguments[0] = argTypeNames.count();
730
731         for (int ii = 0; ii < argTypeNames.count(); ++ii) {
732             int type = QMetaType::type(argTypeNames.at(ii));
733             if (type == QVariant::Invalid)
734                 type = EnumType(object->metaObject(), argTypeNames.at(ii));
735             if (type == QVariant::Invalid) {
736                 if (unknownTypeError) *unknownTypeError = argTypeNames.at(ii);
737                 qFree(args);
738                 return 0;
739             }
740             args->arguments[ii + 1] = type;
741         }
742
743         rv->arguments = args;
744         args->next = c->argumentsCache;
745         c->argumentsCache = args;
746         return static_cast<A *>(rv->arguments)->arguments;
747
748     } else {
749         QMetaMethod m = object->metaObject()->method(index);
750         QList<QByteArray> argTypeNames = m.parameterTypes();
751         dummy.resize(argTypeNames.count() + 1);
752         dummy[0] = argTypeNames.count();
753
754         for (int ii = 0; ii < argTypeNames.count(); ++ii) {
755             int type = QMetaType::type(argTypeNames.at(ii));
756             if (type == QVariant::Invalid)
757                 type = EnumType(object->metaObject(), argTypeNames.at(ii));
758             if (type == QVariant::Invalid) {
759                 if (unknownTypeError) *unknownTypeError = argTypeNames.at(ii);
760                 return 0;
761             }
762             dummy[ii + 1] = type;
763         }
764
765         return dummy.data();
766     }
767 }
768
769 QDeclarativePropertyData qDeclarativePropertyCacheCreate(const QMetaObject *metaObject,
770                                                          const QString &property)
771 {
772     Q_ASSERT(metaObject);
773
774     QDeclarativePropertyData rv;
775     {
776         const QMetaObject *cmo = metaObject;
777         const QByteArray propertyName = property.toUtf8();
778         while (cmo) {
779             int idx = cmo->indexOfProperty(propertyName);
780             if (idx != -1) {
781                 QMetaProperty p = cmo->property(idx);
782                 if (p.isScriptable()) {
783                     rv.load(p);
784                     return rv;
785                 } else {
786                     while (cmo && cmo->propertyOffset() >= idx)
787                         cmo = cmo->superClass();
788                 }
789             } else {
790                 cmo = 0;
791             }
792         }
793     }
794
795     int methodCount = metaObject->methodCount();
796     int defaultMethods = QObject::staticMetaObject.methodCount();
797     for (int ii = methodCount - 1; ii >= defaultMethods; --ii) {
798         // >=defaultMethods to block the signals and slots of QObject::staticMetaObject
799         // incl. destroyed signals, objectNameChanged signal, deleteLater slot, _q_reregisterTimers slot.
800         QMetaMethod m = metaObject->method(ii);
801         if (m.access() == QMetaMethod::Private)
802             continue;
803         QString methodName = QString::fromUtf8(m.signature());
804
805         int parenIdx = methodName.indexOf(QLatin1Char('('));
806         Q_ASSERT(parenIdx != -1);
807         QStringRef methodNameRef = methodName.leftRef(parenIdx);
808
809         if (methodNameRef == property) {
810             rv.load(m);
811             return rv;
812         }
813     }
814
815     return rv;
816 }
817
818 inline const QString &qDeclarativePropertyCacheToString(const QString &string)
819 {
820     return string;
821 }
822
823 inline QString qDeclarativePropertyCacheToString(const QHashedV8String &string)
824 {
825     return QV8Engine::toStringStatic(string.string());
826 }
827
828 template<typename T>
829 QDeclarativePropertyData *
830 qDeclarativePropertyCacheProperty(QDeclarativeEngine *engine, QObject *obj,
831                                   const T &name, QDeclarativePropertyData &local)
832 {
833     QDeclarativePropertyCache *cache = 0;
834
835     if (engine) {
836         QDeclarativeData *ddata = QDeclarativeData::get(obj);
837
838         if (ddata && ddata->propertyCache) {
839             cache = ddata->propertyCache;
840         } else if (engine) {
841             QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
842             cache = ep->cache(obj);
843             if (cache) {
844                 ddata = QDeclarativeData::get(obj, true);
845                 cache->addref();
846                 ddata->propertyCache = cache;
847             }
848         }
849     }
850
851     QDeclarativePropertyData *rv = 0;
852
853     if (cache) {
854         rv = cache->property(name);
855     } else {
856         local = qDeclarativePropertyCacheCreate(obj->metaObject(),
857                                                 qDeclarativePropertyCacheToString(name));
858         if (local.isValid())
859             rv = &local;
860     }
861
862     return rv;
863 }
864
865 QDeclarativePropertyData *
866 QDeclarativePropertyCache::property(QDeclarativeEngine *engine, QObject *obj, 
867                                     const QHashedV8String &name, QDeclarativePropertyData &local)
868 {
869     return qDeclarativePropertyCacheProperty<QHashedV8String>(engine, obj, name, local);
870 }
871
872 QDeclarativePropertyData *
873 QDeclarativePropertyCache::property(QDeclarativeEngine *engine, QObject *obj,
874                                     const QString &name, QDeclarativePropertyData &local)
875 {
876     return qDeclarativePropertyCacheProperty<QString>(engine, obj, name, local);
877 }
878
879 static inline const QMetaObjectPrivate *priv(const uint* data)
880 { return reinterpret_cast<const QMetaObjectPrivate*>(data); }
881
882 bool QDeclarativePropertyCache::isDynamicMetaObject(const QMetaObject *mo)
883 {
884     return priv(mo->d.data)->revision >= 3 && priv(mo->d.data)->flags & DynamicMetaObject;
885 }
886
887 QT_END_NAMESPACE