Optimize QML type registration.
[profile/ivi/qtdeclarative.git] / src / qml / qml / qqmlmetatype.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 <QtQml/qqmlprivate.h>
43 #include "qqmlmetatype_p.h"
44
45 #include <private/qqmlproxymetaobject_p.h>
46 #include <private/qqmlcustomparser_p.h>
47 #include <private/qqmlguard_p.h>
48 #include <private/qhashedstring_p.h>
49
50 #include <QtCore/qdebug.h>
51 #include <QtCore/qstringlist.h>
52 #include <QtCore/qmetaobject.h>
53 #include <QtCore/qbitarray.h>
54 #include <QtCore/qreadwritelock.h>
55 #include <QtCore/private/qmetaobject_p.h>
56
57 #include <qmetatype.h>
58 #include <qobjectdefs.h>
59 #include <qbytearray.h>
60 #include <qreadwritelock.h>
61 #include <qstring.h>
62 #include <qstringlist.h>
63 #include <qvector.h>
64
65 #include <ctype.h>
66
67 QT_BEGIN_NAMESPACE
68
69 struct QQmlMetaTypeData
70 {
71     QQmlMetaTypeData();
72     ~QQmlMetaTypeData();
73     QList<QQmlType *> types;
74     typedef QHash<int, QQmlType *> Ids;
75     Ids idToType;
76     typedef QHash<QHashedStringRef,QQmlType *> Names;
77     Names nameToType;
78     typedef QHash<const QMetaObject *, QQmlType *> MetaObjects;
79     MetaObjects metaObjectToType;
80     typedef QHash<int, QQmlMetaType::StringConverter> StringConverters;
81     StringConverters stringConverters;
82
83     struct VersionedUri {
84         VersionedUri()
85         : majorVersion(0) {}
86         VersionedUri(const QHashedString &uri, int majorVersion)
87         : uri(uri), majorVersion(majorVersion) {}
88         bool operator==(const VersionedUri &other) const {
89             return other.majorVersion == majorVersion && other.uri == uri;
90         }
91         QHashedString uri;
92         int majorVersion;
93     };
94     typedef QHash<VersionedUri, QQmlTypeModule *> TypeModules;
95     TypeModules uriToModule;
96
97     struct ModuleApiList {
98         ModuleApiList() : sorted(true) {}
99         QList<QQmlMetaType::ModuleApi> moduleApis;
100         bool sorted;
101     };
102     typedef QStringHash<ModuleApiList> ModuleApis;
103     ModuleApis moduleApis;
104     int moduleApiCount;
105
106     QBitArray objects;
107     QBitArray interfaces;
108     QBitArray lists;
109
110     QList<QQmlPrivate::AutoParentFunction> parentFunctions;
111 };
112
113 class QQmlTypeModulePrivate
114 {
115 public:
116     QQmlTypeModulePrivate() 
117     : minMinorVersion(INT_MAX), maxMinorVersion(0) {}
118
119     QQmlMetaTypeData::VersionedUri uri;
120
121     int minMinorVersion;
122     int maxMinorVersion;
123
124     void add(QQmlType *);
125
126     QStringHash<QList<QQmlType *> > typeHash;
127     QList<QQmlType *> types;
128 };
129
130 Q_GLOBAL_STATIC(QQmlMetaTypeData, metaTypeData)
131 Q_GLOBAL_STATIC(QReadWriteLock, metaTypeDataLock)
132
133 static uint qHash(const QQmlMetaTypeData::VersionedUri &v)
134 {
135     return v.uri.hash() ^ qHash(v.majorVersion);
136 }
137
138 QQmlMetaTypeData::QQmlMetaTypeData()
139 : moduleApiCount(0)
140 {
141 }
142
143 QQmlMetaTypeData::~QQmlMetaTypeData()
144 {
145     for (int i = 0; i < types.count(); ++i)
146         delete types.at(i);
147 }
148
149 class QQmlTypePrivate
150 {
151 public:
152     QQmlTypePrivate();
153
154     void init() const;
155     void initEnums() const;
156
157     bool m_isInterface : 1;
158     const char *m_iid;
159     QHashedString m_module;
160     QString m_name;
161     QString m_elementName;
162     int m_version_maj;
163     int m_version_min;
164     int m_typeId; int m_listId; 
165     int m_revision;
166     mutable bool m_containsRevisionedAttributes;
167     mutable QQmlType *m_superType;
168
169     int m_allocationSize;
170     void (*m_newFunc)(void *);
171     QString m_noCreationReason;
172
173     const QMetaObject *m_baseMetaObject;
174     QQmlAttachedPropertiesFunc m_attachedPropertiesFunc;
175     const QMetaObject *m_attachedPropertiesType;
176     int m_attachedPropertiesId;
177     int m_parserStatusCast;
178     int m_propertyValueSourceCast;
179     int m_propertyValueInterceptorCast;
180     QObject *(*m_extFunc)(QObject *);
181     const QMetaObject *m_extMetaObject;
182     int m_index;
183     QQmlCustomParser *m_customParser;
184     mutable volatile bool m_isSetup:1;
185     mutable volatile bool m_isEnumSetup:1;
186     mutable bool m_haveSuperType:1;
187     mutable QList<QQmlProxyMetaObject::ProxyData> m_metaObjects;
188     mutable QStringHash<int> m_enums;
189
190     static QHash<const QMetaObject *, int> m_attachedPropertyIds;
191 };
192
193 // Avoid multiple fromUtf8(), copies and hashing of the module name.
194 // This is only called when metaTypeDataLock is locked.
195 static QHashedString moduletoUtf8(const char *module)
196 {
197     if (!module)
198         return QHashedString();
199
200     static const char *lastModule = 0;
201     static QHashedString lastModuleStr;
202
203     if (lastModule != module) {
204         lastModuleStr = QString::fromUtf8(module);
205         lastModuleStr.hash();
206         lastModule = module;
207     }
208
209     return lastModuleStr;
210 }
211
212 QHash<const QMetaObject *, int> QQmlTypePrivate::m_attachedPropertyIds;
213
214 QQmlTypePrivate::QQmlTypePrivate()
215 : m_isInterface(false), m_iid(0), m_typeId(0), m_listId(0), m_revision(0), m_containsRevisionedAttributes(false),
216   m_superType(0), m_allocationSize(0), m_newFunc(0), m_baseMetaObject(0), m_attachedPropertiesFunc(0), 
217   m_attachedPropertiesType(0), m_parserStatusCast(-1), m_propertyValueSourceCast(-1), 
218   m_propertyValueInterceptorCast(-1), m_extFunc(0), m_extMetaObject(0), m_index(-1), m_customParser(0), 
219   m_isSetup(false), m_isEnumSetup(false), m_haveSuperType(false)
220 {
221 }
222
223
224 QQmlType::QQmlType(int index, const QQmlPrivate::RegisterInterface &interface)
225 : d(new QQmlTypePrivate)
226 {
227     d->m_isInterface = true;
228     d->m_iid = interface.iid;
229     d->m_typeId = interface.typeId;
230     d->m_listId = interface.listId;
231     d->m_newFunc = 0;
232     d->m_index = index;
233     d->m_isSetup = true;
234     d->m_version_maj = 0;
235     d->m_version_min = 0;
236 }
237
238 QQmlType::QQmlType(int index, const QQmlPrivate::RegisterType &type)
239 : d(new QQmlTypePrivate)
240 {
241     d->m_module = moduletoUtf8(type.uri);
242     d->m_elementName = QString::fromUtf8(type.elementName);
243
244     d->m_version_maj = type.versionMajor;
245     d->m_version_min = type.versionMinor;
246     if (type.version >= 1) // revisions added in version 1
247         d->m_revision = type.revision;
248     d->m_typeId = type.typeId;
249     d->m_listId = type.listId;
250     d->m_allocationSize = type.objectSize;
251     d->m_newFunc = type.create;
252     d->m_noCreationReason = type.noCreationReason;
253     d->m_baseMetaObject = type.metaObject;
254     d->m_attachedPropertiesFunc = type.attachedPropertiesFunction;
255     d->m_attachedPropertiesType = type.attachedPropertiesMetaObject;
256     if (d->m_attachedPropertiesType) {
257         QHash<const QMetaObject *, int>::Iterator iter = d->m_attachedPropertyIds.find(d->m_baseMetaObject);
258         if (iter == d->m_attachedPropertyIds.end())
259             iter = d->m_attachedPropertyIds.insert(d->m_baseMetaObject, index);
260         d->m_attachedPropertiesId = *iter;
261     } else {
262         d->m_attachedPropertiesId = -1;
263     }
264     d->m_parserStatusCast = type.parserStatusCast;
265     d->m_propertyValueSourceCast = type.valueSourceCast;
266     d->m_propertyValueInterceptorCast = type.valueInterceptorCast;
267     d->m_extFunc = type.extensionObjectCreate;
268     d->m_index = index;
269     d->m_customParser = type.customParser;
270
271     if (type.extensionMetaObject)
272         d->m_extMetaObject = type.extensionMetaObject;
273 }
274
275 QQmlType::~QQmlType()
276 {
277     delete d->m_customParser;
278     delete d;
279 }
280
281 const QHashedString &QQmlType::module() const
282 {
283     return d->m_module;
284 }
285
286 int QQmlType::majorVersion() const
287 {
288     return d->m_version_maj;
289 }
290
291 int QQmlType::minorVersion() const
292 {
293     return d->m_version_min;
294 }
295
296 bool QQmlType::availableInVersion(int vmajor, int vminor) const
297 {
298     Q_ASSERT(vmajor >= 0 && vminor >= 0);
299     return vmajor == d->m_version_maj && vminor >= d->m_version_min;
300 }
301
302 bool QQmlType::availableInVersion(const QHashedStringRef &module, int vmajor, int vminor) const
303 {
304     Q_ASSERT(vmajor >= 0 && vminor >= 0);
305     return module == d->m_module && vmajor == d->m_version_maj && vminor >= d->m_version_min;
306 }
307
308 // returns the nearest _registered_ super class
309 QQmlType *QQmlType::superType() const
310 {
311     if (!d->m_haveSuperType) {
312         const QMetaObject *mo = d->m_baseMetaObject->superClass();
313         while (mo && !d->m_superType) {
314             d->m_superType = QQmlMetaType::qmlType(mo, d->m_module, d->m_version_maj, d->m_version_min);
315             mo = mo->superClass();
316         }
317         d->m_haveSuperType = true;
318     }
319
320     return d->m_superType;
321 }
322
323 static void clone(QMetaObjectBuilder &builder, const QMetaObject *mo, 
324                   const QMetaObject *ignoreStart, const QMetaObject *ignoreEnd)
325 {
326     // Set classname
327     builder.setClassName(ignoreEnd->className());
328
329     // Clone Q_CLASSINFO
330     for (int ii = mo->classInfoOffset(); ii < mo->classInfoCount(); ++ii) {
331         QMetaClassInfo info = mo->classInfo(ii);
332
333         int otherIndex = ignoreEnd->indexOfClassInfo(info.name());
334         if (otherIndex >= ignoreStart->classInfoOffset() + ignoreStart->classInfoCount()) {
335             // Skip 
336         } else {
337             builder.addClassInfo(info.name(), info.value());
338         }
339     }
340
341     // Clone Q_PROPERTY
342     for (int ii = mo->propertyOffset(); ii < mo->propertyCount(); ++ii) {
343         QMetaProperty property = mo->property(ii);
344
345         int otherIndex = ignoreEnd->indexOfProperty(property.name());
346         if (otherIndex >= ignoreStart->propertyOffset() + ignoreStart->propertyCount()) {
347             builder.addProperty(QByteArray("__qml_ignore__") + property.name(), QByteArray("void"));
348             // Skip 
349         } else {
350             builder.addProperty(property);
351         }
352     }
353
354     // Clone Q_METHODS
355     for (int ii = mo->methodOffset(); ii < mo->methodCount(); ++ii) {
356         QMetaMethod method = mo->method(ii);
357
358         // More complex - need to search name
359         QByteArray name = method.name();
360
361
362         bool found = false;
363
364         for (int ii = ignoreStart->methodOffset() + ignoreStart->methodCount(); 
365              !found && ii < ignoreEnd->methodOffset() + ignoreEnd->methodCount();
366              ++ii) {
367
368             QMetaMethod other = ignoreEnd->method(ii);
369
370             found = name == other.name();
371         }
372
373         QMetaMethodBuilder m = builder.addMethod(method);
374         if (found) // SKIP
375             m.setAccess(QMetaMethod::Private);
376     }
377
378     // Clone Q_ENUMS
379     for (int ii = mo->enumeratorOffset(); ii < mo->enumeratorCount(); ++ii) {
380         QMetaEnum enumerator = mo->enumerator(ii);
381
382         int otherIndex = ignoreEnd->indexOfEnumerator(enumerator.name());
383         if (otherIndex >= ignoreStart->enumeratorOffset() + ignoreStart->enumeratorCount()) {
384             // Skip 
385         } else {
386             builder.addEnumerator(enumerator);
387         }
388     }
389 }
390
391 static bool isPropertyRevisioned(const QMetaObject *mo, int index)
392 {
393     int i = index;
394     i -= mo->propertyOffset();
395     if (i < 0 && mo->d.superdata)
396         return isPropertyRevisioned(mo->d.superdata, index);
397
398     const QMetaObjectPrivate *mop = reinterpret_cast<const QMetaObjectPrivate*>(mo->d.data);
399     if (i >= 0 && i < mop->propertyCount) {
400         int handle = mop->propertyData + 3*i;
401         int flags = mo->d.data[handle + 2];
402
403         return (flags & Revisioned);
404     }
405
406     return false;
407 }
408
409 void QQmlTypePrivate::init() const
410 {
411     if (m_isSetup) return;
412
413     QWriteLocker lock(metaTypeDataLock());
414     if (m_isSetup)
415         return;
416
417     // Setup extended meta object
418     // XXX - very inefficient
419     const QMetaObject *mo = m_baseMetaObject;
420     if (m_extFunc) {
421         QMetaObjectBuilder builder;
422         clone(builder, m_extMetaObject, m_extMetaObject, m_extMetaObject);
423         builder.setFlags(QMetaObjectBuilder::DynamicMetaObject);
424         QMetaObject *mmo = builder.toMetaObject();
425         mmo->d.superdata = mo;
426         QQmlProxyMetaObject::ProxyData data = { mmo, m_extFunc, 0, 0 };
427         m_metaObjects << data;
428     }
429
430     mo = mo->d.superdata;
431     while(mo) {
432         QQmlType *t = metaTypeData()->metaObjectToType.value(mo);
433         if (t) {
434             if (t->d->m_extFunc) {
435                 QMetaObjectBuilder builder;
436                 clone(builder, t->d->m_extMetaObject, t->d->m_baseMetaObject, m_baseMetaObject);
437                 builder.setFlags(QMetaObjectBuilder::DynamicMetaObject);
438                 QMetaObject *mmo = builder.toMetaObject();
439                 mmo->d.superdata = m_baseMetaObject;
440                 if (!m_metaObjects.isEmpty())
441                     m_metaObjects.last().metaObject->d.superdata = mmo;
442                 QQmlProxyMetaObject::ProxyData data = { mmo, t->d->m_extFunc, 0, 0 };
443                 m_metaObjects << data;
444             }
445         }
446         mo = mo->d.superdata;
447     }
448
449     for (int ii = 0; ii < m_metaObjects.count(); ++ii) {
450         m_metaObjects[ii].propertyOffset =
451             m_metaObjects.at(ii).metaObject->propertyOffset();
452         m_metaObjects[ii].methodOffset =
453             m_metaObjects.at(ii).metaObject->methodOffset();
454     }
455     
456     // Check for revisioned details
457     {
458         const QMetaObject *mo = 0;
459         if (m_metaObjects.isEmpty())
460             mo = m_baseMetaObject;
461         else
462             mo = m_metaObjects.first().metaObject;
463
464         for (int ii = 0; !m_containsRevisionedAttributes && ii < mo->propertyCount(); ++ii) {
465             if (isPropertyRevisioned(mo, ii))
466                 m_containsRevisionedAttributes = true;
467         }
468
469         for (int ii = 0; !m_containsRevisionedAttributes && ii < mo->methodCount(); ++ii) {
470             if (mo->method(ii).revision() != 0)
471                 m_containsRevisionedAttributes = true;
472         }
473     }
474
475     m_isSetup = true;
476     lock.unlock();
477 }
478
479 void QQmlTypePrivate::initEnums() const
480 {
481     if (m_isEnumSetup) return;
482
483     init();
484
485     QWriteLocker lock(metaTypeDataLock());
486     if (m_isEnumSetup) return;
487
488     const QMetaObject *metaObject = m_baseMetaObject;
489     for (int ii = 0; ii < metaObject->enumeratorCount(); ++ii) {
490
491         QMetaEnum e = metaObject->enumerator(ii);
492
493         for (int jj = 0; jj < e.keyCount(); ++jj) 
494             m_enums.insert(QString::fromUtf8(e.key(jj)), e.value(jj));
495     }
496
497     m_isEnumSetup = true;
498 }
499
500 QByteArray QQmlType::typeName() const
501 {
502     if (d->m_baseMetaObject)
503         return d->m_baseMetaObject->className();
504     else
505         return QByteArray();
506 }
507
508 const QString &QQmlType::elementName() const
509 {
510     return d->m_elementName;
511 }
512
513 const QString &QQmlType::qmlTypeName() const
514 {
515     if (d->m_name.isEmpty()) {
516         if (!d->m_module.isEmpty())
517             d->m_name = static_cast<QString>(d->m_module) + QLatin1Char('/') + d->m_elementName;
518         else
519             d->m_name = d->m_elementName;
520     }
521
522     return d->m_name;
523 }
524
525 QObject *QQmlType::create() const
526 {
527     d->init();
528
529     QObject *rv = (QObject *)operator new(d->m_allocationSize);
530     d->m_newFunc(rv);
531
532     if (rv && !d->m_metaObjects.isEmpty())
533         (void)new QQmlProxyMetaObject(rv, &d->m_metaObjects);
534
535     return rv;
536 }
537
538 void QQmlType::create(QObject **out, void **memory, size_t additionalMemory) const
539 {
540     d->init();
541
542     QObject *rv = (QObject *)operator new(d->m_allocationSize + additionalMemory);
543     d->m_newFunc(rv);
544
545     if (rv && !d->m_metaObjects.isEmpty())
546         (void)new QQmlProxyMetaObject(rv, &d->m_metaObjects);
547
548     *out = rv;
549     *memory = ((char *)rv) + d->m_allocationSize;
550 }
551
552 QQmlCustomParser *QQmlType::customParser() const
553 {
554     return d->m_customParser;
555 }
556
557 QQmlType::CreateFunc QQmlType::createFunction() const
558 {
559     return d->m_newFunc;
560 }
561
562 QString QQmlType::noCreationReason() const
563 {
564     return d->m_noCreationReason;
565 }
566
567 int QQmlType::createSize() const
568 {
569     return d->m_allocationSize;
570 }
571
572 bool QQmlType::isCreatable() const
573 {
574     return d->m_newFunc != 0;
575 }
576
577 bool QQmlType::isExtendedType() const
578 {
579     d->init();
580
581     return !d->m_metaObjects.isEmpty();
582 }
583
584 bool QQmlType::isInterface() const
585 {
586     return d->m_isInterface;
587 }
588
589 int QQmlType::typeId() const
590 {
591     return d->m_typeId;
592 }
593
594 int QQmlType::qListTypeId() const
595 {
596     return d->m_listId;
597 }
598
599 const QMetaObject *QQmlType::metaObject() const
600 {
601     d->init();
602
603     if (d->m_metaObjects.isEmpty())
604         return d->m_baseMetaObject;
605     else
606         return d->m_metaObjects.first().metaObject;
607
608 }
609
610 const QMetaObject *QQmlType::baseMetaObject() const
611 {
612     return d->m_baseMetaObject;
613 }
614
615 bool QQmlType::containsRevisionedAttributes() const
616 {
617     d->init();
618
619     return d->m_containsRevisionedAttributes;
620 }
621
622 int QQmlType::metaObjectRevision() const
623 {
624     return d->m_revision;
625 }
626
627 QQmlAttachedPropertiesFunc QQmlType::attachedPropertiesFunction() const
628 {
629     return d->m_attachedPropertiesFunc;
630 }
631
632 const QMetaObject *QQmlType::attachedPropertiesType() const
633 {
634     return d->m_attachedPropertiesType;
635 }
636
637 /*
638 This is the id passed to qmlAttachedPropertiesById().  This is different from the index
639 for the case that a single class is registered under two or more names (eg. Item in 
640 Qt 4.7 and QtQuick 1.0).
641 */
642 int QQmlType::attachedPropertiesId() const
643 {
644     return d->m_attachedPropertiesId;
645 }
646
647 int QQmlType::parserStatusCast() const
648 {
649     return d->m_parserStatusCast;
650 }
651
652 int QQmlType::propertyValueSourceCast() const
653 {
654     return d->m_propertyValueSourceCast;
655 }
656
657 int QQmlType::propertyValueInterceptorCast() const
658 {
659     return d->m_propertyValueInterceptorCast;
660 }
661
662 const char *QQmlType::interfaceIId() const
663 {
664     return d->m_iid;
665 }
666
667 int QQmlType::index() const
668 {
669     return d->m_index;
670 }
671
672 int QQmlType::enumValue(const QHashedStringRef &name) const
673 {
674     d->initEnums();
675
676     int *rv = d->m_enums.value(name);
677     return rv?*rv:-1;
678 }
679
680 int QQmlType::enumValue(const QHashedV8String &name) const
681 {
682     d->initEnums();
683
684     int *rv = d->m_enums.value(name);
685     return rv?*rv:-1;
686 }
687
688 QQmlTypeModule::QQmlTypeModule()
689 : d(new QQmlTypeModulePrivate)
690 {
691 }
692
693 QQmlTypeModule::~QQmlTypeModule()
694 {
695     delete d; d = 0;
696 }
697
698 QString QQmlTypeModule::module() const
699 {
700     return d->uri.uri;
701 }
702
703 int QQmlTypeModule::majorVersion() const
704 {
705     return d->uri.majorVersion;
706 }
707
708 int QQmlTypeModule::minimumMinorVersion() const
709 {
710     return d->minMinorVersion;
711 }
712
713 int QQmlTypeModule::maximumMinorVersion() const
714 {
715     return d->maxMinorVersion;
716 }
717
718 void QQmlTypeModulePrivate::add(QQmlType *type)
719 {
720     minMinorVersion = qMin(minMinorVersion, type->minorVersion());
721     maxMinorVersion = qMax(maxMinorVersion, type->minorVersion());
722
723     QList<QQmlType *> &list = typeHash[type->elementName()];
724     for (int ii = 0; ii < list.count(); ++ii) {
725         if (list.at(ii)->minorVersion() < type->minorVersion()) {
726             list.insert(ii, type);
727             return;
728         }
729     }
730     list.append(type);
731 }
732
733 QQmlType *QQmlTypeModule::type(const QHashedStringRef &name, int minor)
734 {
735     QReadLocker lock(metaTypeDataLock());
736
737     QList<QQmlType *> *types = d->typeHash.value(name);
738     if (!types) return 0;
739
740     for (int ii = 0; ii < types->count(); ++ii)
741         if (types->at(ii)->minorVersion() <= minor)
742             return types->at(ii);
743
744     return 0;
745 }
746
747 QQmlType *QQmlTypeModule::type(const QHashedV8String &name, int minor)
748 {
749     QReadLocker lock(metaTypeDataLock());
750
751     QList<QQmlType *> *types = d->typeHash.value(name);
752     if (!types) return 0;
753
754     for (int ii = 0; ii < types->count(); ++ii)
755         if (types->at(ii)->minorVersion() <= minor)
756             return types->at(ii);
757
758     return 0;
759 }
760
761
762 QQmlTypeModuleVersion::QQmlTypeModuleVersion()
763 : m_module(0), m_minor(0)
764 {
765 }
766
767 QQmlTypeModuleVersion::QQmlTypeModuleVersion(QQmlTypeModule *module, int minor)
768 : m_module(module), m_minor(minor)
769 {
770     Q_ASSERT(m_module);
771     Q_ASSERT(m_minor >= 0);
772 }
773
774 QQmlTypeModuleVersion::QQmlTypeModuleVersion(const QQmlTypeModuleVersion &o)
775 : m_module(o.m_module), m_minor(o.m_minor)
776 {
777 }
778
779 QQmlTypeModuleVersion &QQmlTypeModuleVersion::operator=(const QQmlTypeModuleVersion &o)
780 {
781     m_module = o.m_module;
782     m_minor = o.m_minor;
783     return *this;
784 }
785
786 QQmlTypeModule *QQmlTypeModuleVersion::module() const
787 {
788     return m_module;
789 }
790
791 int QQmlTypeModuleVersion::minorVersion() const
792 {
793     return m_minor;
794 }
795
796 QQmlType *QQmlTypeModuleVersion::type(const QHashedStringRef &name) const
797 {
798     if (m_module) return m_module->type(name, m_minor);
799     else return 0;
800 }
801
802 QQmlType *QQmlTypeModuleVersion::type(const QHashedV8String &name) const
803 {
804     if (m_module) return m_module->type(name, m_minor);
805     else return 0;
806 }
807
808
809 int registerAutoParentFunction(QQmlPrivate::RegisterAutoParent &autoparent)
810 {
811     QWriteLocker lock(metaTypeDataLock());
812     QQmlMetaTypeData *data = metaTypeData();
813
814     data->parentFunctions.append(autoparent.function);
815
816     return data->parentFunctions.count() - 1;
817 }
818
819 int registerInterface(const QQmlPrivate::RegisterInterface &interface)
820 {
821     if (interface.version > 0) 
822         qFatal("qmlRegisterType(): Cannot mix incompatible QML versions.");
823
824     QWriteLocker lock(metaTypeDataLock());
825     QQmlMetaTypeData *data = metaTypeData();
826
827     int index = data->types.count();
828
829     QQmlType *type = new QQmlType(index, interface);
830
831     data->types.append(type);
832     data->idToType.insert(type->typeId(), type);
833     data->idToType.insert(type->qListTypeId(), type);
834     // XXX No insertMulti, so no multi-version interfaces?
835     if (!type->elementName().isEmpty())
836         data->nameToType.insert(type->elementName(), type);
837
838     if (data->interfaces.size() <= interface.typeId)
839         data->interfaces.resize(interface.typeId + 16);
840     if (data->lists.size() <= interface.listId)
841         data->lists.resize(interface.listId + 16);
842     data->interfaces.setBit(interface.typeId, true);
843     data->lists.setBit(interface.listId, true);
844
845     return index;
846 }
847
848 int registerType(const QQmlPrivate::RegisterType &type)
849 {
850     if (type.elementName) {
851         for (int ii = 0; type.elementName[ii]; ++ii) {
852             if (!isalnum(type.elementName[ii])) {
853                 qWarning("qmlRegisterType(): Invalid QML element name \"%s\"", type.elementName);
854                 return -1;
855             }
856         }
857     }
858
859     QWriteLocker lock(metaTypeDataLock());
860     QQmlMetaTypeData *data = metaTypeData();
861     int index = data->types.count();
862
863     QQmlType *dtype = new QQmlType(index, type);
864
865     data->types.append(dtype);
866     data->idToType.insert(dtype->typeId(), dtype);
867     if (dtype->qListTypeId()) data->idToType.insert(dtype->qListTypeId(), dtype);
868
869     if (!dtype->elementName().isEmpty())
870         data->nameToType.insertMulti(dtype->elementName(), dtype);
871
872     data->metaObjectToType.insertMulti(dtype->baseMetaObject(), dtype);
873
874     if (data->objects.size() <= type.typeId)
875         data->objects.resize(type.typeId + 16);
876     if (data->lists.size() <= type.listId)
877         data->lists.resize(type.listId + 16);
878     data->objects.setBit(type.typeId, true);
879     if (type.listId) data->lists.setBit(type.listId, true);
880
881     if (!dtype->module().isEmpty()) {
882         const QHashedString &mod = dtype->module();
883
884         QQmlMetaTypeData::VersionedUri versionedUri(mod, type.versionMajor);
885         QQmlTypeModule *module = data->uriToModule.value(versionedUri);
886         if (!module) {
887             module = new QQmlTypeModule;
888             module->d->uri = versionedUri;
889             data->uriToModule.insert(versionedUri, module);
890         }
891         module->d->add(dtype);
892     }
893
894     return index;
895 }
896
897 int registerModuleApi(const QQmlPrivate::RegisterModuleApi &api)
898 {
899     QWriteLocker lock(metaTypeDataLock());
900
901     QQmlMetaTypeData *data = metaTypeData();
902     QString uri = QString::fromUtf8(api.uri);
903     QQmlMetaType::ModuleApi import;
904     import.major = api.versionMajor;
905     import.minor = api.versionMinor;
906     import.script = api.scriptApi;
907     import.qobject = api.qobjectApi;
908     import.instanceMetaObject = (api.qobjectApi && api.version >= 1) ? api.instanceMetaObject : 0; // BC with version 0.
909
910     if (import.qobject && !import.instanceMetaObject) // BC - check import.iMO rather than api.iMO.
911         qWarning() << "qmlRegisterModuleApi(): sub-optimal: use the templated version of this function instead!";
912
913     int index = data->moduleApiCount++;
914
915     QQmlMetaTypeData::ModuleApiList *apiList = data->moduleApis.value(uri);
916     if (!apiList) {
917         QQmlMetaTypeData::ModuleApiList apis;
918         apis.moduleApis << import;
919         data->moduleApis.insert(uri, apis);
920     } else {
921         apiList->moduleApis << import;
922         apiList->sorted = false;
923     }
924
925     return index;
926 }
927
928
929 /*
930 This method is "over generalized" to allow us to (potentially) register more types of things in
931 the future without adding exported symbols.
932 */
933 int QQmlPrivate::qmlregister(RegistrationType type, void *data)
934 {
935     if (type == TypeRegistration) {
936         return registerType(*reinterpret_cast<RegisterType *>(data));
937     } else if (type == InterfaceRegistration) {
938         return registerInterface(*reinterpret_cast<RegisterInterface *>(data));
939     } else if (type == AutoParentRegistration) {
940         return registerAutoParentFunction(*reinterpret_cast<RegisterAutoParent *>(data));
941     } else if (type == ModuleApiRegistration) {
942         return registerModuleApi(*reinterpret_cast<RegisterModuleApi *>(data));
943     }
944     return -1;
945 }
946
947 /*
948     Returns true if a module \a uri of any version is installed.
949 */
950 bool QQmlMetaType::isAnyModule(const QString &uri)
951 {
952     QReadLocker lock(metaTypeDataLock());
953     QQmlMetaTypeData *data = metaTypeData();
954
955     for (QQmlMetaTypeData::TypeModules::ConstIterator iter = data->uriToModule.begin();
956          iter != data->uriToModule.end(); ++iter) {
957         if ((*iter)->module() == uri)
958             return true;
959     }
960
961     return false;
962 }
963
964 /*
965     Returns true if any type or API has been registered for the given \a module with at least
966     versionMajor.versionMinor, or if types have been registered for \a module with at most
967     versionMajor.versionMinor.
968
969     So if only 4.7 and 4.9 have been registered, 4.7,4.8, and 4.9 are valid, but not 4.6 nor 4.10.
970 */
971 bool QQmlMetaType::isModule(const QString &module, int versionMajor, int versionMinor)
972 {
973     Q_ASSERT(versionMajor >= 0 && versionMinor >= 0);
974     QReadLocker lock(metaTypeDataLock());
975
976     QQmlMetaTypeData *data = metaTypeData();
977
978     // first, check Types
979     QQmlTypeModule *tm = 
980         data->uriToModule.value(QQmlMetaTypeData::VersionedUri(module, versionMajor));
981     if (tm && tm->minimumMinorVersion() <= versionMinor && tm->maximumMinorVersion() >= versionMinor)
982         return true;
983
984     // then, check ModuleApis
985     QQmlMetaTypeData::ModuleApiList *apiList = data->moduleApis.value(module);
986     if (apiList) {
987         foreach (const QQmlMetaType::ModuleApi &mApi, apiList->moduleApis) {
988             if (mApi.major == versionMajor && mApi.minor == versionMinor) // XXX is this correct?
989                 return true;
990         }
991     }
992
993     return false;
994 }
995
996 QQmlTypeModule *QQmlMetaType::typeModule(const QString &uri, int majorVersion)
997 {
998     QReadLocker lock(metaTypeDataLock());
999     QQmlMetaTypeData *data = metaTypeData();
1000     return data->uriToModule.value(QQmlMetaTypeData::VersionedUri(uri, majorVersion));
1001 }
1002
1003 QList<QQmlPrivate::AutoParentFunction> QQmlMetaType::parentFunctions()
1004 {
1005     QReadLocker lock(metaTypeDataLock());
1006     QQmlMetaTypeData *data = metaTypeData();
1007     return data->parentFunctions;
1008 }
1009
1010 static bool operator<(const QQmlMetaType::ModuleApi &lhs, const QQmlMetaType::ModuleApi &rhs)
1011 {
1012     return lhs.major < rhs.major || (lhs.major == rhs.major && lhs.minor < rhs.minor);
1013 }
1014
1015 QQmlMetaType::ModuleApi
1016 QQmlMetaType::moduleApi(const QString &uri, int versionMajor, int versionMinor)
1017 {
1018     QReadLocker lock(metaTypeDataLock());
1019     QQmlMetaTypeData *data = metaTypeData();
1020
1021     QQmlMetaTypeData::ModuleApiList *apiList = data->moduleApis.value(uri);
1022     if (!apiList)
1023         return ModuleApi();
1024
1025     if (apiList->sorted == false) {
1026         qSort(apiList->moduleApis.begin(), apiList->moduleApis.end());
1027         apiList->sorted = true;
1028     }
1029
1030     for (int ii = apiList->moduleApis.count() - 1; ii >= 0; --ii) {
1031         const ModuleApi &import = apiList->moduleApis.at(ii);
1032         if (import.major == versionMajor && import.minor <= versionMinor)
1033             return import;
1034     }
1035
1036     return ModuleApi();
1037 }
1038
1039 QHash<QString, QList<QQmlMetaType::ModuleApi> > QQmlMetaType::moduleApis()
1040 {
1041     QReadLocker lock(metaTypeDataLock());
1042     QQmlMetaTypeData *data = metaTypeData();
1043
1044     QHash<QString, QList<ModuleApi> > moduleApis;
1045     QStringHash<QQmlMetaTypeData::ModuleApiList>::ConstIterator it = data->moduleApis.begin();
1046     for (; it != data->moduleApis.end(); ++it)
1047         moduleApis[it.key()] = it.value().moduleApis;
1048
1049     return moduleApis;
1050 }
1051
1052 QObject *QQmlMetaType::toQObject(const QVariant &v, bool *ok)
1053 {
1054     if (!isQObject(v.userType())) {
1055         if (ok) *ok = false;
1056         return 0;
1057     }
1058
1059     if (ok) *ok = true;
1060
1061     return *(QObject **)v.constData();
1062 }
1063
1064 bool QQmlMetaType::isQObject(int userType)
1065 {
1066     if (userType == QMetaType::QObjectStar)
1067         return true;
1068
1069     QReadLocker lock(metaTypeDataLock());
1070     QQmlMetaTypeData *data = metaTypeData();
1071     return userType >= 0 && userType < data->objects.size() && data->objects.testBit(userType);
1072 }
1073
1074 /*
1075     Returns the item type for a list of type \a id.
1076  */
1077 int QQmlMetaType::listType(int id)
1078 {
1079     QReadLocker lock(metaTypeDataLock());
1080     QQmlMetaTypeData *data = metaTypeData();
1081     QQmlType *type = data->idToType.value(id);
1082     if (type && type->qListTypeId() == id)
1083         return type->typeId();
1084     else
1085         return 0;
1086 }
1087
1088 int QQmlMetaType::attachedPropertiesFuncId(const QMetaObject *mo)
1089 {
1090     QReadLocker lock(metaTypeDataLock());
1091     QQmlMetaTypeData *data = metaTypeData();
1092
1093     QQmlType *type = data->metaObjectToType.value(mo);
1094     if (type && type->attachedPropertiesFunction())
1095         return type->attachedPropertiesId();
1096     else
1097         return -1;
1098 }
1099
1100 QQmlAttachedPropertiesFunc QQmlMetaType::attachedPropertiesFuncById(int id)
1101 {
1102     if (id < 0)
1103         return 0;
1104     QReadLocker lock(metaTypeDataLock());
1105     QQmlMetaTypeData *data = metaTypeData();
1106     return data->types.at(id)->attachedPropertiesFunction();
1107 }
1108
1109 QMetaProperty QQmlMetaType::defaultProperty(const QMetaObject *metaObject)
1110 {
1111     int idx = metaObject->indexOfClassInfo("DefaultProperty");
1112     if (-1 == idx)
1113         return QMetaProperty();
1114
1115     QMetaClassInfo info = metaObject->classInfo(idx);
1116     if (!info.value())
1117         return QMetaProperty();
1118
1119     idx = metaObject->indexOfProperty(info.value());
1120     if (-1 == idx)
1121         return QMetaProperty();
1122
1123     return metaObject->property(idx);
1124 }
1125
1126 QMetaProperty QQmlMetaType::defaultProperty(QObject *obj)
1127 {
1128     if (!obj)
1129         return QMetaProperty();
1130
1131     const QMetaObject *metaObject = obj->metaObject();
1132     return defaultProperty(metaObject);
1133 }
1134
1135 QMetaMethod QQmlMetaType::defaultMethod(const QMetaObject *metaObject)
1136 {
1137     int idx = metaObject->indexOfClassInfo("DefaultMethod");
1138     if (-1 == idx)
1139         return QMetaMethod();
1140
1141     QMetaClassInfo info = metaObject->classInfo(idx);
1142     if (!info.value())
1143         return QMetaMethod();
1144
1145     idx = metaObject->indexOfMethod(info.value());
1146     if (-1 == idx)
1147         return QMetaMethod();
1148
1149     return metaObject->method(idx);
1150 }
1151
1152 QMetaMethod QQmlMetaType::defaultMethod(QObject *obj)
1153 {
1154     if (!obj)
1155         return QMetaMethod();
1156
1157     const QMetaObject *metaObject = obj->metaObject();
1158     return defaultMethod(metaObject);
1159 }
1160
1161 QQmlMetaType::TypeCategory QQmlMetaType::typeCategory(int userType)
1162 {
1163     if (userType < 0)
1164         return Unknown;
1165     if (userType == QMetaType::QObjectStar)
1166         return Object;
1167
1168     QReadLocker lock(metaTypeDataLock());
1169     QQmlMetaTypeData *data = metaTypeData();
1170     if (userType < data->objects.size() && data->objects.testBit(userType))
1171         return Object;
1172     else if (userType < data->lists.size() && data->lists.testBit(userType))
1173         return List;
1174     else
1175         return Unknown;
1176 }
1177
1178 bool QQmlMetaType::isInterface(int userType)
1179 {
1180     QReadLocker lock(metaTypeDataLock());
1181     QQmlMetaTypeData *data = metaTypeData();
1182     return userType >= 0 && userType < data->interfaces.size() && data->interfaces.testBit(userType);
1183 }
1184
1185 const char *QQmlMetaType::interfaceIId(int userType)
1186 {
1187     QReadLocker lock(metaTypeDataLock());
1188     QQmlMetaTypeData *data = metaTypeData();
1189     QQmlType *type = data->idToType.value(userType);
1190     lock.unlock();
1191     if (type && type->isInterface() && type->typeId() == userType)
1192         return type->interfaceIId();
1193     else
1194         return 0;
1195 }
1196
1197 bool QQmlMetaType::isList(int userType)
1198 {
1199     QReadLocker lock(metaTypeDataLock());
1200     QQmlMetaTypeData *data = metaTypeData();
1201     return userType >= 0 && userType < data->lists.size() && data->lists.testBit(userType);
1202 }
1203
1204 /*!
1205     A custom string convertor allows you to specify a function pointer that
1206     returns a variant of \a type. For example, if you have written your own icon
1207     class that you want to support as an object property assignable in QML:
1208
1209     \code
1210     int type = qRegisterMetaType<SuperIcon>("SuperIcon");
1211     QML::addCustomStringConvertor(type, &SuperIcon::pixmapFromString);
1212     \endcode
1213
1214     The function pointer must be of the form:
1215     \code
1216     QVariant (*StringConverter)(const QString &);
1217     \endcode
1218  */
1219 void QQmlMetaType::registerCustomStringConverter(int type, StringConverter converter)
1220 {
1221     QWriteLocker lock(metaTypeDataLock());
1222
1223     QQmlMetaTypeData *data = metaTypeData();
1224     if (data->stringConverters.contains(type))
1225         return;
1226     data->stringConverters.insert(type, converter);
1227 }
1228
1229 /*!
1230     Return the custom string converter for \a type, previously installed through
1231     registerCustomStringConverter()
1232  */
1233 QQmlMetaType::StringConverter QQmlMetaType::customStringConverter(int type)
1234 {
1235     QReadLocker lock(metaTypeDataLock());
1236
1237     QQmlMetaTypeData *data = metaTypeData();
1238     return data->stringConverters.value(type);
1239 }
1240
1241 /*!
1242     Returns the type (if any) of URI-qualified named \a qualifiedName and version specified
1243     by \a version_major and \a version_minor.
1244 */
1245 QQmlType *QQmlMetaType::qmlType(const QString &qualifiedName, int version_major, int version_minor)
1246 {
1247     int slash = qualifiedName.indexOf(QLatin1Char('/'));
1248     if (slash <= 0)
1249         return 0;
1250
1251     QHashedStringRef module(qualifiedName.constData(), slash);
1252     QHashedStringRef name(qualifiedName.constData() + slash + 1, qualifiedName.length() - slash - 1);
1253
1254     return qmlType(name, module, version_major, version_minor);
1255 }
1256
1257 /*!
1258     Returns the type (if any) of \a name in \a module and version specified
1259     by \a version_major and \a version_minor.
1260 */
1261 QQmlType *QQmlMetaType::qmlType(const QHashedStringRef &name, const QHashedStringRef &module, int version_major, int version_minor)
1262 {
1263     Q_ASSERT(version_major >= 0 && version_minor >= 0);
1264     QReadLocker lock(metaTypeDataLock());
1265     QQmlMetaTypeData *data = metaTypeData();
1266
1267     QQmlMetaTypeData::Names::ConstIterator it = data->nameToType.find(name);
1268     while (it != data->nameToType.end() && it.key() == name) {
1269         // XXX version_major<0 just a kludge for QQmlPropertyPrivate::initProperty
1270         if (version_major < 0 || (*it)->availableInVersion(module, version_major,version_minor))
1271             return (*it);
1272         ++it;
1273     }
1274
1275     return 0;
1276 }
1277
1278 /*!
1279     Returns the type (if any) that corresponds to the \a metaObject.  Returns null if no
1280     type is registered.
1281 */
1282 QQmlType *QQmlMetaType::qmlType(const QMetaObject *metaObject)
1283 {
1284     QReadLocker lock(metaTypeDataLock());
1285     QQmlMetaTypeData *data = metaTypeData();
1286
1287     return data->metaObjectToType.value(metaObject);
1288 }
1289
1290 /*!
1291     Returns the type (if any) that corresponds to the \a metaObject in version specified
1292     by \a version_major and \a version_minor in module specified by \a uri.  Returns null if no
1293     type is registered.
1294 */
1295 QQmlType *QQmlMetaType::qmlType(const QMetaObject *metaObject, const QHashedStringRef &module, int version_major, int version_minor)
1296 {
1297     Q_ASSERT(version_major >= 0 && version_minor >= 0);
1298     QReadLocker lock(metaTypeDataLock());
1299     QQmlMetaTypeData *data = metaTypeData();
1300
1301     QQmlMetaTypeData::MetaObjects::const_iterator it = data->metaObjectToType.find(metaObject);
1302     while (it != data->metaObjectToType.end() && it.key() == metaObject) {
1303         QQmlType *t = *it;
1304         if (version_major < 0 || t->availableInVersion(module, version_major,version_minor))
1305             return t;
1306         ++it;
1307     }
1308
1309     return 0;
1310 }
1311
1312 /*!
1313     Returns the type (if any) that corresponds to the QVariant::Type \a userType.  
1314     Returns null if no type is registered.
1315 */
1316 QQmlType *QQmlMetaType::qmlType(int userType)
1317 {
1318     QReadLocker lock(metaTypeDataLock());
1319     QQmlMetaTypeData *data = metaTypeData();
1320
1321     QQmlType *type = data->idToType.value(userType);
1322     if (type && type->typeId() == userType)
1323         return type;
1324     else
1325         return 0;
1326 }
1327
1328 /*!
1329     Returns the list of registered QML type names.
1330 */
1331 QList<QString> QQmlMetaType::qmlTypeNames()
1332 {
1333     QReadLocker lock(metaTypeDataLock());
1334     QQmlMetaTypeData *data = metaTypeData();
1335
1336     QList<QString> names;
1337     QQmlMetaTypeData::Names::ConstIterator it = data->nameToType.begin();
1338     while (it != data->nameToType.end()) {
1339         names += (*it)->qmlTypeName();
1340         ++it;
1341     }
1342
1343     return names;
1344 }
1345
1346 /*!
1347     Returns the list of registered QML types.
1348 */
1349 QList<QQmlType*> QQmlMetaType::qmlTypes()
1350 {
1351     QReadLocker lock(metaTypeDataLock());
1352     QQmlMetaTypeData *data = metaTypeData();
1353
1354     return data->nameToType.values();
1355 }
1356
1357 int QQmlMetaType::QQuickAnchorLineMetaTypeId()
1358 {
1359     static int id = 0;
1360     if (!id) {
1361         id = QMetaType::type("QQuickAnchorLine");
1362     }
1363     return id;
1364 }
1365
1366 QQmlMetaType::CompareFunction QQmlMetaType::anchorLineCompareFunction = 0;
1367
1368 void QQmlMetaType::setQQuickAnchorLineCompareFunction(CompareFunction fun)
1369 {
1370     anchorLineCompareFunction = fun;
1371 }
1372
1373 bool QQmlMetaType::QQuickAnchorLineCompare(const void *p1, const void *p2)
1374 {
1375     Q_ASSERT(anchorLineCompareFunction != 0);
1376     return anchorLineCompareFunction(p1, p2);
1377 }
1378
1379 QT_END_NAMESPACE